diff --git a/.eslintrc.json b/.eslintrc.json index 4052342d825..b0904fb6937 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,8 +1,5 @@ { - "plugins": [ - "node", - "prettier" - ], + "plugins": ["node", "prettier"], "parserOptions": { "sourceType": "module", "ecmaFeatures": { diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cb6801cf0b..28c94ed382f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). ### Commits -- RulesProxy: Make sure _redirects works with dev [`27f92f2`](https://github.com/netlify/cli/commit/27f92f23148f7250e63a1586744d155a54751cd5) +- RulesProxy: Make sure \_redirects works with dev [`27f92f2`](https://github.com/netlify/cli/commit/27f92f23148f7250e63a1586744d155a54751cd5) - update logo [`3984bbb`](https://github.com/netlify/cli/commit/3984bbb1c4177fb410f9100d83baac7875ea0025) - Dev: Make stdio more maintainable [`4cbdb02`](https://github.com/netlify/cli/commit/4cbdb02ca85c7680b9c469aad5ce725e3975f86f) @@ -29,11 +29,11 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - Dev: Make functions port configureable [`#525`](https://github.com/netlify/cli/pull/525) - Fix port for proxy redirects [`#520`](https://github.com/netlify/cli/pull/520) - Rules Proxy: Pass on query parameters [`#519`](https://github.com/netlify/cli/pull/519) -- Import rules-proxy and and redirect-parser [`#518`](https://github.com/netlify/cli/pull/518) +- Import rules-proxy and and redirect-parser [`#518`](https://github.com/netlify/cli/pull/518) - Consider sites from different team in Netlify link [`#500`](https://github.com/netlify/cli/pull/500) - Improve prompts for `link` command [`#502`](https://github.com/netlify/cli/pull/502) - Add Parcel detector [`#505`](https://github.com/netlify/cli/pull/505) -- rename deploy path [`#508`](https://github.com/netlify/cli/pull/508) +- rename deploy path [`#508`](https://github.com/netlify/cli/pull/508) - Improve analytics [`#513`](https://github.com/netlify/cli/pull/513) - Update ISSUE_TEMPLATE.md [`#504`](https://github.com/netlify/cli/pull/504) - Neltify -> Netlify [`#512`](https://github.com/netlify/cli/pull/512) @@ -383,7 +383,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - update netlify dev plugin [`514d759`](https://github.com/netlify/cli/commit/514d7591609fbd645c1de87f47200099e6919abe) - Add a test for raw parsing [`deb4cb9`](https://github.com/netlify/cli/commit/deb4cb97cf0ef12efba83b07c719064e9e16342e) -- Use conventional file casing [`60ad9d0`](https://github.com/netlify/cli/commit/60ad9d07c5a43ea24e78b63d70955e1a11dacc13) +- Use conventional file casing [`60ad9d0`](https://github.com/netlify/cli/commit/60ad9d07c5a43ea24e78b63d70955e1a11dacc13) ## [v2.11.7](https://github.com/netlify/cli/compare/v2.11.6...v2.11.7) - 2019-04-10 @@ -597,7 +597,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). ### Commits - Run `npm up` [`29f16fa`](https://github.com/netlify/cli/commit/29f16fa376a55093b09d0c14a67e6ab68a5718f7) -- Update js-client providing zip-n-ship capabilities [`f9774a2`](https://github.com/netlify/cli/commit/f9774a29781c37d10875563c6221c2b92d2d7800) +- Update js-client providing zip-n-ship capabilities [`f9774a2`](https://github.com/netlify/cli/commit/f9774a29781c37d10875563c6221c2b92d2d7800) - Update deps [`985e8da`](https://github.com/netlify/cli/commit/985e8da37e162fefabfd27ac5bf6e567ba7ea790) ## [v2.6.6](https://github.com/netlify/cli/compare/v2.6.5...v2.6.6) - 2019-01-31 @@ -608,7 +608,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). ### Commits -- Run prune before shrink-wrap [`761fcc5`](https://github.com/netlify/cli/commit/761fcc5660c8ac2a293afde661a129a0c8fbee84) +- Run prune before shrink-wrap [`761fcc5`](https://github.com/netlify/cli/commit/761fcc5660c8ac2a293afde661a129a0c8fbee84) ## [v2.6.5](https://github.com/netlify/cli/compare/v2.6.4...v2.6.5) - 2019-01-31 @@ -645,7 +645,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). ### Commits -- Update js-client to fix rate limit handling [`32590eb`](https://github.com/netlify/cli/commit/32590ebf2aa9788733908afee3aefd87f21e9bb8) +- Update js-client to fix rate limit handling [`32590eb`](https://github.com/netlify/cli/commit/32590ebf2aa9788733908afee3aefd87f21e9bb8) ## [v2.6.2](https://github.com/netlify/cli/compare/v2.6.1...v2.6.2) - 2019-01-19 @@ -735,7 +735,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). ### Commits -- Fix missing dependencies [`4dd06ad`](https://github.com/netlify/cli/commit/4dd06ad5bf53d62355e2f126bcc641786dba4139) +- Fix missing dependencies [`4dd06ad`](https://github.com/netlify/cli/commit/4dd06ad5bf53d62355e2f126bcc641786dba4139) ## [v2.2.2](https://github.com/netlify/cli/compare/v2.2.1...v2.2.2) - 2018-11-26 @@ -859,7 +859,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). ### Commits - add root to this.netlify.site [`9104cf2`](https://github.com/netlify/cli/commit/9104cf2df283e19b4565daeb7f9c7a695a5bc419) -- Use dirname, not base name [`73b594c`](https://github.com/netlify/cli/commit/73b594c1bb8dc024ecca8d1a1c9a42ab0b953317) +- Use dirname, not base name [`73b594c`](https://github.com/netlify/cli/commit/73b594c1bb8dc024ecca8d1a1c9a42ab0b953317) ## [v2.0.0-beta.8](https://github.com/netlify/cli/compare/v2.0.0-beta.7...v2.0.0-beta.8) - 2018-10-09 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 2867c8a784f..73b70570546 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -14,21 +14,21 @@ orientation. Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or -advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 680145ea40f..c37f96b2979 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -66,7 +66,7 @@ We actively welcome your pull requests. 1. Clean out local `node_modules`. `rm -rf node_modules`. This is to counteract any oddities that may arise during the `shrinkwrap` process that happens when cli is released. 2. Install dependencies. `npm install`. -3. `npm version [major, minor, patch]` Generate changelog and bump version. +3. `npm version [major, minor, patch]` Generate changelog and bump version. 4. `npm publish` Publish to npm, push version commit + tag, push latest CHANGELOG entry to GitHub release page. ## License diff --git a/README.md b/README.md index 0108f9cffc6..3fc768570f9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Netlify CLI + [![npm version][npm-img]][npm] [![build status][azure-img]][azure] [![coverage][coverage-img]][coverage] [![dependencies][david-img]][david] [![downloads][dl-img]][dl] [![netlify-status][netlify-img]][netlify] Welcome to the Netlify CLI! The new 2.0 version was rebuilt from the ground up to help improve the site building experience. @@ -15,20 +16,20 @@ Welcome to the Netlify CLI! The new 2.0 version was rebuilt from the ground up t - [Usage](#usage) - [Documentation](#documentation) - [Commands](#commands) - * [addons](#addons) - * [api](#api) - * [deploy](#deploy) - * [dev](#dev) - * [functions](#functions) - * [init](#init) - * [link](#link) - * [login](#login) - * [open](#open) - * [sites](#sites) - * [status](#status) - * [switch](#switch) - * [unlink](#unlink) - * [watch](#watch) + - [addons](#addons) + - [api](#api) + - [deploy](#deploy) + - [dev](#dev) + - [functions](#functions) + - [init](#init) + - [link](#link) + - [login](#login) + - [open](#open) + - [sites](#sites) + - [status](#status) + - [switch](#switch) + - [unlink](#unlink) + - [watch](#watch) - [Contributing](#contributing) - [Development](#development) - [License](#license) @@ -66,18 +67,18 @@ For a full command reference, see the list below, or visit [cli.netlify.com](htt ## Commands + ### [addons](/docs/commands/addons.md) (Beta) Manage Netlify Add-ons -| Subcommand | description | -|:--------------------------- |:-----| -| [`addons:auth`](/docs/commands/addons.md#addonsauth) | Login to add-on provider | -| [`addons:config`](/docs/commands/addons.md#addonsconfig) | Configure add-on settings | -| [`addons:create`](/docs/commands/addons.md#addonscreate) | Add an add-on extension to your site | -| [`addons:delete`](/docs/commands/addons.md#addonsdelete) | Remove an add-on extension to your site | -| [`addons:list`](/docs/commands/addons.md#addonslist) | List currently installed add-ons for site | - +| Subcommand | description | +| :------------------------------------------------------- | :---------------------------------------- | +| [`addons:auth`](/docs/commands/addons.md#addonsauth) | Login to add-on provider | +| [`addons:config`](/docs/commands/addons.md#addonsconfig) | Configure add-on settings | +| [`addons:create`](/docs/commands/addons.md#addonscreate) | Add an add-on extension to your site | +| [`addons:delete`](/docs/commands/addons.md#addonsdelete) | Remove an add-on extension to your site | +| [`addons:list`](/docs/commands/addons.md#addonslist) | List currently installed add-ons for site | ### [api](/docs/commands/api.md) @@ -91,21 +92,19 @@ Create a new deploy from the contents of a folder Local dev server -| Subcommand | description | -|:--------------------------- |:-----| -| [`dev:exec`](/docs/commands/dev.md#devexec) | Exec command | - +| Subcommand | description | +| :------------------------------------------ | :----------- | +| [`dev:exec`](/docs/commands/dev.md#devexec) | Exec command | ### [functions](/docs/commands/functions.md) Manage netlify functions -| Subcommand | description | -|:--------------------------- |:-----| -| [`functions:build`](/docs/commands/functions.md#functionsbuild) | build functions locally | -| [`functions:create`](/docs/commands/functions.md#functionscreate) | create a new function locally | -| [`functions:invoke`](/docs/commands/functions.md#functionsinvoke) | trigger a function while in netlify dev with simulated data, good for testing function calls including Netlify's Event Triggered Functions | - +| Subcommand | description | +| :---------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------- | +| [`functions:build`](/docs/commands/functions.md#functionsbuild) | build functions locally | +| [`functions:create`](/docs/commands/functions.md#functionscreate) | create a new function locally | +| [`functions:invoke`](/docs/commands/functions.md#functionsinvoke) | trigger a function while in netlify dev with simulated data, good for testing function calls including Netlify's Event Triggered Functions | ### [init](/docs/commands/init.md) @@ -123,31 +122,28 @@ Login to your Netlify account Open settings for the site linked to the current folder -| Subcommand | description | -|:--------------------------- |:-----| -| [`open:admin`](/docs/commands/open.md#openadmin) | Opens current site admin UI in Netlify | -| [`open:site`](/docs/commands/open.md#opensite) | Opens current site url in browser | - +| Subcommand | description | +| :----------------------------------------------- | :------------------------------------- | +| [`open:admin`](/docs/commands/open.md#openadmin) | Opens current site admin UI in Netlify | +| [`open:site`](/docs/commands/open.md#opensite) | Opens current site url in browser | ### [sites](/docs/commands/sites.md) Handle various site operations -| Subcommand | description | -|:--------------------------- |:-----| -| [`sites:create`](/docs/commands/sites.md#sitescreate) | Create an empty site (advanced) | -| [`sites:delete`](/docs/commands/sites.md#sitesdelete) | Delete a site | -| [`sites:list`](/docs/commands/sites.md#siteslist) | List all sites you have access to | - +| Subcommand | description | +| :---------------------------------------------------- | :-------------------------------- | +| [`sites:create`](/docs/commands/sites.md#sitescreate) | Create an empty site (advanced) | +| [`sites:delete`](/docs/commands/sites.md#sitesdelete) | Delete a site | +| [`sites:list`](/docs/commands/sites.md#siteslist) | List all sites you have access to | ### [status](/docs/commands/status.md) Print status information -| Subcommand | description | -|:--------------------------- |:-----| -| [`status:hooks`](/docs/commands/status.md#statushooks) | Print hook information of the linked site | - +| Subcommand | description | +| :----------------------------------------------------- | :---------------------------------------- | +| [`status:hooks`](/docs/commands/status.md#statushooks) | Print hook information of the linked site | ### [switch](/docs/commands/switch.md) @@ -161,7 +157,6 @@ Unlink a local folder from a Netlify site Watch for site deploy to finish - ## Contributing diff --git a/azure-pipelines-template.yml b/azure-pipelines-template.yml index 405870dc8b4..42cbae55cee 100644 --- a/azure-pipelines-template.yml +++ b/azure-pipelines-template.yml @@ -6,18 +6,18 @@ jobs: steps: - task: NodeTool@0 inputs: - versionSpec: "10.x" - displayName: "Install Node.js" + versionSpec: '10.x' + displayName: 'Install Node.js' - script: | node --version npm --version - displayName: "Print node + npm versions" + displayName: 'Print node + npm versions' - task: Npm@1 inputs: command: install - displayName: "Install deps with npm" + displayName: 'Install deps with npm' - task: Npm@1 inputs: command: custom customCommand: test - displayName: "Run tests" + displayName: 'Run tests' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5666af58f91..0e2afc5cf8d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,15 +1,15 @@ jobs: -- template: azure-pipelines-template.yml - parameters: - name: macOS - vmImage: macOS-10.13 + - template: azure-pipelines-template.yml + parameters: + name: macOS + vmImage: macOS-10.13 -- template: azure-pipelines-template.yml - parameters: - name: Linux - vmImage: ubuntu-16.04 + - template: azure-pipelines-template.yml + parameters: + name: Linux + vmImage: ubuntu-16.04 -- template: azure-pipelines-template.yml - parameters: - name: Windows - vmImage: vs2017-win2016 + - template: azure-pipelines-template.yml + parameters: + name: Windows + vmImage: vs2017-win2016 diff --git a/package.json b/package.json index b43275bdd69..cadc8ddc299 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "ava": "ava --verbose", "test:ava": "nyc --reporter=lcov ava --verbose && nyc report", "test:lint": "eslint src", + "test:prettier": "prettier --write --loglevel warn 'src/**/*.js' '*.{js,md,yml,json}'", "test:deps": "dependency-check ./package.json --entry \"src/**/!(*.test).js\" --unused --missing --no-dev --no-peer -i @oclif/plugin-not-found -i @oclif/config -i @oclif/plugin-help -i @oclif/plugin-plugins", "test:cli-version": "npm run start -- --version", "test:cli-help": "npm run start -- --help", diff --git a/src/commands/addons/auth.js b/src/commands/addons/auth.js index 81ab1e034d6..d39063c9daf 100644 --- a/src/commands/addons/auth.js +++ b/src/commands/addons/auth.js @@ -40,9 +40,9 @@ class AddonsAuthCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "addons:auth", - }, - }); + command: 'addons:auth' + } + }) this.log() this.log(`Opening ${addonName} add-on admin URL:`) diff --git a/src/commands/addons/config.js b/src/commands/addons/config.js index bf9cbd4aa04..31e21b2b032 100644 --- a/src/commands/addons/config.js +++ b/src/commands/addons/config.js @@ -63,9 +63,9 @@ class AddonsConfigCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "addons:config", - }, - }); + command: 'addons:config' + } + }) if (hasConfig) { const required = requiredConfigValues(manifest.config) @@ -75,19 +75,22 @@ class AddonsConfigCommand extends Command { if (rawFlags && !missingValues.length) { const newConfig = updateConfigValues(manifest.config, currentConfig, rawFlags) - await update({ - addonName, - currentConfig, - newConfig, - settings: { - siteId: siteId, - instanceId: currentAddon.id, - addon: addonName, - config: newConfig + await update( + { + addonName, + currentConfig, + newConfig, + settings: { + siteId: siteId, + instanceId: currentAddon.id, + addon: addonName, + config: newConfig + }, + accessToken, + error: this.error }, - accessToken, - error: this.error - }, this.log) + this.log + ) return false } @@ -148,19 +151,22 @@ class AddonsConfigCommand extends Command { return false } - await update({ - addonName, - currentConfig, - newConfig, - settings: { - siteId: siteId, - instanceId: currentAddon.id, - addon: addonName, - config: newConfig + await update( + { + addonName, + currentConfig, + newConfig, + settings: { + siteId: siteId, + instanceId: currentAddon.id, + addon: addonName, + config: newConfig + }, + accessToken, + error: this.error }, - accessToken, - error: this.error - }, this.log) + this.log + ) } } } diff --git a/src/commands/addons/create.js b/src/commands/addons/create.js index 01d1dcc8172..00dfbb1758b 100644 --- a/src/commands/addons/create.js +++ b/src/commands/addons/create.js @@ -54,16 +54,16 @@ class AddonsCreateCommand extends Command { } const manifest = await getAddonManifest(addonName, accessToken) - const hasConfig = manifest.config && Object.keys(manifest.config).length + const hasConfig = manifest.config && Object.keys(manifest.config).length let configValues = rawFlags await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "addons:create", - }, - }); + command: 'addons:create' + } + }) if (hasConfig) { const required = requiredConfigValues(manifest.config) @@ -90,17 +90,20 @@ class AddonsCreateCommand extends Command { return false } - await createSiteAddon({ - addonName, - settings: { - siteId: siteId, - addon: addonName, - config: newConfig + await createSiteAddon( + { + addonName, + settings: { + siteId: siteId, + addon: addonName, + config: newConfig + }, + accessToken, + siteData, + error: this.error }, - accessToken, - siteData, - error: this.error - }, this.log) + this.log + ) return false } @@ -132,17 +135,20 @@ class AddonsCreateCommand extends Command { } } - await createSiteAddon({ - addonName, - settings: { - siteId: siteId, - addon: addonName, - config: configValues + await createSiteAddon( + { + addonName, + settings: { + siteId: siteId, + addon: addonName, + config: configValues + }, + accessToken, + siteData, + error: this.error }, - accessToken, - siteData, - error: this.error - }, this.log) + this.log + ) } } diff --git a/src/commands/addons/delete.js b/src/commands/addons/delete.js index 9eaf0ba1262..4f60d0c1351 100644 --- a/src/commands/addons/delete.js +++ b/src/commands/addons/delete.js @@ -27,10 +27,8 @@ class AddonsDeleteCommand extends Command { } // Filter down addons to current args.name - const currentAddon = addons.find( - current => current.service_path && current.service_path.replace('/.netlify/', '') === addonName - ) || {} - + const currentAddon = + addons.find(current => current.service_path && current.service_path.replace('/.netlify/', '') === addonName) || {} const { force, f } = parseRawFlags(raw) if (!force && !f) { @@ -54,9 +52,9 @@ class AddonsDeleteCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "addons:delete", - }, - }); + command: 'addons:delete' + } + }) const settings = { siteId: siteId, @@ -81,9 +79,7 @@ class AddonsDeleteCommand extends Command { this.log(`Addon "${addonName}" deleted`) } else { this.log( - `Addon "${addonName}" was not deleted "${addonName}". Returned status: ${ - addonResponse.status - }. Addon deletion must return status 204 from "${addonName}" provider.` + `Addon "${addonName}" was not deleted "${addonName}". Returned status: ${addonResponse.status}. Addon deletion must return status 204 from "${addonName}" provider.` ) } } diff --git a/src/commands/addons/index.js b/src/commands/addons/index.js index 77c3824436a..194b4d82559 100644 --- a/src/commands/addons/index.js +++ b/src/commands/addons/index.js @@ -15,9 +15,9 @@ class AddonsCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "addons", - }, - }); + command: 'addons' + } + }) } } diff --git a/src/commands/addons/list.js b/src/commands/addons/list.js index 4b46cd9d671..d401b6e0b80 100644 --- a/src/commands/addons/list.js +++ b/src/commands/addons/list.js @@ -35,9 +35,9 @@ class AddonsListCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "addons:list", - }, - }); + command: 'addons:list' + } + }) const addonData = addons.map(addon => { return { diff --git a/src/commands/api.js b/src/commands/api.js index b019d0c8273..a69cbbd6bee 100644 --- a/src/commands/api.js +++ b/src/commands/api.js @@ -15,14 +15,14 @@ class APICommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "api", - }, - }); + command: 'api' + } + }) if (isEmptyCommand(flags, args) || flags.list) { const table = new AsciiTable(`Netlify API Methods`) table.setHeading('API Method', 'Docs Link') - methods.forEach((method) => { + methods.forEach(method => { const { operationId } = method table.addRow(operationId, `https://open-api.netlify.com/#/default/${operationId}`) }) @@ -42,7 +42,7 @@ class APICommand extends Command { } if (flags.data) { - const payload = (typeof flags.data === 'string') ? JSON.parse(flags.data) : flags.data + const payload = typeof flags.data === 'string' ? JSON.parse(flags.data) : flags.data try { const apiResponse = await api[apiMethod](payload) this.log(JSON.stringify(apiResponse, null, 2)) @@ -65,10 +65,7 @@ APICommand.args = [ } ] -APICommand.examples = [ - 'netlify api --list', - "netlify api getSite --data '{ \"site_id\": \"123456\"}'", -] +APICommand.examples = ['netlify api --list', 'netlify api getSite --data \'{ "site_id": "123456"}\''] APICommand.flags = { data: oclif.flags.string({ @@ -77,7 +74,7 @@ APICommand.flags = { }), list: oclif.flags.boolean({ description: 'List out available API methods' - }), + }) } APICommand.strict = false diff --git a/src/commands/deploy.js b/src/commands/deploy.js index aea5c46b6ce..60fe621baf6 100644 --- a/src/commands/deploy.js +++ b/src/commands/deploy.js @@ -25,12 +25,12 @@ class DeployCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "deploy", + command: 'deploy', open: flags.open, prod: flags.prod, - json: flags.json, - }, - }); + json: flags.json + } + }) let siteId = flags.site || site.id let siteData @@ -128,7 +128,9 @@ class DeployCommand extends Command { stat = fs.statSync(functionsFolder) } catch (e) { if (e.code === 'ENOENT') { - console.log(`Functions folder "${functionsFolder}" specified but it doesn't exist! Will proceed without deploying functions`) + console.log( + `Functions folder "${functionsFolder}" specified but it doesn't exist! Will proceed without deploying functions` + ) functionsFolder = undefined } // Improve the message of permission errors @@ -154,10 +156,10 @@ class DeployCommand extends Command { results = await api.deploy(siteId, deployFolder, { configPath: configPath, fnDir: functionsFolder, - statusCb: (flags.json || flags.silent) ? () => {} : deployProgressCb(), + statusCb: flags.json || flags.silent ? () => {} : deployProgressCb(), draft: !deployToProduction, message: flags.message, - deployTimeout: (flags.timeout * 1000) || 1.2e6, + deployTimeout: flags.timeout * 1000 || 1.2e6 }) } catch (e) { switch (true) { @@ -213,7 +215,7 @@ class DeployCommand extends Command { site_id: results.deploy.site_id, deploy_id: results.deployId, deploy_url: deployUrl, - logs: logsUrl, + logs: logsUrl } if (deployToProduction) { jsonData.url = siteUrl @@ -316,7 +318,7 @@ DeployCommand.examples = [ 'netlify deploy --prod', 'netlify deploy --prod --open', 'netlify deploy --message "A message with an $ENV_VAR"', - 'netlify deploy --auth $NETLIFY_AUTH_TOKEN', + 'netlify deploy --auth $NETLIFY_AUTH_TOKEN' ] DeployCommand.flags = { @@ -357,7 +359,7 @@ DeployCommand.flags = { }), timeout: flags.integer({ description: 'Timeout to wait for deployment to finish' - }), + }) } function deployProgressCb() { diff --git a/src/commands/dev/exec.js b/src/commands/dev/exec.js index 33d3421d33a..0e0fe5d84f6 100644 --- a/src/commands/dev/exec.js +++ b/src/commands/dev/exec.js @@ -1,47 +1,45 @@ -const execa = require("execa"); -const Command = require("@netlify/cli-utils"); +const execa = require('execa') +const Command = require('@netlify/cli-utils') const { // NETLIFYDEV, NETLIFYDEVLOG, // NETLIFYDEVWARN, NETLIFYDEVERR -} = require("netlify-cli-logo"); +} = require('netlify-cli-logo') class ExecCommand extends Command { async run() { - const { site, api } = this.netlify; + const { site, api } = this.netlify if (site.id) { - this.log( - `${NETLIFYDEVLOG} Checking your site's environment variables...` - ); // just to show some visual response first - const accessToken = api.accessToken; - const { addEnvVariables } = require("../../utils/dev"); - await addEnvVariables(api, site, accessToken); + this.log(`${NETLIFYDEVLOG} Checking your site's environment variables...`) // just to show some visual response first + const accessToken = api.accessToken + const { addEnvVariables } = require('../../utils/dev') + await addEnvVariables(api, site, accessToken) } else { this.log( `${NETLIFYDEVERR} No Site ID detected. You probably forgot to run \`netlify link\` or \`netlify init\`. ` - ); + ) } execa(this.argv[0], this.argv.slice(1), { env: process.env, - stdio: "inherit" - }); + stdio: 'inherit' + }) await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "dev:exec", - }, - }); + command: 'dev:exec' + } + }) } } ExecCommand.description = `Exec command Runs a command within the netlify dev environment, e.g. with env variables from any installed addons -`; +` -ExecCommand.examples = ["$ netlify exec npm run bootstrap"]; +ExecCommand.examples = ['$ netlify exec npm run bootstrap'] -ExecCommand.strict = false; -ExecCommand.parse = false; +ExecCommand.strict = false +ExecCommand.parse = false -module.exports = ExecCommand; +module.exports = ExecCommand diff --git a/src/commands/dev/index.js b/src/commands/dev/index.js index 460293386f1..a5fe129df59 100644 --- a/src/commands/dev/index.js +++ b/src/commands/dev/index.js @@ -154,8 +154,8 @@ function startDevServer(settings, log) { env: { ...settings.env, FORCE_COLOR: 'true' }, stdio: settings.stdio || 'inherit' }) - if (ps.stdout) ps.stdout.on('data', ((buff) => process.stdout.write(buff.toString('utf8')))) - if (ps.stderr) ps.stderr.on('data', ((buff) => process.stderr.write(buff.toString('utf8')))) + if (ps.stdout) ps.stdout.on('data', buff => process.stdout.write(buff.toString('utf8'))) + if (ps.stderr) ps.stderr.on('data', buff => process.stderr.write(buff.toString('utf8'))) ps.on('close', code => process.exit(code)) ps.on('SIGINT', process.exit) ps.on('SIGTERM', process.exit) @@ -199,7 +199,9 @@ class DevCommand extends Command { this.log( `${NETLIFYDEVWARN} Setup a netlify.toml file with a [dev] section to specify your dev server settings.` ) - this.log(`${NETLIFYDEVWARN} See docs at: https://github.com/netlify/cli/blob/master/docs/netlify-dev.md#project-detection`) + this.log( + `${NETLIFYDEVWARN} See docs at: https://github.com/netlify/cli/blob/master/docs/netlify-dev.md#project-detection` + ) this.log(`${NETLIFYDEVWARN} Using current working directory for now...`) dist = process.cwd() } diff --git a/src/commands/functions/create.js b/src/commands/functions/create.js index 930836ac0e9..aa06d61f6a6 100644 --- a/src/commands/functions/create.js +++ b/src/commands/functions/create.js @@ -1,69 +1,69 @@ -const fs = require("fs-extra"); -const path = require("path"); -const copy = require("copy-template-dir"); -const { flags } = require("@oclif/command"); -const Command = require("@netlify/cli-utils"); -const inquirer = require("inquirer"); -const { readRepoURL, validateRepoURL } = require("../../utils/read-repo-url"); -const { addEnvVariables } = require("../../utils/dev"); -const { createSiteAddon } = require("../../utils/addons"); -const fetch = require("node-fetch"); -const cp = require("child_process"); -const ora = require("ora"); -const chalk = require("chalk"); +const fs = require('fs-extra') +const path = require('path') +const copy = require('copy-template-dir') +const { flags } = require('@oclif/command') +const Command = require('@netlify/cli-utils') +const inquirer = require('inquirer') +const { readRepoURL, validateRepoURL } = require('../../utils/read-repo-url') +const { addEnvVariables } = require('../../utils/dev') +const { createSiteAddon } = require('../../utils/addons') +const fetch = require('node-fetch') +const cp = require('child_process') +const ora = require('ora') +const chalk = require('chalk') const { // NETLIFYDEV, NETLIFYDEVLOG, NETLIFYDEVWARN, NETLIFYDEVERR -} = require("netlify-cli-logo"); +} = require('netlify-cli-logo') -const templatesDir = path.resolve(__dirname, "../../functions-templates"); +const templatesDir = path.resolve(__dirname, '../../functions-templates') /** * Be very clear what is the SOURCE (templates dir) vs the DEST (functions dir) */ class FunctionsCreateCommand extends Command { async run() { - const { flags, args } = this.parse(FunctionsCreateCommand); - const { config } = this.netlify; - const functionsDir = ensureFunctionDirExists.call(this, flags, config); + const { flags, args } = this.parse(FunctionsCreateCommand) + const { config } = this.netlify + const functionsDir = ensureFunctionDirExists.call(this, flags, config) /* either download from URL or scaffold from template */ if (flags.url) { - await downloadFromURL.call(this, flags, args, functionsDir); + await downloadFromURL.call(this, flags, args, functionsDir) } else { - await scaffoldFromTemplate.call(this, flags, args, functionsDir); + await scaffoldFromTemplate.call(this, flags, args, functionsDir) } await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "functions:create", - }, - }); + command: 'functions:create' + } + }) } } FunctionsCreateCommand.args = [ { - name: "name", - description: "name of your new function file inside your functions folder" + name: 'name', + description: 'name of your new function file inside your functions folder' } -]; +] -FunctionsCreateCommand.description = `create a new function locally`; +FunctionsCreateCommand.description = `create a new function locally` FunctionsCreateCommand.examples = [ - "netlify functions:create", - "netlify functions:create hello-world", - "netlify functions:create --name hello-world" -]; -FunctionsCreateCommand.aliases = ["function:create"]; + 'netlify functions:create', + 'netlify functions:create hello-world', + 'netlify functions:create --name hello-world' +] +FunctionsCreateCommand.aliases = ['function:create'] FunctionsCreateCommand.flags = { - name: flags.string({ char: "n", description: "function name" }), - url: flags.string({ char: "u", description: "pull template from URL" }) -}; -module.exports = FunctionsCreateCommand; + name: flags.string({ char: 'n', description: 'function name' }), + url: flags.string({ char: 'u', description: 'pull template from URL' }) +} +module.exports = FunctionsCreateCommand /** * all subsections of code called from the main logic flow above @@ -71,69 +71,63 @@ module.exports = FunctionsCreateCommand; // prompt for a name if name not supplied async function getNameFromArgs(args, flags, defaultName) { - if (flags.name && args.name) - throw new Error( - "function name specified in both flag and arg format, pick one" - ); - let name; - if (flags.name && !args.name) name = flags.name; + if (flags.name && args.name) throw new Error('function name specified in both flag and arg format, pick one') + let name + if (flags.name && !args.name) name = flags.name // use flag if exists - else if (!flags.name && args.name) name = args.name; + else if (!flags.name && args.name) name = args.name // if neither are specified, prompt for it if (!name) { let responses = await inquirer.prompt([ { - name: "name", - message: "name your function: ", + name: 'name', + message: 'name your function: ', default: defaultName, - type: "input", + type: 'input', validate: val => Boolean(val) && /^[\w\-.]+$/i.test(val) // make sure it is not undefined and is a valid filename. // this has some nuance i have ignored, eg crossenv and i18n concerns } - ]); - name = responses.name; + ]) + name = responses.name } - return name; + return name } // pick template from our existing templates async function pickTemplate() { // lazy loading on purpose - inquirer.registerPrompt( - "autocomplete", - require("inquirer-autocomplete-prompt") - ); - const fuzzy = require("fuzzy"); + inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt')) + const fuzzy = require('fuzzy') // doesnt scale but will be ok for now const [ jsreg // tsreg, goreg ] = [ - "js" + 'js' // 'ts', 'go' - ].map(formatRegistryArrayForInquirer); + ].map(formatRegistryArrayForInquirer) const specialCommands = [ new inquirer.Separator(`----[Special Commands]----`), { name: `*** Clone template from Github URL ***`, - value: "url", - short: "gh-url" + value: 'url', + short: 'gh-url' }, { name: `*** Report issue with, or suggest a new template ***`, - value: "report", - short: "gh-report" + value: 'report', + short: 'gh-report' } - ]; + ] const { chosentemplate } = await inquirer.prompt({ - name: "chosentemplate", - message: "Pick a template", - type: "autocomplete", + name: 'chosentemplate', + message: 'Pick a template', + type: 'autocomplete', // suggestOnly: true, // we can explore this for entering URL in future source: async function(answersSoFar, input) { - if (!input || input === "") { + if (!input || input === '') { // show separators return [ new inquirer.Separator(`----[JS]----`), @@ -143,7 +137,7 @@ async function pickTemplate() { // new inquirer.Separator(`----[GO]----`), // ...goreg ...specialCommands - ]; + ] } // only show filtered results sorted by score let ans = [ @@ -151,95 +145,77 @@ async function pickTemplate() { // ...filterRegistry(tsreg, input), // ...filterRegistry(goreg, input) ...specialCommands - ].sort((a, b) => b.score - a.score); - return ans; + ].sort((a, b) => b.score - a.score) + return ans } - }); - return chosentemplate; + }) + return chosentemplate function filterRegistry(registry, input) { - const temp = registry.map(x => x.name + x.description); - const filteredTemplates = fuzzy.filter(input, temp); - const filteredTemplateNames = filteredTemplates.map(x => - input ? x.string : x - ); + const temp = registry.map(x => x.name + x.description) + const filteredTemplates = fuzzy.filter(input, temp) + const filteredTemplateNames = filteredTemplates.map(x => (input ? x.string : x)) return registry .filter(t => filteredTemplateNames.includes(t.name + t.description)) .map(t => { // add the score - const { score } = filteredTemplates.find( - f => f.string === t.name + t.description - ); - t.score = score; - return t; - }); + const { score } = filteredTemplates.find(f => f.string === t.name + t.description) + t.score = score + return t + }) } function formatRegistryArrayForInquirer(lang) { - const folderNames = fs.readdirSync(path.join(templatesDir, lang)); + const folderNames = fs.readdirSync(path.join(templatesDir, lang)) const registry = folderNames - .filter(x => !x.endsWith(".md")) // filter out markdown files - .map(name => - require(path.join( - templatesDir, - lang, - name, - ".netlify-function-template.js" - )) - ) + .filter(x => !x.endsWith('.md')) // filter out markdown files + .map(name => require(path.join(templatesDir, lang, name, '.netlify-function-template.js'))) .sort((a, b) => (a.priority || 999) - (b.priority || 999)) .map(t => { - t.lang = lang; + t.lang = lang return { // confusing but this is the format inquirer wants name: `[${t.name}] ` + t.description, value: t, - short: lang + "-" + t.name - }; - }); - return registry; + short: lang + '-' + t.name + } + }) + return registry } } /* get functions dir (and make it if necessary) */ function ensureFunctionDirExists(flags, config) { - const functionsDir = config.build && config.build.functions; + const functionsDir = config.build && config.build.functions if (!functionsDir) { - this.log(`${NETLIFYDEVLOG} No functions folder specified in netlify.toml`); - process.exit(1); + this.log(`${NETLIFYDEVLOG} No functions folder specified in netlify.toml`) + process.exit(1) } if (!fs.existsSync(functionsDir)) { this.log( `${NETLIFYDEVLOG} functions folder ${chalk.magenta.inverse( functionsDir )} specified in netlify.toml but folder not found, creating it...` - ); - fs.mkdirSync(functionsDir); - this.log( - `${NETLIFYDEVLOG} functions folder ${chalk.magenta.inverse( - functionsDir - )} created` - ); + ) + fs.mkdirSync(functionsDir) + this.log(`${NETLIFYDEVLOG} functions folder ${chalk.magenta.inverse(functionsDir)} created`) } - return functionsDir; + return functionsDir } // Download files from a given github URL async function downloadFromURL(flags, args, functionsDir) { - const folderContents = await readRepoURL(flags.url); - const functionName = flags.url.split("/").slice(-1)[0]; - const nameToUse = await getNameFromArgs(args, flags, functionName); - const fnFolder = path.join(functionsDir, nameToUse); - if ( - fs.existsSync(fnFolder + ".js") && - fs.lstatSync(fnFolder + ".js").isFile() - ) { + const folderContents = await readRepoURL(flags.url) + const functionName = flags.url.split('/').slice(-1)[0] + const nameToUse = await getNameFromArgs(args, flags, functionName) + const fnFolder = path.join(functionsDir, nameToUse) + if (fs.existsSync(fnFolder + '.js') && fs.lstatSync(fnFolder + '.js').isFile()) { this.log( `${NETLIFYDEVWARN}: A single file version of the function ${nameToUse} already exists at ${fnFolder}.js. Terminating without further action.` - ); - process.exit(1); + ) + process.exit(1) } try { - fs.mkdirSync(fnFolder, { recursive: true }); + fs.mkdirSync(fnFolder, { recursive: true }) } catch (error) { // Ignore } @@ -247,213 +223,168 @@ async function downloadFromURL(flags, args, functionsDir) { folderContents.map(({ name, download_url }) => { return fetch(download_url) .then(res => { - const finalName = - path.basename(name, ".js") === functionName - ? nameToUse + ".js" - : name; - const dest = fs.createWriteStream(path.join(fnFolder, finalName)); - res.body.pipe(dest); + const finalName = path.basename(name, '.js') === functionName ? nameToUse + '.js' : name + const dest = fs.createWriteStream(path.join(fnFolder, finalName)) + res.body.pipe(dest) }) .catch(error => { - throw new Error( - "Error while retrieving " + download_url + ` ${error}` - ); - }); + throw new Error('Error while retrieving ' + download_url + ` ${error}`) + }) }) - ); + ) - this.log(`${NETLIFYDEVLOG} Installing dependencies for ${nameToUse}...`); - cp.exec("npm i", { cwd: path.join(functionsDir, nameToUse) }, () => { - this.log( - `${NETLIFYDEVLOG} Installing dependencies for ${nameToUse} complete ` - ); - }); + this.log(`${NETLIFYDEVLOG} Installing dependencies for ${nameToUse}...`) + cp.exec('npm i', { cwd: path.join(functionsDir, nameToUse) }, () => { + this.log(`${NETLIFYDEVLOG} Installing dependencies for ${nameToUse} complete `) + }) // read, execute, and delete function template file if exists - const fnTemplateFile = path.join(fnFolder, ".netlify-function-template.js"); + const fnTemplateFile = path.join(fnFolder, '.netlify-function-template.js') if (fs.existsSync(fnTemplateFile)) { - const { onComplete, addons = [] } = require(fnTemplateFile); + const { onComplete, addons = [] } = require(fnTemplateFile) - await installAddons.call(this, addons, path.resolve(fnFolder)); + await installAddons.call(this, addons, path.resolve(fnFolder)) if (onComplete) { - await addEnvVariables( - this.netlify.api, - this.netlify.site, - this.netlify.api.accessToken - ); - await onComplete.call(this); + await addEnvVariables(this.netlify.api, this.netlify.site, this.netlify.api.accessToken) + await onComplete.call(this) } - fs.unlinkSync(fnTemplateFile); // delete + fs.unlinkSync(fnTemplateFile) // delete } } async function installDeps(functionPath) { return new Promise(resolve => { - cp.exec("npm i", { cwd: path.join(functionPath) }, () => { - resolve(); - }); - }); + cp.exec('npm i', { cwd: path.join(functionPath) }, () => { + resolve() + }) + }) } // no --url flag specified, pick from a provided template async function scaffoldFromTemplate(flags, args, functionsDir) { - const chosentemplate = await pickTemplate.call(this); // pull the rest of the metadata from the template - if (chosentemplate === "url") { + const chosentemplate = await pickTemplate.call(this) // pull the rest of the metadata from the template + if (chosentemplate === 'url') { const { chosenurl } = await inquirer.prompt([ { - name: "chosenurl", - message: "URL to clone: ", - type: "input", + name: 'chosenurl', + message: 'URL to clone: ', + type: 'input', validate: val => Boolean(validateRepoURL(val)) // make sure it is not undefined and is a valid filename. // this has some nuance i have ignored, eg crossenv and i18n concerns } - ]); - flags.url = chosenurl.trim(); + ]) + flags.url = chosenurl.trim() try { - await downloadFromURL.call(this, flags, args, functionsDir); + await downloadFromURL.call(this, flags, args, functionsDir) } catch (error) { - this.error(`$${NETLIFYDEVERR} Error downloading from URL: ` + flags.url); - this.error(error); - process.exit(1); + this.error(`$${NETLIFYDEVERR} Error downloading from URL: ` + flags.url) + this.error(error) + process.exit(1) } - } else if (chosentemplate === "report") { - this.log( - `${NETLIFYDEVLOG} Open in browser: https://github.com/netlify/cli/issues/new` - ); + } else if (chosentemplate === 'report') { + this.log(`${NETLIFYDEVLOG} Open in browser: https://github.com/netlify/cli/issues/new`) } else { - const { - onComplete, - name: templateName, - lang, - addons = [] - } = chosentemplate; + const { onComplete, name: templateName, lang, addons = [] } = chosentemplate - const pathToTemplate = path.join(templatesDir, lang, templateName); + const pathToTemplate = path.join(templatesDir, lang, templateName) if (!fs.existsSync(pathToTemplate)) { throw new Error( `there isnt a corresponding folder to the selected name, ${templateName} template is misconfigured` - ); + ) } - const name = await getNameFromArgs(args, flags, templateName); - this.log(`${NETLIFYDEVLOG} Creating function ${chalk.cyan.inverse(name)}`); - const functionPath = ensureFunctionPathIsOk.call( - this, - functionsDir, - flags, - name - ); + const name = await getNameFromArgs(args, flags, templateName) + this.log(`${NETLIFYDEVLOG} Creating function ${chalk.cyan.inverse(name)}`) + const functionPath = ensureFunctionPathIsOk.call(this, functionsDir, flags, name) // // SWYX: note to future devs - useful for debugging source to output issues // this.log('from ', pathToTemplate, ' to ', functionPath) - const vars = { NETLIFY_STUFF_TO_REPLACE: "REPLACEMENT" }; // SWYX: TODO - let hasPackageJSON = false; + const vars = { NETLIFY_STUFF_TO_REPLACE: 'REPLACEMENT' } // SWYX: TODO + let hasPackageJSON = false copy(pathToTemplate, functionPath, vars, async (err, createdFiles) => { - if (err) throw err; + if (err) throw err createdFiles.forEach(filePath => { - if (filePath.endsWith(".netlify-function-template.js")) return; - this.log( - `${NETLIFYDEVLOG} ${chalk.greenBright("Created")} ${filePath}` - ); - require("fs").chmodSync(path.resolve(filePath), 0o777); - if (filePath.includes("package.json")) hasPackageJSON = true; - }); + if (filePath.endsWith('.netlify-function-template.js')) return + this.log(`${NETLIFYDEVLOG} ${chalk.greenBright('Created')} ${filePath}`) + require('fs').chmodSync(path.resolve(filePath), 0o777) + if (filePath.includes('package.json')) hasPackageJSON = true + }) // delete function template file that was copied over by copydir - fs.unlinkSync(path.join(functionPath, ".netlify-function-template.js")); + fs.unlinkSync(path.join(functionPath, '.netlify-function-template.js')) // rename the root function file if it has a different name from default if (name !== templateName) { - fs.renameSync( - path.join(functionPath, templateName + ".js"), - path.join(functionPath, name + ".js") - ); + fs.renameSync(path.join(functionPath, templateName + '.js'), path.join(functionPath, name + '.js')) } // npm install if (hasPackageJSON) { const spinner = ora({ text: `installing dependencies for ${name}`, - spinner: "moon" - }).start(); - await installDeps(functionPath); - spinner.succeed(`installed dependencies for ${name}`); + spinner: 'moon' + }).start() + await installDeps(functionPath) + spinner.succeed(`installed dependencies for ${name}`) } - installAddons.call(this, addons, path.resolve(functionPath)); + installAddons.call(this, addons, path.resolve(functionPath)) if (onComplete) { - await addEnvVariables( - this.netlify.api, - this.netlify.site, - this.netlify.api.accessToken - ); - await onComplete.call(this); + await addEnvVariables(this.netlify.api, this.netlify.site, this.netlify.api.accessToken) + await onComplete.call(this) } - }); + }) } } async function installAddons(addons = [], fnPath) { if (addons.length > 0) { - const { api, site } = this.netlify; - const siteId = site.id; + const { api, site } = this.netlify + const siteId = site.id if (!siteId) { - this.log( - "No site id found, please run inside a site folder or `netlify link`" - ); - return false; + this.log('No site id found, please run inside a site folder or `netlify link`') + return false } - this.log(`${NETLIFYDEVLOG} checking Netlify APIs...`); + this.log(`${NETLIFYDEVLOG} checking Netlify APIs...`) return api.getSite({ siteId }).then(async siteData => { - const accessToken = api.accessToken; + const accessToken = api.accessToken const arr = addons.map(({ addonName, addonDidInstall }) => { - this.log( - `${NETLIFYDEVLOG} installing addon: ` + - chalk.yellow.inverse(addonName) - ); + this.log(`${NETLIFYDEVLOG} installing addon: ` + chalk.yellow.inverse(addonName)) // will prompt for configs if not supplied - we do not yet allow for addon configs supplied by `netlify functions:create` command and may never do so - return createSiteAddon( - accessToken, - addonName, - siteId, - siteData, - this.log - ) + return createSiteAddon(accessToken, addonName, siteId, siteData, this.log) .then(async addonCreateMsg => { if (addonCreateMsg) { // spinner.success("installed addon: " + addonName); if (addonDidInstall) { - const { addEnvVariables } = require("../../utils/dev"); - await addEnvVariables(api, site, accessToken); + const { addEnvVariables } = require('../../utils/dev') + await addEnvVariables(api, site, accessToken) const { confirmPostInstall } = await inquirer.prompt([ { - type: "confirm", - name: "confirmPostInstall", + type: 'confirm', + name: 'confirmPostInstall', message: `This template has an optional setup script that runs after addon install. This can be helpful for first time users to try out templates. Run the script?`, default: false } - ]); - if (confirmPostInstall) addonDidInstall(fnPath); + ]) + if (confirmPostInstall) addonDidInstall(fnPath) } } }) .catch(error => { - this.error(`${NETLIFYDEVERR} Error installing addon: `, error); - }); - }); - return Promise.all(arr); - }); + this.error(`${NETLIFYDEVERR} Error installing addon: `, error) + }) + }) + return Promise.all(arr) + }) } } // we used to allow for a --dir command, // but have retired that to force every scaffolded function to be a folder function ensureFunctionPathIsOk(functionsDir, flags, name) { - const functionPath = path.join(functionsDir, name); + const functionPath = path.join(functionsDir, name) if (fs.existsSync(functionPath)) { - this.log( - `${NETLIFYDEVLOG} Function ${functionPath} already exists, cancelling...` - ); - process.exit(1); + this.log(`${NETLIFYDEVLOG} Function ${functionPath} already exists, cancelling...`) + process.exit(1) } - return functionPath; + return functionPath } diff --git a/src/commands/functions/index.js b/src/commands/functions/index.js index 382171d5e83..2cef0381591 100644 --- a/src/commands/functions/index.js +++ b/src/commands/functions/index.js @@ -1,52 +1,52 @@ -const chalk = require("chalk"); -const { Command } = require("@oclif/command"); -const { execSync } = require("child_process"); +const chalk = require('chalk') +const { Command } = require('@oclif/command') +const { execSync } = require('child_process') function showHelp(command) { - execSync(`netlify ${command} --help`, { stdio: [0, 1, 2] }); + execSync(`netlify ${command} --help`, { stdio: [0, 1, 2] }) } function isEmptyCommand(flags, args) { if (!hasFlags(flags) && !hasArgs(args)) { - return true; + return true } - return false; + return false } function hasFlags(flags) { - return Object.keys(flags).length; + return Object.keys(flags).length } function hasArgs(args) { - return Object.keys(args).length; + return Object.keys(args).length } class FunctionsCommand extends Command { async run() { - const { flags, args } = this.parse(FunctionsCommand); + const { flags, args } = this.parse(FunctionsCommand) // run help command if no args passed if (isEmptyCommand(flags, args)) { - showHelp(this.id); - this.exit(); + showHelp(this.id) + this.exit() } await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "functions", - }, - }); + command: 'functions' + } + }) } } -const name = chalk.greenBright("`functions`"); -FunctionsCommand.aliases = ["function"]; +const name = chalk.greenBright('`functions`') +FunctionsCommand.aliases = ['function'] FunctionsCommand.description = `Manage netlify functions The ${name} command will help you manage the functions in this site -`; +` FunctionsCommand.examples = [ - "netlify functions:create --name function-xyz", - "netlify functions:build --name function-abc --timeout 30s" -]; + 'netlify functions:create --name function-xyz', + 'netlify functions:build --name function-abc --timeout 30s' +] -module.exports = FunctionsCommand; +module.exports = FunctionsCommand diff --git a/src/commands/init.js b/src/commands/init.js index 57eb5a4965b..ef63ccfaa8b 100644 --- a/src/commands/init.js +++ b/src/commands/init.js @@ -25,12 +25,12 @@ class InitCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "init", + command: 'init', manual: flags.manual, watch: flags.watch, - force: flags.force, - }, - }); + force: flags.force + } + }) // const hasFlags = !isEmpty(flags) let siteData @@ -214,9 +214,7 @@ git remote add origin https://github.com/YourUserName/RepoName.git this.warn(`GitHub error: ${e.status}`) if (e.code === 404) { this.error( - `Does the repository ${ - repo.repo_path - } exist and do you have the correct permissions to set up deploy keys?` + `Does the repository ${repo.repo_path} exist and do you have the correct permissions to set up deploy keys?` ) } else { throw e diff --git a/src/commands/link.js b/src/commands/link.js index 88eb644c203..5a7e64e6f3a 100644 --- a/src/commands/link.js +++ b/src/commands/link.js @@ -17,9 +17,9 @@ class LinkCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "link", - }, - }); + command: 'link' + } + }) let siteData try { @@ -110,11 +110,7 @@ class LinkCommand extends Command { LinkCommand.description = `Link a local repo or project folder to an existing site on Netlify` -LinkCommand.examples = [ - 'netlify link', - 'netlify link --id 123-123-123-123', - 'netlify link --name my-site-name' -] +LinkCommand.examples = ['netlify link', 'netlify link --id 123-123-123-123', 'netlify link --name my-site-name'] LinkCommand.flags = { id: flags.string({ diff --git a/src/commands/login.js b/src/commands/login.js index c8f58822e2a..d532110e2fe 100644 --- a/src/commands/login.js +++ b/src/commands/login.js @@ -5,7 +5,7 @@ const chalk = require('chalk') class LoginCommand extends Command { async run() { const { flags } = this.parse(LoginCommand) - const [ accessToken, location ] = this.getConfigToken() + const [accessToken, location] = this.getConfigToken() if (accessToken && !flags.new) { this.log(`Already logged in ${msg(location)}`) this.log() @@ -19,10 +19,10 @@ class LoginCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "login", - new: flags.new, - }, - }); + command: 'login', + new: flags.new + } + }) await this.expensivelyAuthenticate() @@ -31,7 +31,7 @@ class LoginCommand extends Command { } function msg(location) { - switch(location) { + switch (location) { case 'env': return 'via process.env.NETLIFY_AUTH_TOKEN set in your terminal session' case 'flag': @@ -46,7 +46,7 @@ function msg(location) { LoginCommand.flags = { new: flags.boolean({ description: 'Login to new Netlify account' - }), + }) } LoginCommand.description = `Login to your Netlify account diff --git a/src/commands/logout.js b/src/commands/logout.js index b08efb52398..1f7ed6607bf 100644 --- a/src/commands/logout.js +++ b/src/commands/logout.js @@ -3,7 +3,7 @@ const { track } = require('../utils/telemetry') class LogoutCommand extends Command { async run() { - const [ accessToken, location ] = this.getConfigToken() + const [accessToken, location] = this.getConfigToken() if (!accessToken) { this.log(`Already logged out`) diff --git a/src/commands/open/admin.js b/src/commands/open/admin.js index 3ec5754321d..6e577883326 100644 --- a/src/commands/open/admin.js +++ b/src/commands/open/admin.js @@ -17,9 +17,9 @@ Run \`netlify link\` to connect to this folder to a site`) await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "open:admin", - }, - }); + command: 'open:admin' + } + }) let siteData try { diff --git a/src/commands/open/index.js b/src/commands/open/index.js index f1b5763fb4b..bff3c482ea4 100644 --- a/src/commands/open/index.js +++ b/src/commands/open/index.js @@ -16,12 +16,12 @@ class OpenCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "open", - }, - }); + command: 'open' + } + }) if (flags.site) { - await OpenSiteCommand.run() + await OpenSiteCommand.run() } // Default open netlify admin await OpenAdminCommand.run() @@ -39,11 +39,6 @@ OpenCommand.flags = { OpenCommand.description = `Open settings for the site linked to the current folder` -OpenCommand.examples = [ - 'netlify open --site', - 'netlify open --admin', - 'netlify open:admin', - 'netlify open:site' -] +OpenCommand.examples = ['netlify open --site', 'netlify open --admin', 'netlify open:admin', 'netlify open:site'] module.exports = OpenCommand diff --git a/src/commands/open/site.js b/src/commands/open/site.js index 8b2e0fc2d14..56b3dadf7e3 100644 --- a/src/commands/open/site.js +++ b/src/commands/open/site.js @@ -17,9 +17,9 @@ Run \`netlify link\` to connect to this folder to a site`) await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "open:site", - }, - }); + command: 'open:site' + } + }) let siteData let url diff --git a/src/commands/sites/config.js b/src/commands/sites/config.js index f41f1808f61..109d5eeecb1 100644 --- a/src/commands/sites/config.js +++ b/src/commands/sites/config.js @@ -8,9 +8,9 @@ class SitesConfigCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "sites:config", - }, - }); + command: 'sites:config' + } + }) // TODO handle repo URL updates } @@ -25,7 +25,7 @@ SitesConfigCommand.flags = { name: flags.string({ char: 'n', description: 'name to print' - }), + }) } // TODO implement logic diff --git a/src/commands/sites/create.js b/src/commands/sites/create.js index b43e19e0b7d..139a5d083b4 100644 --- a/src/commands/sites/create.js +++ b/src/commands/sites/create.js @@ -20,9 +20,9 @@ class SitesCreateCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "sites:create", - }, - }); + command: 'sites:create' + } + }) const accounts = await api.listAccountsForUser() @@ -47,7 +47,7 @@ class SitesCreateCommand extends Command { let site // Allow the user to reenter site name if selected one isn't available - const inputSiteName = async (name) => { + const inputSiteName = async name => { if (!userName) userName = await api.getCurrentUser() if (!name) { @@ -61,7 +61,9 @@ class SitesCreateCommand extends Command { ] const siteSuggestion = sample(suggestions) - console.log(`Choose a unique site name (e.g. ${siteSuggestion}.netlify.com) or leave it blank for a random name. You can update the site name later.`) + console.log( + `Choose a unique site name (e.g. ${siteSuggestion}.netlify.com) or leave it blank for a random name. You can update the site name later.` + ) const results = await inquirer.prompt([ { type: 'input', @@ -142,9 +144,7 @@ class SitesCreateCommand extends Command { this.warn(`Github error: ${e.status}`) if (e.code === 404) { this.error( - `Does the repository ${ - repo.repo_path - } exist and do you have the correct permissions to set up deploy keys?` + `Does the repository ${repo.repo_path} exist and do you have the correct permissions to set up deploy keys?` ) } else { throw e @@ -161,7 +161,33 @@ class SitesCreateCommand extends Command { } if (flags.json) { - this.logJson(pick(site, ["id","state","plan","name","custom_domain","domain_aliases","url","ssl_url","admin_url","screenshot_url","created_at","updated_at","user_id","ssl","force_ssl","managed_dns","deploy_url","account_name","account_slug","git_provider","deploy_hook","capabilities","id_domain"])) + this.logJson( + pick(site, [ + 'id', + 'state', + 'plan', + 'name', + 'custom_domain', + 'domain_aliases', + 'url', + 'ssl_url', + 'admin_url', + 'screenshot_url', + 'created_at', + 'updated_at', + 'user_id', + 'ssl', + 'force_ssl', + 'managed_dns', + 'deploy_url', + 'account_name', + 'account_slug', + 'git_provider', + 'deploy_hook', + 'capabilities', + 'id_domain' + ]) + ) } return site diff --git a/src/commands/sites/delete.js b/src/commands/sites/delete.js index 03f19a7cf03..7f57e1fd54e 100644 --- a/src/commands/sites/delete.js +++ b/src/commands/sites/delete.js @@ -30,10 +30,10 @@ class SitesDeleteCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "sites:delete", - force: flags.force, - }, - }); + command: 'sites:delete', + force: flags.force + } + }) const { force, f } = parseRawFlags(raw) const noForce = !force && !f @@ -59,7 +59,7 @@ class SitesDeleteCommand extends Command { } /* Validation logic if siteId passed in does not match current site ID */ - if (noForce && (cwdSiteId && (cwdSiteId !== siteId))) { + if (noForce && (cwdSiteId && cwdSiteId !== siteId)) { this.log(`${chalk.redBright('Warning')}: The siteId supplied does not match the current working directory siteId`) this.log() this.log(`Supplied: "${siteId}"`) @@ -115,8 +115,6 @@ SitesDeleteCommand.flags = { }) } -SitesDeleteCommand.examples = [ - 'netlify site:delete 1234-3262-1211' -] +SitesDeleteCommand.examples = ['netlify site:delete 1234-3262-1211'] module.exports = SitesDeleteCommand diff --git a/src/commands/sites/index.js b/src/commands/sites/index.js index b91225f9f06..9757231757c 100644 --- a/src/commands/sites/index.js +++ b/src/commands/sites/index.js @@ -15,9 +15,9 @@ class SitesCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "sites", - }, - }); + command: 'sites' + } + }) } } diff --git a/src/commands/sites/list.js b/src/commands/sites/list.js index 948856439bb..c7527c6d024 100644 --- a/src/commands/sites/list.js +++ b/src/commands/sites/list.js @@ -15,9 +15,9 @@ class SitesListCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "sites:list", - }, - }); + command: 'sites:list' + } + }) const sites = await api.listSites({ filter: 'all' }) if (!flags.json) { diff --git a/src/commands/status/hooks.js b/src/commands/status/hooks.js index 07702770263..458f8f45e97 100644 --- a/src/commands/status/hooks.js +++ b/src/commands/status/hooks.js @@ -16,9 +16,9 @@ class StatusHooksCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: "status:hooks", - }, - }); + command: 'status:hooks' + } + }) let siteData try { diff --git a/src/commands/status/index.js b/src/commands/status/index.js index ef70a91d3a3..78ee1c08045 100644 --- a/src/commands/status/index.js +++ b/src/commands/status/index.js @@ -11,7 +11,7 @@ class StatusCommand extends Command { const { globalConfig, api, site } = this.netlify const { flags } = this.parse(StatusCommand) const current = globalConfig.get('userId') - const [ accessToken ] = this.getConfigToken() + const [accessToken] = this.getConfigToken() if (!accessToken) { this.log(`Not logged in. Please log in to see site status.`) @@ -84,7 +84,7 @@ class StatusCommand extends Command { System: ['OS', 'CPU'], Binaries: ['Node', 'Yarn', 'npm'], Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'], - npmGlobalPackages: ['netlify'], + npmGlobalPackages: ['netlify'] }) this.log(data) } @@ -97,21 +97,23 @@ class StatusCommand extends Command { 'config-path': site.configPath, 'admin-url': siteData.admin_url, 'site-url': siteData.ssl_url || siteData.url, - 'site-id': siteData.id, - }, + 'site-id': siteData.id + } }) } this.log(`────────────────────┐ Netlify Site Info │ ────────────────────┘`) - this.log(prettyjson.render({ - 'Current site': `${siteData.name}`, - 'Netlify TOML': site.configPath, - 'Admin URL': chalk.magentaBright(siteData.admin_url), - 'Site URL': chalk.cyanBright(siteData.ssl_url || siteData.url), - 'Site Id': chalk.yellowBright(siteData.id), - })) + this.log( + prettyjson.render({ + 'Current site': `${siteData.name}`, + 'Netlify TOML': site.configPath, + 'Admin URL': chalk.magentaBright(siteData.admin_url), + 'Site URL': chalk.cyanBright(siteData.ssl_url || siteData.url), + 'Site Id': chalk.yellowBright(siteData.id) + }) + ) this.log() } } diff --git a/src/commands/switch.js b/src/commands/switch.js index 1e9163cca8f..37cb2b3f65b 100644 --- a/src/commands/switch.js +++ b/src/commands/switch.js @@ -7,22 +7,25 @@ class SwitchCommand extends Command { async run() { const LOGIN_NEW = 'I would like to login to a new account' const availableUsersChoices = Object.values(this.netlify.globalConfig.get('users')).reduce( - (prev, current) => Object.assign(prev, { [current.id]: current.name ? `${current.name} (${current.email})` : current.email }), {}) + (prev, current) => + Object.assign(prev, { [current.id]: current.name ? `${current.name} (${current.email})` : current.email }), + {} + ) await this.config.runHook('analytics', { eventName: 'command', payload: { - command: 'switch', - }, - }); + command: 'switch' + } + }) const { accountSwitchChoice } = await inquirer.prompt([ { type: 'list', name: 'accountSwitchChoice', message: 'Please select the account you want to use:', - choices: [...Object.entries(availableUsersChoices).map(([, val]) => val), LOGIN_NEW], - }, + choices: [...Object.entries(availableUsersChoices).map(([, val]) => val), LOGIN_NEW] + } ]) if (accountSwitchChoice === LOGIN_NEW) { diff --git a/src/commands/unlink.js b/src/commands/unlink.js index 8494b4e8667..793563743f6 100644 --- a/src/commands/unlink.js +++ b/src/commands/unlink.js @@ -14,9 +14,9 @@ class UnlinkCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: 'unlink', - }, - }); + command: 'unlink' + } + }) let siteData = {} try { diff --git a/src/commands/watch.js b/src/commands/watch.js index 88c02dc0355..734b6dd4db5 100644 --- a/src/commands/watch.js +++ b/src/commands/watch.js @@ -18,9 +18,9 @@ class SitesWatchCommand extends Command { await this.config.runHook('analytics', { eventName: 'command', payload: { - command: 'watch', - }, - }); + command: 'watch' + } + }) // Get latest commit and look for that // git rev-parse HEAD diff --git a/src/detectors/brunch.js b/src/detectors/brunch.js index a0ba2610477..b9f44106675 100644 --- a/src/detectors/brunch.js +++ b/src/detectors/brunch.js @@ -1,30 +1,25 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json", "brunch-config.js"])) return false; + if (!hasRequiredFiles(['package.json', 'brunch-config.js'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["brunch"])) return false; + if (!hasRequiredDeps(['brunch'])) return false /** everything below now assumes that we are within gatsby */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["start"], - preferredCommand: "brunch watch --server" - }); + preferredScriptsArr: ['start'], + preferredCommand: 'brunch watch --server' + }) return { - type: "brunch", + type: 'brunch', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 3333, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${3333}(/)?`, "g"), - dist: "app/assets" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${3333}(/)?`, 'g'), + dist: 'app/assets' + } +} diff --git a/src/detectors/cra.js b/src/detectors/cra.js index 4e854184225..26733dd30cf 100644 --- a/src/detectors/cra.js +++ b/src/detectors/cra.js @@ -1,40 +1,35 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') /** * detection logic - artificial intelligence! * */ module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json"])) return false; + if (!hasRequiredFiles(['package.json'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["react-scripts"])) return false; + if (!hasRequiredDeps(['react-scripts'])) return false /** everything below now assumes that we are within create-react-app */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["start", "serve", "run"], - preferredCommand: "react-scripts start" - }); + preferredScriptsArr: ['start', 'serve', 'run'], + preferredCommand: 'react-scripts start' + }) if (possibleArgsArrs.length === 0) { // ofer to run it when the user doesnt have any scripts setup! 🤯 - possibleArgsArrs.push(["react-scripts", "start"]); + possibleArgsArrs.push(['react-scripts', 'start']) } return { - type: "create-react-app", + type: 'create-react-app', command: getYarnOrNPMCommand(), port: 8888, // the port that the Netlify Dev User will use proxyPort: 3000, // the port that create-react-app normally outputs - env: { ...process.env, BROWSER: "none", PORT: 3000 }, + env: { ...process.env, BROWSER: 'none', PORT: 3000 }, stdio: ['inherit', 'pipe', 'pipe'], possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, "g"), - dist: "public" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, 'g'), + dist: 'public' + } +} diff --git a/src/detectors/docusaurus.js b/src/detectors/docusaurus.js index 746948cb450..bd4b9b92af5 100644 --- a/src/detectors/docusaurus.js +++ b/src/detectors/docusaurus.js @@ -1,30 +1,25 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json", "siteConfig.js"])) return false; + if (!hasRequiredFiles(['package.json', 'siteConfig.js'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["docusaurus"])) return false; + if (!hasRequiredDeps(['docusaurus'])) return false /** everything below now assumes that we are within gatsby */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["start"], - preferredCommand: "docusaurus-start" - }); + preferredScriptsArr: ['start'], + preferredCommand: 'docusaurus-start' + }) return { - type: "docusaurus", + type: 'docusaurus', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 3000, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, "g"), - dist: "static" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, 'g'), + dist: 'static' + } +} diff --git a/src/detectors/eleventy.js b/src/detectors/eleventy.js index 045d70981c2..d31c3295e1d 100644 --- a/src/detectors/eleventy.js +++ b/src/detectors/eleventy.js @@ -2,23 +2,23 @@ const { // hasRequiredDeps, hasRequiredFiles // scanScripts -} = require("./utils/jsdetect"); +} = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json", ".eleventy.js"])) return false; + if (!hasRequiredFiles(['package.json', '.eleventy.js'])) return false // commented this out because we're not sure if we want to require it // // REQUIRED DEPS // if (!hasRequiredDeps(["@11y/eleventy"])) return false; return { - type: "eleventy", + type: 'eleventy', port: 8888, proxyPort: 8080, env: { ...process.env }, - command: "npx", - possibleArgsArrs: [["eleventy", "--serve", "--watch"]], - urlRegexp: new RegExp(`(http://)([^:]+:)${8080}(/)?`, "g"), - dist: "_site" - }; -}; + command: 'npx', + possibleArgsArrs: [['eleventy', '--serve', '--watch']], + urlRegexp: new RegExp(`(http://)([^:]+:)${8080}(/)?`, 'g'), + dist: '_site' + } +} diff --git a/src/detectors/gatsby.js b/src/detectors/gatsby.js index 8caff8c705b..57eb944197a 100644 --- a/src/detectors/gatsby.js +++ b/src/detectors/gatsby.js @@ -1,34 +1,29 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json", "gatsby-config.js"])) return false; + if (!hasRequiredFiles(['package.json', 'gatsby-config.js'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["gatsby"])) return false; + if (!hasRequiredDeps(['gatsby'])) return false /** everything below now assumes that we are within gatsby */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["start", "develop", "dev"], - preferredCommand: "gatsby develop" - }); + preferredScriptsArr: ['start', 'develop', 'dev'], + preferredCommand: 'gatsby develop' + }) if (possibleArgsArrs.length === 0) { // ofer to run it when the user doesnt have any scripts setup! 🤯 - possibleArgsArrs.push(["gatsby", "develop"]); + possibleArgsArrs.push(['gatsby', 'develop']) } return { - type: "gatsby", + type: 'gatsby', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 8000, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${8000}(/)?`, "g"), - dist: "public" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${8000}(/)?`, 'g'), + dist: 'public' + } +} diff --git a/src/detectors/gridsome.js b/src/detectors/gridsome.js index efe026c9ff3..fd35d7815f1 100644 --- a/src/detectors/gridsome.js +++ b/src/detectors/gridsome.js @@ -1,30 +1,25 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json", "gridsome.config.js"])) return false; + if (!hasRequiredFiles(['package.json', 'gridsome.config.js'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["gridsome"])) return false; + if (!hasRequiredDeps(['gridsome'])) return false /** everything below now assumes that we are within gridsome */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["develop"], - preferredCommand: "gridsome develop" - }); + preferredScriptsArr: ['develop'], + preferredCommand: 'gridsome develop' + }) return { - type: "gridsome", + type: 'gridsome', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 8080, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${8080}(/)?`, "g"), - dist: "static" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${8080}(/)?`, 'g'), + dist: 'static' + } +} diff --git a/src/detectors/hexo.js b/src/detectors/hexo.js index a269a5c9428..750c0720908 100644 --- a/src/detectors/hexo.js +++ b/src/detectors/hexo.js @@ -1,34 +1,29 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json", "_config.yml"])) return false; + if (!hasRequiredFiles(['package.json', '_config.yml'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["hexo"])) return false; + if (!hasRequiredDeps(['hexo'])) return false /** everything below now assumes that we are within gatsby */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["start", "dev", "develop"], - preferredCommand: "hexo server" - }); + preferredScriptsArr: ['start', 'dev', 'develop'], + preferredCommand: 'hexo server' + }) if (possibleArgsArrs.length === 0) { // ofer to run it when the user doesnt have any scripts setup! 🤯 - possibleArgsArrs.push(["hexo", "server"]); + possibleArgsArrs.push(['hexo', 'server']) } return { - type: "hexo", + type: 'hexo', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 4000, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${4000}(/)?`, "g"), - dist: "public" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${4000}(/)?`, 'g'), + dist: 'public' + } +} diff --git a/src/detectors/hugo.js b/src/detectors/hugo.js index aac2b8da82f..1ff1e25f5a7 100644 --- a/src/detectors/hugo.js +++ b/src/detectors/hugo.js @@ -1,18 +1,18 @@ -const { existsSync } = require("fs"); +const { existsSync } = require('fs') module.exports = function() { - if (!existsSync("config.toml") && !existsSync("config.yaml")) { - return false; + if (!existsSync('config.toml') && !existsSync('config.yaml')) { + return false } return { - type: "hugo", + type: 'hugo', port: 8888, proxyPort: 1313, env: { ...process.env }, - command: "hugo", - possibleArgsArrs: [["server", "-w"]], - urlRegexp: new RegExp(`(http://)([^:]+:)${1313}(/)?`, "g"), - dist: "public" - }; -}; + command: 'hugo', + possibleArgsArrs: [['server', '-w']], + urlRegexp: new RegExp(`(http://)([^:]+:)${1313}(/)?`, 'g'), + dist: 'public' + } +} diff --git a/src/detectors/jekyll.js b/src/detectors/jekyll.js index 89d4397e21f..3d8b68e282b 100644 --- a/src/detectors/jekyll.js +++ b/src/detectors/jekyll.js @@ -1,18 +1,18 @@ -const { existsSync } = require("fs"); +const { existsSync } = require('fs') module.exports = function() { - if (!existsSync("_config.yml")) { - return false; + if (!existsSync('_config.yml')) { + return false } return { - type: "jekyll", + type: 'jekyll', port: 8888, proxyPort: 4000, env: { ...process.env }, - command: "bundle", - possibleArgsArrs: [["exec", "jekyll", "serve", "-w"]], - urlRegexp: new RegExp(`(http://)([^:]+:)${4000}(/)?`, "g"), - dist: "_site" - }; -}; + command: 'bundle', + possibleArgsArrs: [['exec', 'jekyll', 'serve', '-w']], + urlRegexp: new RegExp(`(http://)([^:]+:)${4000}(/)?`, 'g'), + dist: '_site' + } +} diff --git a/src/detectors/middleman.js b/src/detectors/middleman.js index f512bae7bc5..d091426bd43 100644 --- a/src/detectors/middleman.js +++ b/src/detectors/middleman.js @@ -1,18 +1,18 @@ -const { existsSync } = require("fs"); +const { existsSync } = require('fs') module.exports = function() { - if (!existsSync("config.rb")) { - return false; + if (!existsSync('config.rb')) { + return false } return { - type: "middleman", + type: 'middleman', port: 8888, proxyPort: 4567, env: { ...process.env }, - command: "bundle", - possibleArgsArrs: [["exec", "middleman", "server"]], - urlRegexp: new RegExp(`(http://)([^:]+:)${4567}(/)?`, "g"), - dist: "build" - }; -}; + command: 'bundle', + possibleArgsArrs: [['exec', 'middleman', 'server']], + urlRegexp: new RegExp(`(http://)([^:]+:)${4567}(/)?`, 'g'), + dist: 'build' + } +} diff --git a/src/detectors/next.js b/src/detectors/next.js index 67fbacee8b1..2a6cb6b40ec 100644 --- a/src/detectors/next.js +++ b/src/detectors/next.js @@ -1,34 +1,29 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json"])) return false; + if (!hasRequiredFiles(['package.json'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["next"])) return false; + if (!hasRequiredDeps(['next'])) return false /** everything below now assumes that we are within gatsby */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["dev", "develop", "start"], - preferredCommand: "next" - }); + preferredScriptsArr: ['dev', 'develop', 'start'], + preferredCommand: 'next' + }) if (possibleArgsArrs.length === 0) { // ofer to run it when the user doesnt have any scripts setup! 🤯 - possibleArgsArrs.push(["next"]); + possibleArgsArrs.push(['next']) } return { - type: "next.js", + type: 'next.js', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 3000, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, "g"), - dist: "out" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, 'g'), + dist: 'out' + } +} diff --git a/src/detectors/nuxt.js b/src/detectors/nuxt.js index f81047223f5..12df644728e 100644 --- a/src/detectors/nuxt.js +++ b/src/detectors/nuxt.js @@ -1,36 +1,31 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json"])) return false; + if (!hasRequiredFiles(['package.json'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["nuxt"])) return false; + if (!hasRequiredDeps(['nuxt'])) return false /** everything below now assumes that we are within vue */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["start", "dev", "run"], - preferredCommand: "nuxt start" - }); + preferredScriptsArr: ['start', 'dev', 'run'], + preferredCommand: 'nuxt start' + }) if (possibleArgsArrs.length === 0) { // ofer to run it when the user doesnt have any scripts setup! 🤯 - possibleArgsArrs.push(["nuxt", "start"]); + possibleArgsArrs.push(['nuxt', 'start']) } return { - type: "yarn", + type: 'yarn', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 3000, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, "g"), - dist: ".nuxt" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, 'g'), + dist: '.nuxt' + } +} diff --git a/src/detectors/parcel.js b/src/detectors/parcel.js index e8f4f9eb010..aeaee00344f 100644 --- a/src/detectors/parcel.js +++ b/src/detectors/parcel.js @@ -1,38 +1,32 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') - module.exports = function() { +module.exports = function() { /* REQUIRED FILES */ - if (!hasRequiredFiles(["package.json"])) return false; + if (!hasRequiredFiles(['package.json'])) return false - /* REQUIRED DEPS */ - if (!(hasRequiredDeps(["parcel-bundler"]) || hasRequiredDeps(["parcel"]))) - return false; + /* REQUIRED DEPS */ + if (!(hasRequiredDeps(['parcel-bundler']) || hasRequiredDeps(['parcel']))) return false - /* Everything below now assumes that we are within parcel */ + /* Everything below now assumes that we are within parcel */ - const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["start", "dev", "run"], - preferredCommand: "parcel" - }); + const possibleArgsArrs = scanScripts({ + preferredScriptsArr: ['start', 'dev', 'run'], + preferredCommand: 'parcel' + }) - if (possibleArgsArrs.length === 0) { + if (possibleArgsArrs.length === 0) { /* Offer to run it when the user doesnt have any scripts setup! 🤯 */ - possibleArgsArrs.push(["parcel"]); + possibleArgsArrs.push(['parcel']) } - return { - type: "parcel", + return { + type: 'parcel', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 1234, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${1234}(/)?`, "g"), - dist: "dist" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${1234}(/)?`, 'g'), + dist: 'dist' + } +} diff --git a/src/detectors/phenomic.js b/src/detectors/phenomic.js index 485eb0392eb..abec8eb355b 100644 --- a/src/detectors/phenomic.js +++ b/src/detectors/phenomic.js @@ -1,30 +1,25 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json"])) return false; + if (!hasRequiredFiles(['package.json'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["@phenomic/core"])) return false; + if (!hasRequiredDeps(['@phenomic/core'])) return false /** everything below now assumes that we are within gatsby */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["start"], - preferredCommand: "phenomic start" - }); + preferredScriptsArr: ['start'], + preferredCommand: 'phenomic start' + }) return { - type: "phenomic", + type: 'phenomic', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 3333, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${3333}(/)?`, "g"), - dist: "public" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${3333}(/)?`, 'g'), + dist: 'public' + } +} diff --git a/src/detectors/quasar-v0.17.js b/src/detectors/quasar-v0.17.js index 23a04a94918..735530e4985 100644 --- a/src/detectors/quasar-v0.17.js +++ b/src/detectors/quasar-v0.17.js @@ -1,37 +1,32 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json"])) return false; + if (!hasRequiredFiles(['package.json'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["quasar-cli"])) return false; + if (!hasRequiredDeps(['quasar-cli'])) return false /** everything below now assumes that we are within Quasar */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["serve", "start", "run", "dev"] + preferredScriptsArr: ['serve', 'start', 'run', 'dev'] // NOTE: this is comented out as it was picking this up in cordova related scripts. // preferredCommand: "quasar dev" - }); + }) if (possibleArgsArrs.length === 0) { // ofer to run this default when the user doesnt have any matching scripts setup! - possibleArgsArrs.push(["quasar", "dev"]); + possibleArgsArrs.push(['quasar', 'dev']) } return { - type: "quasar-cli-v0.17", + type: 'quasar-cli-v0.17', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 8080, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${8080}(/)?`, "g"), - dist: ".quasar" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${8080}(/)?`, 'g'), + dist: '.quasar' + } +} diff --git a/src/detectors/quasar.js b/src/detectors/quasar.js index 24ec3fb9b89..1b4308c910c 100644 --- a/src/detectors/quasar.js +++ b/src/detectors/quasar.js @@ -1,37 +1,32 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json"])) return false; + if (!hasRequiredFiles(['package.json'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["@quasar/app"])) return false; + if (!hasRequiredDeps(['@quasar/app'])) return false /** everything below now assumes that we are within Quasar */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["serve", "start", "run", "dev"] + preferredScriptsArr: ['serve', 'start', 'run', 'dev'] // NOTE: this is comented out as it was picking this up in cordova related scripts. // preferredCommand: "quasar dev" - }); + }) if (possibleArgsArrs.length === 0) { // ofer to run this default when the user doesnt have any matching scripts setup! - possibleArgsArrs.push(["quasar", "dev"]); + possibleArgsArrs.push(['quasar', 'dev']) } return { - type: "quasar-cli", + type: 'quasar-cli', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 8080, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${8080}(/)?`, "g"), - dist: ".quasar" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${8080}(/)?`, 'g'), + dist: '.quasar' + } +} diff --git a/src/detectors/react-static.js b/src/detectors/react-static.js index 08dfeb6693f..127463f3216 100644 --- a/src/detectors/react-static.js +++ b/src/detectors/react-static.js @@ -1,34 +1,29 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json", "static.config.js"])) return false; + if (!hasRequiredFiles(['package.json', 'static.config.js'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["react-static"])) return false; + if (!hasRequiredDeps(['react-static'])) return false /** everything below now assumes that we are within react-static */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["start", "develop", "dev"], - preferredCommand: "react-static start" - }); + preferredScriptsArr: ['start', 'develop', 'dev'], + preferredCommand: 'react-static start' + }) if (possibleArgsArrs.length === 0) { // ofer to run it when the user doesnt have any scripts setup! 🤯 - possibleArgsArrs.push(["react-static", "start"]); + possibleArgsArrs.push(['react-static', 'start']) } return { - type: "react-static", + type: 'react-static', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 3000, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, "g"), - dist: "dist" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, 'g'), + dist: 'dist' + } +} diff --git a/src/detectors/sapper.js b/src/detectors/sapper.js index 3443b474f20..c4347ea26f4 100644 --- a/src/detectors/sapper.js +++ b/src/detectors/sapper.js @@ -1,36 +1,31 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json"])) return false; + if (!hasRequiredFiles(['package.json'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["sapper"])) return false; + if (!hasRequiredDeps(['sapper'])) return false /** everything below now assumes that we are within Sapper */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["dev", "start"], - preferredCommand: "sapper dev" - }); + preferredScriptsArr: ['dev', 'start'], + preferredCommand: 'sapper dev' + }) if (possibleArgsArrs.length === 0) { // ofer to run it when the user doesnt have any scripts setup! 🤯 - possibleArgsArrs.push(["sapper", "dev"]); + possibleArgsArrs.push(['sapper', 'dev']) } return { - type: "sapper", + type: 'sapper', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 3000, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, "g"), - dist: "static" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, 'g'), + dist: 'static' + } +} diff --git a/src/detectors/stencil.js b/src/detectors/stencil.js index 0ed753ded84..cffc173ba59 100644 --- a/src/detectors/stencil.js +++ b/src/detectors/stencil.js @@ -1,34 +1,29 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') /** * detection logic - artificial intelligence! * */ module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json", "stencil.config.ts"])) return false; + if (!hasRequiredFiles(['package.json', 'stencil.config.ts'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["@stencil/core"])) return false; + if (!hasRequiredDeps(['@stencil/core'])) return false /** everything below now assumes that we are within stencil */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["start"], - preferredCommand: "stencil build --dev --watch --serve" - }); + preferredScriptsArr: ['start'], + preferredCommand: 'stencil build --dev --watch --serve' + }) return { - type: "stencil", + type: 'stencil', command: getYarnOrNPMCommand(), port: 8888, // the port that the Netlify Dev User will use proxyPort: 3333, // the port that stencil normally outputs - env: { ...process.env, BROWSER: "none", PORT: 3000 }, + env: { ...process.env, BROWSER: 'none', PORT: 3000 }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, "g"), - dist: "www" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${3000}(/)?`, 'g'), + dist: 'www' + } +} diff --git a/src/detectors/svelte.js b/src/detectors/svelte.js index 2cb33f5f09e..ca009502129 100644 --- a/src/detectors/svelte.js +++ b/src/detectors/svelte.js @@ -1,38 +1,33 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json"])) return false; + if (!hasRequiredFiles(['package.json'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["svelte"])) return false; + if (!hasRequiredDeps(['svelte'])) return false // HAS DETECTOR, IT WILL BE PICKED UP BY SAPPER DETECTOR, avoid duplication https://github.com/netlify/cli/issues/347 - if (hasRequiredDeps(["sapper"])) return false; + if (hasRequiredDeps(['sapper'])) return false /** everything below now assumes that we are within svelte */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["dev", "start", "run"], - preferredCommand: "npm run dev" - }); + preferredScriptsArr: ['dev', 'start', 'run'], + preferredCommand: 'npm run dev' + }) if (possibleArgsArrs.length === 0) { // ofer to run it when the user doesnt have any scripts setup! 🤯 - possibleArgsArrs.push(["npm", "dev"]); + possibleArgsArrs.push(['npm', 'dev']) } return { - type: "svelte", + type: 'svelte', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 5000, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${5000}(/)?`, "g"), - dist: "public" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${5000}(/)?`, 'g'), + dist: 'public' + } +} diff --git a/src/detectors/utils/jsdetect.js b/src/detectors/utils/jsdetect.js index 3cd2f820f44..4875d755e77 100644 --- a/src/detectors/utils/jsdetect.js +++ b/src/detectors/utils/jsdetect.js @@ -3,29 +3,26 @@ * and can therefore build in assumptions that only js projects have * */ -const { existsSync, readFileSync } = require("fs"); -let pkgJSON = null; -let yarnExists = false; -let warnedAboutEmptyScript = false; -const { NETLIFYDEVWARN } = require("netlify-cli-logo"); +const { existsSync, readFileSync } = require('fs') +let pkgJSON = null +let yarnExists = false +let warnedAboutEmptyScript = false +const { NETLIFYDEVWARN } = require('netlify-cli-logo') /** hold package.json in a singleton so we dont do expensive parsing repeatedly */ function getPkgJSON() { if (pkgJSON) { - return pkgJSON; + return pkgJSON } - if (!existsSync("package.json")) - throw new Error( - "dont call this method unless you already checked for pkg json" - ); - pkgJSON = JSON.parse(readFileSync("package.json", { encoding: "utf8" })); - return pkgJSON; + if (!existsSync('package.json')) throw new Error('dont call this method unless you already checked for pkg json') + pkgJSON = JSON.parse(readFileSync('package.json', { encoding: 'utf8' })) + return pkgJSON } function getYarnOrNPMCommand() { if (!yarnExists) { - yarnExists = existsSync("yarn.lock") ? "yes" : "no"; + yarnExists = existsSync('yarn.lock') ? 'yes' : 'no' } - return yarnExists === "yes" ? "yarn" : "npm"; + return yarnExists === 'yes' ? 'yarn' : 'npm' } /** @@ -34,40 +31,38 @@ function getYarnOrNPMCommand() { */ function hasRequiredDeps(requiredDepArray) { - const { dependencies, devDependencies } = getPkgJSON(); + const { dependencies, devDependencies } = getPkgJSON() for (let depName of requiredDepArray) { - const hasItInDeps = dependencies && dependencies[depName]; - const hasItInDevDeps = devDependencies && devDependencies[depName]; + const hasItInDeps = dependencies && dependencies[depName] + const hasItInDevDeps = devDependencies && devDependencies[depName] if (!hasItInDeps && !hasItInDevDeps) { - return false; + return false } } - return true; + return true } function hasRequiredFiles(filenameArr) { for (const filename of filenameArr) { if (!existsSync(filename)) { - return false; + return false } } - return true; + return true } // preferredScriptsArr is in decreasing order of preference function scanScripts({ preferredScriptsArr, preferredCommand }) { - const { scripts } = getPkgJSON(); + const { scripts } = getPkgJSON() if (!scripts && !warnedAboutEmptyScript) { // eslint-disable-next-line no-console - console.log( - `${NETLIFYDEVWARN} You have a package.json without any npm scripts.` - ); + console.log(`${NETLIFYDEVWARN} You have a package.json without any npm scripts.`) // eslint-disable-next-line no-console console.log( `${NETLIFYDEVWARN} Netlify Dev's detector system works best with a script, or you can specify a command to run in the netlify.toml [dev] block ` - ); - warnedAboutEmptyScript = true; // dont spam message with every detector - return []; // not going to match any scripts anyway + ) + warnedAboutEmptyScript = true // dont spam message with every detector + return [] // not going to match any scripts anyway } /** * @@ -83,16 +78,16 @@ function scanScripts({ preferredScriptsArr, preferredCommand }) { // eg make a dependency tree of npm scripts and offer the parentest node first let possibleArgsArrs = preferredScriptsArr .filter(s => Object.keys(scripts).includes(s)) - .filter(s => !scripts[s].includes("netlify dev")) // prevent netlify dev calling netlify dev - .map(x => [x]); // make into arr of arrs + .filter(s => !scripts[s].includes('netlify dev')) // prevent netlify dev calling netlify dev + .map(x => [x]) // make into arr of arrs Object.entries(scripts) .filter(([k]) => !preferredScriptsArr.includes(k)) .forEach(([k, v]) => { - if (v.includes(preferredCommand)) possibleArgsArrs.push([k]); - }); + if (v.includes(preferredCommand)) possibleArgsArrs.push([k]) + }) - return possibleArgsArrs; + return possibleArgsArrs } module.exports = { @@ -100,4 +95,4 @@ module.exports = { hasRequiredFiles, getYarnOrNPMCommand, scanScripts -}; +} diff --git a/src/detectors/vue.js b/src/detectors/vue.js index c69bdb31448..44a0148762d 100644 --- a/src/detectors/vue.js +++ b/src/detectors/vue.js @@ -1,36 +1,31 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json"])) return false; + if (!hasRequiredFiles(['package.json'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["@vue/cli-service"])) return false; + if (!hasRequiredDeps(['@vue/cli-service'])) return false /** everything below now assumes that we are within vue */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["serve", "start", "run"], - preferredCommand: "vue-cli-service serve" - }); + preferredScriptsArr: ['serve', 'start', 'run'], + preferredCommand: 'vue-cli-service serve' + }) if (possibleArgsArrs.length === 0) { // ofer to run it when the user doesnt have any scripts setup! 🤯 - possibleArgsArrs.push(["vue-cli-service", "serve"]); + possibleArgsArrs.push(['vue-cli-service', 'serve']) } return { - type: "vue-cli", + type: 'vue-cli', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 8080, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${8080}(/)?`, "g"), - dist: "dist" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${8080}(/)?`, 'g'), + dist: 'dist' + } +} diff --git a/src/detectors/vuepress.js b/src/detectors/vuepress.js index ef20cf5fb63..327a87ecb78 100644 --- a/src/detectors/vuepress.js +++ b/src/detectors/vuepress.js @@ -1,36 +1,31 @@ -const { - hasRequiredDeps, - hasRequiredFiles, - getYarnOrNPMCommand, - scanScripts -} = require("./utils/jsdetect"); +const { hasRequiredDeps, hasRequiredFiles, getYarnOrNPMCommand, scanScripts } = require('./utils/jsdetect') module.exports = function() { // REQUIRED FILES - if (!hasRequiredFiles(["package.json"])) return false; + if (!hasRequiredFiles(['package.json'])) return false // REQUIRED DEPS - if (!hasRequiredDeps(["vuepress"])) return false; + if (!hasRequiredDeps(['vuepress'])) return false /** everything below now assumes that we are within vue */ const possibleArgsArrs = scanScripts({ - preferredScriptsArr: ["docs:dev", "dev", "run"], - preferredCommand: "vuepress dev" - }); + preferredScriptsArr: ['docs:dev', 'dev', 'run'], + preferredCommand: 'vuepress dev' + }) if (possibleArgsArrs.length === 0) { // ofer to run it when the user doesnt have any scripts setup! 🤯 - possibleArgsArrs.push(["vuepress", "dev"]); + possibleArgsArrs.push(['vuepress', 'dev']) } return { - type: "vuepress", + type: 'vuepress', command: getYarnOrNPMCommand(), port: 8888, proxyPort: 8080, env: { ...process.env }, possibleArgsArrs, - urlRegexp: new RegExp(`(http://)([^:]+:)${8080}(/)?`, "g"), - dist: ".vuepress/dist" - }; -}; + urlRegexp: new RegExp(`(http://)([^:]+:)${8080}(/)?`, 'g'), + dist: '.vuepress/dist' + } +} diff --git a/src/function-builder-detectors/netlify-lambda.js b/src/function-builder-detectors/netlify-lambda.js index 55fba88a31c..51303dbb840 100644 --- a/src/function-builder-detectors/netlify-lambda.js +++ b/src/function-builder-detectors/netlify-lambda.js @@ -1,41 +1,33 @@ -const { existsSync, readFileSync } = require("fs"); -const execa = require("execa"); +const { existsSync, readFileSync } = require('fs') +const execa = require('execa') module.exports = function() { - if (!existsSync("package.json")) { - return false; + if (!existsSync('package.json')) { + return false } - const packageSettings = JSON.parse( - readFileSync("package.json", { encoding: "utf8" }) - ); - const { dependencies, devDependencies, scripts } = packageSettings; - if ( - !( - (dependencies && dependencies["netlify-lambda"]) || - (devDependencies && devDependencies["netlify-lambda"]) - ) - ) { - return false; + const packageSettings = JSON.parse(readFileSync('package.json', { encoding: 'utf8' })) + const { dependencies, devDependencies, scripts } = packageSettings + if (!((dependencies && dependencies['netlify-lambda']) || (devDependencies && devDependencies['netlify-lambda']))) { + return false } - const yarnExists = existsSync("yarn.lock"); - const settings = {}; + const yarnExists = existsSync('yarn.lock') + const settings = {} for (const key in scripts) { - const script = scripts[key]; - const match = script.match(/netlify-lambda build (\S+)/); + const script = scripts[key] + const match = script.match(/netlify-lambda build (\S+)/) if (match) { - settings.src = match[1]; - settings.npmScript = key; - break; + settings.src = match[1] + settings.npmScript = key + break } } if (settings.npmScript) { - settings.build = () => - execa(yarnExists ? "yarn" : "npm", ["run", settings.npmScript]); - settings.builderName = "netlify-lambda"; - return settings; + settings.build = () => execa(yarnExists ? 'yarn' : 'npm', ['run', settings.npmScript]) + settings.builderName = 'netlify-lambda' + return settings } -}; +} diff --git a/src/functions-templates/js/apollo-graphql-rest/.netlify-function-template.js b/src/functions-templates/js/apollo-graphql-rest/.netlify-function-template.js index 29e6b9ed294..b4626b90ee6 100644 --- a/src/functions-templates/js/apollo-graphql-rest/.netlify-function-template.js +++ b/src/functions-templates/js/apollo-graphql-rest/.netlify-function-template.js @@ -1,5 +1,4 @@ module.exports = { - name: "apollo-graphql-rest", - description: - "GraphQL function to wrap REST API using apollo-server-lambda and apollo-datasource-rest!" -}; + name: 'apollo-graphql-rest', + description: 'GraphQL function to wrap REST API using apollo-server-lambda and apollo-datasource-rest!' +} diff --git a/src/functions-templates/js/apollo-graphql-rest/apollo-graphql-rest.js b/src/functions-templates/js/apollo-graphql-rest/apollo-graphql-rest.js index 7c12b2fd2eb..65637ccc2fb 100644 --- a/src/functions-templates/js/apollo-graphql-rest/apollo-graphql-rest.js +++ b/src/functions-templates/js/apollo-graphql-rest/apollo-graphql-rest.js @@ -1,6 +1,6 @@ /* eslint-disable */ -const { ApolloServer, gql } = require("apollo-server-lambda"); -const RandomUser = require("./random-user.js"); +const { ApolloServer, gql } = require('apollo-server-lambda') +const RandomUser = require('./random-user.js') // example from: https://medium.com/yld-engineering-blog/easier-graphql-wrappers-for-your-rest-apis-1410b0b5446d const typeDefs = gql` @@ -47,15 +47,13 @@ const typeDefs = gql` getUser(gender: String): User getUsers(people: Int, gender: String): [User] } -`; +` const resolvers = { Query: { - getUser: async (_, { gender }, { dataSources }) => - dataSources.RandomUser.getUser(gender), - getUsers: async (_, { people, gender }, { dataSources }) => - dataSources.RandomUser.getUsers(people, gender) + getUser: async (_, { gender }, { dataSources }) => dataSources.RandomUser.getUser(gender), + getUsers: async (_, { people, gender }, { dataSources }) => dataSources.RandomUser.getUsers(people, gender) } -}; +} const server = new ApolloServer({ typeDefs, @@ -63,6 +61,6 @@ const server = new ApolloServer({ dataSources: () => ({ RandomUser: new RandomUser() }) -}); +}) -exports.handler = server.createHandler(); +exports.handler = server.createHandler() diff --git a/src/functions-templates/js/apollo-graphql-rest/random-user.js b/src/functions-templates/js/apollo-graphql-rest/random-user.js index a81447f7107..f0c225a68ab 100644 --- a/src/functions-templates/js/apollo-graphql-rest/random-user.js +++ b/src/functions-templates/js/apollo-graphql-rest/random-user.js @@ -1,20 +1,20 @@ -const { RESTDataSource } = require("apollo-datasource-rest"); +const { RESTDataSource } = require('apollo-datasource-rest') class RandomUser extends RESTDataSource { constructor() { - super(); - this.baseURL = "https://randomuser.me/api"; + super() + this.baseURL = 'https://randomuser.me/api' } - async getUser(gender = "all") { - const user = await this.get(`/?gender=${gender}`); - return user.results[0]; + async getUser(gender = 'all') { + const user = await this.get(`/?gender=${gender}`) + return user.results[0] } - async getUsers(people = 10, gender = "all") { - const user = await this.get(`/?results=${people}&gender=${gender}`); - return user.results; + async getUsers(people = 10, gender = 'all') { + const user = await this.get(`/?results=${people}&gender=${gender}`) + return user.results } } -module.exports = RandomUser; +module.exports = RandomUser diff --git a/src/functions-templates/js/apollo-graphql/.netlify-function-template.js b/src/functions-templates/js/apollo-graphql/.netlify-function-template.js index 992deeab3fd..a94c6f7927f 100644 --- a/src/functions-templates/js/apollo-graphql/.netlify-function-template.js +++ b/src/functions-templates/js/apollo-graphql/.netlify-function-template.js @@ -1,4 +1,4 @@ module.exports = { - name: "apollo-graphql", - description: "GraphQL function using Apollo-Server-Lambda!" -}; + name: 'apollo-graphql', + description: 'GraphQL function using Apollo-Server-Lambda!' +} diff --git a/src/functions-templates/js/apollo-graphql/apollo-graphql.js b/src/functions-templates/js/apollo-graphql/apollo-graphql.js index 655a058edff..2afc73dd1e7 100644 --- a/src/functions-templates/js/apollo-graphql/apollo-graphql.js +++ b/src/functions-templates/js/apollo-graphql/apollo-graphql.js @@ -1,4 +1,4 @@ -const { ApolloServer, gql } = require("apollo-server-lambda"); +const { ApolloServer, gql } = require('apollo-server-lambda') const typeDefs = gql` type Query { @@ -12,35 +12,35 @@ const typeDefs = gql` name: String! married: Boolean! } -`; +` const authors = [ - { id: 1, name: "Terry Pratchett", married: false }, - { id: 2, name: "Stephen King", married: true }, - { id: 3, name: "JK Rowling", married: false } -]; + { id: 1, name: 'Terry Pratchett', married: false }, + { id: 2, name: 'Stephen King', married: true }, + { id: 3, name: 'JK Rowling', married: false } +] const resolvers = { Query: { hello: (root, args, context) => { - return "Hello, world!"; + return 'Hello, world!' }, allAuthors: (root, args, context) => { - return authors; + return authors }, author: (root, args, context) => { - return; + return }, authorByName: (root, args, context) => { - console.log("hihhihi", args.name); - return authors.find(x => x.name === args.name) || "NOTFOUND"; + console.log('hihhihi', args.name) + return authors.find(x => x.name === args.name) || 'NOTFOUND' } } -}; +} const server = new ApolloServer({ typeDefs, resolvers -}); +}) -exports.handler = server.createHandler(); +exports.handler = server.createHandler() diff --git a/src/functions-templates/js/auth-fetch/.netlify-function-template.js b/src/functions-templates/js/auth-fetch/.netlify-function-template.js index bf60b2ac18a..190280cc858 100644 --- a/src/functions-templates/js/auth-fetch/.netlify-function-template.js +++ b/src/functions-templates/js/auth-fetch/.netlify-function-template.js @@ -1,10 +1,10 @@ module.exports = { - name: "auth-fetch", - description: "Use `node-fetch` library and Netlify Identity to access APIs", + name: 'auth-fetch', + description: 'Use `node-fetch` library and Netlify Identity to access APIs', onComplete() { - console.log(`auth-fetch function created from template!`); + console.log(`auth-fetch function created from template!`) console.log( - "REMINDER: Make sure to call this function with the Netlify Identity JWT. See https://netlify-gotrue-in-react.netlify.com/ for demo" - ); + 'REMINDER: Make sure to call this function with the Netlify Identity JWT. See https://netlify-gotrue-in-react.netlify.com/ for demo' + ) } -}; +} diff --git a/src/functions-templates/js/auth-fetch/auth-fetch.js b/src/functions-templates/js/auth-fetch/auth-fetch.js index 77f20611455..333b730ea69 100644 --- a/src/functions-templates/js/auth-fetch/auth-fetch.js +++ b/src/functions-templates/js/auth-fetch/auth-fetch.js @@ -1,34 +1,34 @@ /* eslint-disable */ // for a full working demo of Netlify Identity + Functions, see https://netlify-gotrue-in-react.netlify.com/ -const fetch = require("node-fetch"); +const fetch = require('node-fetch') exports.handler = async function(event, context) { if (!context.clientContext && !context.clientContext.identity) { return { statusCode: 500, body: JSON.stringify({ - msg: "No identity instance detected. Did you enable it?" + msg: 'No identity instance detected. Did you enable it?' }) // Could be a custom message or object i.e. JSON.stringify(err) - }; + } } - const { identity, user } = context.clientContext; + const { identity, user } = context.clientContext try { - const response = await fetch("https://api.chucknorris.io/jokes/random"); + const response = await fetch('https://api.chucknorris.io/jokes/random') if (!response.ok) { // NOT res.status >= 200 && res.status < 300 - return { statusCode: response.status, body: response.statusText }; + return { statusCode: response.status, body: response.statusText } } - const data = await response.json(); + const data = await response.json() return { statusCode: 200, body: JSON.stringify({ identity, user, msg: data.value }) - }; + } } catch (err) { - console.log(err); // output to netlify function log + console.log(err) // output to netlify function log return { statusCode: 500, body: JSON.stringify({ msg: err.message }) // Could be a custom message or object i.e. JSON.stringify(err) - }; + } } -}; +} diff --git a/src/functions-templates/js/create-user/.netlify-function-template.js b/src/functions-templates/js/create-user/.netlify-function-template.js index 030d6a2f543..de382ca12a4 100644 --- a/src/functions-templates/js/create-user/.netlify-function-template.js +++ b/src/functions-templates/js/create-user/.netlify-function-template.js @@ -1,11 +1,10 @@ module.exports = { - name: "create-user", - description: - "Programmatically create a Netlify Identity user by invoking a function", + name: 'create-user', + description: 'Programmatically create a Netlify Identity user by invoking a function', onComplete() { - console.log(`create-user function created from template!`); + console.log(`create-user function created from template!`) console.log( - "REMINDER: Make sure to call this function with a Netlify Identity JWT. See https://netlify-gotrue-in-react.netlify.com/ for demo" - ); + 'REMINDER: Make sure to call this function with a Netlify Identity JWT. See https://netlify-gotrue-in-react.netlify.com/ for demo' + ) } -}; +} diff --git a/src/functions-templates/js/create-user/create-user.js b/src/functions-templates/js/create-user/create-user.js index 91b46f17e55..ebb51fa93ca 100644 --- a/src/functions-templates/js/create-user/create-user.js +++ b/src/functions-templates/js/create-user/create-user.js @@ -1,22 +1,21 @@ -const fetch = require("node-fetch"); +const fetch = require('node-fetch') exports.handler = async (event, context) => { - if (event.httpMethod !== "POST") - return { statusCode: 400, body: "Must POST to this function" }; + if (event.httpMethod !== 'POST') return { statusCode: 400, body: 'Must POST to this function' } // send account information along with the POST - const { email, password, full_name } = JSON.parse(event.body); - if (!email) return { statusCode: 400, body: "email missing" }; - if (!password) return { statusCode: 400, body: "password missing" }; - if (!full_name) return { statusCode: 400, body: "full_name missing" }; + const { email, password, full_name } = JSON.parse(event.body) + if (!email) return { statusCode: 400, body: 'email missing' } + if (!password) return { statusCode: 400, body: 'password missing' } + if (!full_name) return { statusCode: 400, body: 'full_name missing' } // identity.token is a short lived admin token which // is provided to all Netlify Functions to interact // with the Identity API - const { identity } = context.clientContext; + const { identity } = context.clientContext await fetch(`${identity.url}/admin/users`, { - method: "POST", + method: 'POST', headers: { Authorization: `Bearer ${identity.token}` }, body: JSON.stringify({ email, @@ -26,10 +25,10 @@ exports.handler = async (event, context) => { full_name } }) - }); + }) return { statusCode: 200, - body: "success!" - }; -}; + body: 'success!' + } +} diff --git a/src/functions-templates/js/fauna-crud/.netlify-function-template.js b/src/functions-templates/js/fauna-crud/.netlify-function-template.js index 9b8e462a93d..b0c559e03ad 100644 --- a/src/functions-templates/js/fauna-crud/.netlify-function-template.js +++ b/src/functions-templates/js/fauna-crud/.netlify-function-template.js @@ -1,16 +1,16 @@ -const execa = require("execa"); +const execa = require('execa') module.exports = { - name: "fauna-crud", - description: "CRUD function using Fauna DB", + name: 'fauna-crud', + description: 'CRUD function using Fauna DB', addons: [ { - addonName: "fauna", + addonName: 'fauna', addonDidInstall(fnPath) { - execa.sync(fnPath + "/create-schema.js", undefined, { + execa.sync(fnPath + '/create-schema.js', undefined, { env: process.env, - stdio: "inherit" - }); + stdio: 'inherit' + }) } } ] -}; +} diff --git a/src/functions-templates/js/fauna-crud/create-schema.js b/src/functions-templates/js/fauna-crud/create-schema.js index 19c60a1834a..a934e41d151 100755 --- a/src/functions-templates/js/fauna-crud/create-schema.js +++ b/src/functions-templates/js/fauna-crud/create-schema.js @@ -1,42 +1,39 @@ #!/usr/bin/env node /* bootstrap database in your FaunaDB account - use with `netlify dev:exec ` */ -const faunadb = require("faunadb"); +const faunadb = require('faunadb') -const q = faunadb.query; +const q = faunadb.query function createFaunaDB() { if (!process.env.FAUNADB_SERVER_SECRET) { - console.log("No FAUNADB_SERVER_SECRET in environment, skipping DB setup"); + console.log('No FAUNADB_SERVER_SECRET in environment, skipping DB setup') } - console.log("Create the database!"); + console.log('Create the database!') const client = new faunadb.Client({ secret: process.env.FAUNADB_SERVER_SECRET - }); + }) /* Based on your requirements, change the schema here */ return client - .query(q.Create(q.Ref("classes"), { name: "items" })) + .query(q.Create(q.Ref('classes'), { name: 'items' })) .then(() => { - console.log("Created items class"); + console.log('Created items class') return client.query( - q.Create(q.Ref("indexes"), { - name: "all_items", - source: q.Ref("classes/items"), + q.Create(q.Ref('indexes'), { + name: 'all_items', + source: q.Ref('classes/items'), active: true }) - ); + ) }) .catch(e => { - if ( - e.requestResult.statusCode === 400 && - e.message === "instance not unique" - ) { - console.log("DB already exists"); + if (e.requestResult.statusCode === 400 && e.message === 'instance not unique') { + console.log('DB already exists') } - throw e; - }); + throw e + }) } -createFaunaDB(); +createFaunaDB() diff --git a/src/functions-templates/js/fauna-crud/create.js b/src/functions-templates/js/fauna-crud/create.js index 47cd9791112..831a20bc429 100644 --- a/src/functions-templates/js/fauna-crud/create.js +++ b/src/functions-templates/js/fauna-crud/create.js @@ -1,36 +1,36 @@ -const faunadb = require("faunadb"); +const faunadb = require('faunadb') /* configure faunaDB Client with our secret */ -const q = faunadb.query; +const q = faunadb.query const client = new faunadb.Client({ secret: process.env.FAUNADB_SERVER_SECRET -}); +}) /* export our lambda function as named "handler" export */ exports.handler = async (event, context) => { /* parse the string body into a useable JS object */ - const data = JSON.parse(event.body); - console.log("Function `create` invoked", data); + const data = JSON.parse(event.body) + console.log('Function `create` invoked', data) const item = { data: data - }; + } /* construct the fauna query */ return client - .query(q.Create(q.Ref("classes/items"), item)) + .query(q.Create(q.Ref('classes/items'), item)) .then(response => { - console.log("success", response); + console.log('success', response) /* Success! return the response with statusCode 200 */ return { statusCode: 200, body: JSON.stringify(response) - }; + } }) .catch(error => { - console.log("error", error); + console.log('error', error) /* Error! return the error with statusCode 400 */ return { statusCode: 400, body: JSON.stringify(error) - }; - }); -}; + } + }) +} diff --git a/src/functions-templates/js/fauna-crud/delete.js b/src/functions-templates/js/fauna-crud/delete.js index f21c7ab8225..c5680dd2e0b 100644 --- a/src/functions-templates/js/fauna-crud/delete.js +++ b/src/functions-templates/js/fauna-crud/delete.js @@ -1,28 +1,28 @@ /* Import faunaDB sdk */ -const faunadb = require("faunadb"); +const faunadb = require('faunadb') -const q = faunadb.query; +const q = faunadb.query const client = new faunadb.Client({ secret: process.env.FAUNADB_SERVER_SECRET -}); +}) exports.handler = async (event, context) => { - const id = event.id; - console.log(`Function 'delete' invoked. delete id: ${id}`); + const id = event.id + console.log(`Function 'delete' invoked. delete id: ${id}`) return client .query(q.Delete(q.Ref(`classes/items/${id}`))) .then(response => { - console.log("success", response); + console.log('success', response) return { statusCode: 200, body: JSON.stringify(response) - }; + } }) .catch(error => { - console.log("error", error); + console.log('error', error) return { statusCode: 400, body: JSON.stringify(error) - }; - }); -}; + } + }) +} diff --git a/src/functions-templates/js/fauna-crud/fauna-crud.js b/src/functions-templates/js/fauna-crud/fauna-crud.js index 3d54dbca5d7..72b2580b32b 100644 --- a/src/functions-templates/js/fauna-crud/fauna-crud.js +++ b/src/functions-templates/js/fauna-crud/fauna-crud.js @@ -1,55 +1,53 @@ /* eslint-disable */ exports.handler = async (event, context) => { - const path = event.path.replace(/\.netlify\/functions\/[^\/]+/, ""); - const segments = path.split("/").filter(e => e); + const path = event.path.replace(/\.netlify\/functions\/[^\/]+/, '') + const segments = path.split('/').filter(e => e) switch (event.httpMethod) { - case "GET": + case 'GET': // e.g. GET /.netlify/functions/fauna-crud if (segments.length === 0) { - return require("./read-all").handler(event, context); + return require('./read-all').handler(event, context) } // e.g. GET /.netlify/functions/fauna-crud/123456 if (segments.length === 1) { - event.id = segments[0]; - return require("./read").handler(event, context); + event.id = segments[0] + return require('./read').handler(event, context) } else { return { statusCode: 500, body: - "too many segments in GET request, must be either /.netlify/functions/fauna-crud or /.netlify/functions/fauna-crud/123456" - }; + 'too many segments in GET request, must be either /.netlify/functions/fauna-crud or /.netlify/functions/fauna-crud/123456' + } } - case "POST": + case 'POST': // e.g. POST /.netlify/functions/fauna-crud with a body of key value pair objects, NOT strings - return require("./create").handler(event, context); - case "PUT": + return require('./create').handler(event, context) + case 'PUT': // e.g. PUT /.netlify/functions/fauna-crud/123456 with a body of key value pair objects, NOT strings if (segments.length === 1) { - event.id = segments[0]; - return require("./update").handler(event, context); + event.id = segments[0] + return require('./update').handler(event, context) } else { return { statusCode: 500, - body: - "invalid segments in POST request, must be /.netlify/functions/fauna-crud/123456" - }; + body: 'invalid segments in POST request, must be /.netlify/functions/fauna-crud/123456' + } } - case "DELETE": + case 'DELETE': // e.g. DELETE /.netlify/functions/fauna-crud/123456 if (segments.length === 1) { - event.id = segments[0]; - return require("./delete").handler(event, context); + event.id = segments[0] + return require('./delete').handler(event, context) } else { return { statusCode: 500, - body: - "invalid segments in DELETE request, must be /.netlify/functions/fauna-crud/123456" - }; + body: 'invalid segments in DELETE request, must be /.netlify/functions/fauna-crud/123456' + } } } return { statusCode: 500, - body: "unrecognized HTTP Method, must be one of GET/POST/PUT/DELETE" - }; -}; + body: 'unrecognized HTTP Method, must be one of GET/POST/PUT/DELETE' + } +} diff --git a/src/functions-templates/js/fauna-crud/read-all.js b/src/functions-templates/js/fauna-crud/read-all.js index e271280b277..4c21ef63ae3 100644 --- a/src/functions-templates/js/fauna-crud/read-all.js +++ b/src/functions-templates/js/fauna-crud/read-all.js @@ -1,34 +1,34 @@ /* Import faunaDB sdk */ -const faunadb = require("faunadb"); +const faunadb = require('faunadb') -const q = faunadb.query; +const q = faunadb.query const client = new faunadb.Client({ secret: process.env.FAUNADB_SERVER_SECRET -}); +}) exports.handler = async (event, context) => { - console.log("Function `read-all` invoked"); + console.log('Function `read-all` invoked') return client - .query(q.Paginate(q.Match(q.Ref("indexes/all_items")))) + .query(q.Paginate(q.Match(q.Ref('indexes/all_items')))) .then(response => { - const itemRefs = response.data; + const itemRefs = response.data // create new query out of item refs. http://bit.ly/2LG3MLg const getAllItemsDataQuery = itemRefs.map(ref => { - return q.Get(ref); - }); + return q.Get(ref) + }) // then query the refs return client.query(getAllItemsDataQuery).then(ret => { return { statusCode: 200, body: JSON.stringify(ret) - }; - }); + } + }) }) .catch(error => { - console.log("error", error); + console.log('error', error) return { statusCode: 400, body: JSON.stringify(error) - }; - }); -}; + } + }) +} diff --git a/src/functions-templates/js/fauna-crud/read.js b/src/functions-templates/js/fauna-crud/read.js index 84efa1706d3..ec9b1359407 100644 --- a/src/functions-templates/js/fauna-crud/read.js +++ b/src/functions-templates/js/fauna-crud/read.js @@ -1,28 +1,28 @@ /* Import faunaDB sdk */ -const faunadb = require("faunadb"); +const faunadb = require('faunadb') -const q = faunadb.query; +const q = faunadb.query const client = new faunadb.Client({ secret: process.env.FAUNADB_SERVER_SECRET -}); +}) exports.handler = async (event, context) => { - const id = event.id; - console.log(`Function 'read' invoked. Read id: ${id}`); + const id = event.id + console.log(`Function 'read' invoked. Read id: ${id}`) return client .query(q.Get(q.Ref(`classes/items/${id}`))) .then(response => { - console.log("success", response); + console.log('success', response) return { statusCode: 200, body: JSON.stringify(response) - }; + } }) .catch(error => { - console.log("error", error); + console.log('error', error) return { statusCode: 400, body: JSON.stringify(error) - }; - }); -}; + } + }) +} diff --git a/src/functions-templates/js/fauna-crud/update.js b/src/functions-templates/js/fauna-crud/update.js index ee563defb03..cceff60b4ce 100644 --- a/src/functions-templates/js/fauna-crud/update.js +++ b/src/functions-templates/js/fauna-crud/update.js @@ -1,29 +1,29 @@ /* Import faunaDB sdk */ -const faunadb = require("faunadb"); +const faunadb = require('faunadb') -const q = faunadb.query; +const q = faunadb.query const client = new faunadb.Client({ secret: process.env.FAUNADB_SERVER_SECRET -}); +}) exports.handler = async (event, context) => { - const data = JSON.parse(event.body); - const id = event.id; - console.log(`Function 'update' invoked. update id: ${id}`); + const data = JSON.parse(event.body) + const id = event.id + console.log(`Function 'update' invoked. update id: ${id}`) return client .query(q.Update(q.Ref(`classes/items/${id}`), { data })) .then(response => { - console.log("success", response); + console.log('success', response) return { statusCode: 200, body: JSON.stringify(response) - }; + } }) .catch(error => { - console.log("error", error); + console.log('error', error) return { statusCode: 400, body: JSON.stringify(error) - }; - }); -}; + } + }) +} diff --git a/src/functions-templates/js/fauna-graphql/.netlify-function-template.js b/src/functions-templates/js/fauna-graphql/.netlify-function-template.js index 9ae35c2199f..e02603821c9 100644 --- a/src/functions-templates/js/fauna-graphql/.netlify-function-template.js +++ b/src/functions-templates/js/fauna-graphql/.netlify-function-template.js @@ -1,16 +1,16 @@ -const execa = require("execa"); +const execa = require('execa') module.exports = { - name: "fauna-graphql", - description: "GraphQL Backend using Fauna DB", + name: 'fauna-graphql', + description: 'GraphQL Backend using Fauna DB', addons: [ { - addonName: "fauna", + addonName: 'fauna', addonDidInstall(fnPath) { - execa.sync(fnPath + "/sync-schema.js", undefined, { + execa.sync(fnPath + '/sync-schema.js', undefined, { env: process.env, - stdio: "inherit" - }); + stdio: 'inherit' + }) } } ] -}; +} diff --git a/src/functions-templates/js/fauna-graphql/fauna-graphql.js b/src/functions-templates/js/fauna-graphql/fauna-graphql.js index 14587470a9b..8ee46ff79bc 100644 --- a/src/functions-templates/js/fauna-graphql/fauna-graphql.js +++ b/src/functions-templates/js/fauna-graphql/fauna-graphql.js @@ -1,10 +1,7 @@ -const { ApolloServer } = require("apollo-server-lambda"); -const { createHttpLink } = require("apollo-link-http"); -const fetch = require("node-fetch"); -const { - introspectSchema, - makeRemoteExecutableSchema -} = require("graphql-tools"); +const { ApolloServer } = require('apollo-server-lambda') +const { createHttpLink } = require('apollo-link-http') +const fetch = require('node-fetch') +const { introspectSchema, makeRemoteExecutableSchema } = require('graphql-tools') exports.handler = async function(event, context) { /** required for Fauna GraphQL auth */ @@ -12,34 +9,34 @@ exports.handler = async function(event, context) { const msg = ` FAUNADB_SERVER_SECRET missing. Did you forget to install the fauna addon or forgot to run inside Netlify Dev? - `; - console.error(msg); + ` + console.error(msg) return { statusCode: 500, body: JSON.stringify({ msg }) - }; + } } const b64encodedSecret = Buffer.from( - process.env.FAUNADB_SERVER_SECRET + ":" // weird but they - ).toString("base64"); - const headers = { Authorization: `Basic ${b64encodedSecret}` }; + process.env.FAUNADB_SERVER_SECRET + ':' // weird but they + ).toString('base64') + const headers = { Authorization: `Basic ${b64encodedSecret}` } /** standard creation of apollo-server executable schema */ const link = createHttpLink({ - uri: "https://graphql.fauna.com/graphql", // modify as you see fit + uri: 'https://graphql.fauna.com/graphql', // modify as you see fit fetch, headers - }); - const schema = await introspectSchema(link); + }) + const schema = await introspectSchema(link) const executableSchema = makeRemoteExecutableSchema({ schema, link - }); + }) const server = new ApolloServer({ schema: executableSchema - }); + }) return new Promise((yay, nay) => { - const cb = (err, args) => (err ? nay(err) : yay(args)); - server.createHandler()(event, context, cb); - }); -}; + const cb = (err, args) => (err ? nay(err) : yay(args)) + server.createHandler()(event, context, cb) + }) +} diff --git a/src/functions-templates/js/fauna-graphql/sync-schema.js b/src/functions-templates/js/fauna-graphql/sync-schema.js index aa146d9871b..67f2538c94f 100644 --- a/src/functions-templates/js/fauna-graphql/sync-schema.js +++ b/src/functions-templates/js/fauna-graphql/sync-schema.js @@ -3,38 +3,32 @@ /* sync GraphQL schema to your FaunaDB account - use with `netlify dev:exec ` */ function createFaunaGraphQL() { if (!process.env.FAUNADB_SERVER_SECRET) { - console.log("No FAUNADB_SERVER_SECRET in environment, skipping DB setup"); + console.log('No FAUNADB_SERVER_SECRET in environment, skipping DB setup') } - console.log("Upload GraphQL Schema!"); + console.log('Upload GraphQL Schema!') - const fetch = require("node-fetch"); - const fs = require("fs"); - const path = require("path"); - var dataString = fs - .readFileSync(path.join(__dirname, "schema.graphql")) - .toString(); // name of your schema file + const fetch = require('node-fetch') + const fs = require('fs') + const path = require('path') + var dataString = fs.readFileSync(path.join(__dirname, 'schema.graphql')).toString() // name of your schema file // encoded authorization header similar to https://www.npmjs.com/package/request#http-authentication - const token = Buffer.from( - process.env.FAUNADB_SERVER_SECRET + ":" - ).toString("base64"); + const token = Buffer.from(process.env.FAUNADB_SERVER_SECRET + ':').toString('base64') var options = { - method: "POST", + method: 'POST', body: dataString, headers: { Authorization: `Basic ${token}` } - }; + } - fetch("https://graphql.fauna.com/import", options) + fetch('https://graphql.fauna.com/import', options) // // uncomment for debugging .then(res => res.text()) .then(body => { - console.log( - "Netlify Functions:Create - `fauna-graphql/sync-schema.js` success!" - ); - console.log(body); + console.log('Netlify Functions:Create - `fauna-graphql/sync-schema.js` success!') + console.log(body) }) - .catch(err => console.error("something wrong happened: ", { err })); + .catch(err => console.error('something wrong happened: ', { err })) } -createFaunaGraphQL(); +createFaunaGraphQL() diff --git a/src/functions-templates/js/google-analytics/.netlify-function-template.js b/src/functions-templates/js/google-analytics/.netlify-function-template.js index 97672eacf26..b16b236c8b1 100644 --- a/src/functions-templates/js/google-analytics/.netlify-function-template.js +++ b/src/functions-templates/js/google-analytics/.netlify-function-template.js @@ -1,4 +1,4 @@ module.exports = { - name: "google-analytics", - description: "Google Analytics: proxy for GA on your domain to avoid adblock" -}; + name: 'google-analytics', + description: 'Google Analytics: proxy for GA on your domain to avoid adblock' +} diff --git a/src/functions-templates/js/google-analytics/google-analytics.js b/src/functions-templates/js/google-analytics/google-analytics.js index cbad15cc745..d68aa54d239 100644 --- a/src/functions-templates/js/google-analytics/google-analytics.js +++ b/src/functions-templates/js/google-analytics/google-analytics.js @@ -1,103 +1,91 @@ // with thanks to https://github.com/codeniko/simple-tracker/blob/master/examples/server-examples/aws-lambda/google-analytics.js -const request = require("request"); -const querystring = require("querystring"); -const uuidv4 = require("uuid/v4"); +const request = require('request') +const querystring = require('querystring') +const uuidv4 = require('uuid/v4') -const GA_ENDPOINT = `https://www.google-analytics.com/collect`; +const GA_ENDPOINT = `https://www.google-analytics.com/collect` // Domains to whitelist. Replace with your own! -const originWhitelist = []; // keep this empty and append domains to whitelist using whiteListDomain() -whitelistDomain("test.com"); -whitelistDomain("nfeld.com"); +const originWhitelist = [] // keep this empty and append domains to whitelist using whiteListDomain() +whitelistDomain('test.com') +whitelistDomain('nfeld.com') function whitelistDomain(domain, addWww = true) { - const prefixes = ["https://", "http://"]; + const prefixes = ['https://', 'http://'] if (addWww) { - prefixes.push("https://www."); - prefixes.push("http://www."); + prefixes.push('https://www.') + prefixes.push('http://www.') } - prefixes.forEach(prefix => originWhitelist.push(prefix + domain)); + prefixes.forEach(prefix => originWhitelist.push(prefix + domain)) } function proxyToGoogleAnalytics(event, done) { // get GA params whether GET or POST request - const params = - event.httpMethod.toUpperCase() === "GET" - ? event.queryStringParameters - : JSON.parse(event.body); - const headers = event.headers || {}; + const params = event.httpMethod.toUpperCase() === 'GET' ? event.queryStringParameters : JSON.parse(event.body) + const headers = event.headers || {} // attach other GA params, required for IP address since client doesn't have access to it. UA and CID can be sent from client - params.uip = headers["x-forwarded-for"] || headers["x-bb-ip"] || ""; // ip override. Look into headers for clients IP address, as opposed to IP address of host running lambda function - params.ua = params.ua || headers["user-agent"] || ""; // user agent override - params.cid = params.cid || uuidv4(); // REQUIRED: use given cid, or generate a new one as last resort. Generating should be avoided because one user can show up in GA multiple times. If user refresh page `n` times, you'll get `n` pageviews logged into GA from "different" users. Client should generate a uuid and store in cookies, local storage, or generate a fingerprint. Check simple-tracker client example + params.uip = headers['x-forwarded-for'] || headers['x-bb-ip'] || '' // ip override. Look into headers for clients IP address, as opposed to IP address of host running lambda function + params.ua = params.ua || headers['user-agent'] || '' // user agent override + params.cid = params.cid || uuidv4() // REQUIRED: use given cid, or generate a new one as last resort. Generating should be avoided because one user can show up in GA multiple times. If user refresh page `n` times, you'll get `n` pageviews logged into GA from "different" users. Client should generate a uuid and store in cookies, local storage, or generate a fingerprint. Check simple-tracker client example - console.info("proxying params:", params); - const qs = querystring.stringify(params); + console.info('proxying params:', params) + const qs = querystring.stringify(params) const reqOptions = { - method: "POST", + method: 'POST', headers: { - "Content-Type": "image/gif" + 'Content-Type': 'image/gif' }, url: GA_ENDPOINT, body: qs - }; + } request(reqOptions, (error, result) => { if (error) { - console.info("googleanalytics error!", error); + console.info('googleanalytics error!', error) } else { - console.info( - "googleanalytics status code", - result.statusCode, - result.statusMessage - ); + console.info('googleanalytics status code', result.statusCode, result.statusMessage) } - }); + }) - done(); + done() } exports.handler = function(event, context, callback) { - const origin = event.headers["origin"] || event.headers["Origin"] || ""; - console.log(`Received ${event.httpMethod} request from, origin: ${origin}`); + const origin = event.headers['origin'] || event.headers['Origin'] || '' + console.log(`Received ${event.httpMethod} request from, origin: ${origin}`) - const isOriginWhitelisted = originWhitelist.indexOf(origin) >= 0; - console.info("is whitelisted?", isOriginWhitelisted); + const isOriginWhitelisted = originWhitelist.indexOf(origin) >= 0 + console.info('is whitelisted?', isOriginWhitelisted) const headers = { //'Access-Control-Allow-Origin': '*', // allow all domains to POST. Use for localhost development only - "Access-Control-Allow-Origin": isOriginWhitelisted - ? origin - : originWhitelist[0], - "Access-Control-Allow-Methods": "GET,POST,OPTIONS", - "Access-Control-Allow-Headers": "Content-Type,Accept" - }; + 'Access-Control-Allow-Origin': isOriginWhitelisted ? origin : originWhitelist[0], + 'Access-Control-Allow-Methods': 'GET,POST,OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type,Accept' + } const done = () => { callback(null, { statusCode: 200, headers, - body: "" - }); - }; + body: '' + }) + } - const httpMethod = event.httpMethod.toUpperCase(); + const httpMethod = event.httpMethod.toUpperCase() - if (event.httpMethod === "OPTIONS") { + if (event.httpMethod === 'OPTIONS') { // CORS (required if you use a different subdomain to host this function, or a different domain entirely) - done(); - } else if ( - (httpMethod === "GET" || httpMethod === "POST") && - isOriginWhitelisted - ) { + done() + } else if ((httpMethod === 'GET' || httpMethod === 'POST') && isOriginWhitelisted) { // allow GET or POST, but only for whitelisted domains - proxyToGoogleAnalytics(event, done); + proxyToGoogleAnalytics(event, done) } else { - callback("Not found"); + callback('Not found') } -}; +} /* Docs on GA endpoint and example params diff --git a/src/functions-templates/js/graphql-gateway/.netlify-function-template.js b/src/functions-templates/js/graphql-gateway/.netlify-function-template.js index fe34af1f346..507bd7c4240 100644 --- a/src/functions-templates/js/graphql-gateway/.netlify-function-template.js +++ b/src/functions-templates/js/graphql-gateway/.netlify-function-template.js @@ -1,5 +1,4 @@ module.exports = { - name: "graphql-gateway", - description: - "Apollo Server Lambda Gateway stitching schemas from other GraphQL Functions!" -}; + name: 'graphql-gateway', + description: 'Apollo Server Lambda Gateway stitching schemas from other GraphQL Functions!' +} diff --git a/src/functions-templates/js/graphql-gateway/example-sibling-function-graphql-1.js b/src/functions-templates/js/graphql-gateway/example-sibling-function-graphql-1.js index 249b6b9d0c2..812762c9610 100644 --- a/src/functions-templates/js/graphql-gateway/example-sibling-function-graphql-1.js +++ b/src/functions-templates/js/graphql-gateway/example-sibling-function-graphql-1.js @@ -1,7 +1,7 @@ // not meant to be run inside the graqhql-gateway function // but just shows a copy-pastable example sibling function // that would work with graphql-gateway -const { ApolloServer, gql } = require("apollo-server-lambda"); +const { ApolloServer, gql } = require('apollo-server-lambda') const typeDefs = gql` type Query { @@ -15,34 +15,34 @@ const typeDefs = gql` name: String! age: Int! } -`; +` const authors = [ - { id: 1, name: "Terry Pratchett", age: 67 }, - { id: 2, name: "Stephen King", age: 71 }, - { id: 3, name: "JK Rowling", age: 53 } -]; + { id: 1, name: 'Terry Pratchett', age: 67 }, + { id: 2, name: 'Stephen King', age: 71 }, + { id: 3, name: 'JK Rowling', age: 53 } +] const resolvers = { Query: { hello: (root, args, context) => { - return "Hello, world!"; + return 'Hello, world!' }, allAuthors: (root, args, context) => { - return authors; + return authors }, author: (root, args, context) => { - return; + return }, authorByName: (root, args, context) => { - return authors.find(x => x.name === args.name) || "NOTFOUND"; + return authors.find(x => x.name === args.name) || 'NOTFOUND' } } -}; +} const server = new ApolloServer({ typeDefs, resolvers -}); +}) -exports.handler = server.createHandler(); +exports.handler = server.createHandler() diff --git a/src/functions-templates/js/graphql-gateway/example-sibling-function-graphql-2.js b/src/functions-templates/js/graphql-gateway/example-sibling-function-graphql-2.js index 7ee3beaf0e1..4ecbd3df671 100644 --- a/src/functions-templates/js/graphql-gateway/example-sibling-function-graphql-2.js +++ b/src/functions-templates/js/graphql-gateway/example-sibling-function-graphql-2.js @@ -1,7 +1,7 @@ // not meant to be run inside the graqhql-gateway function // but just shows a copy-pastable example sibling function // that would work with graphql-gateway -const { ApolloServer, gql } = require("apollo-server-lambda"); +const { ApolloServer, gql } = require('apollo-server-lambda') const typeDefs = gql` type Query { @@ -15,70 +15,70 @@ const typeDefs = gql` title: String! authorName: String! } -`; +` const books = [ { id: 1, title: "The Philosopher's Stone", year: 1997, - authorName: "JK Rowling" + authorName: 'JK Rowling' }, { id: 2, - title: "Pet Sematary", + title: 'Pet Sematary', year: 1983, - authorName: "Stephen King" + authorName: 'Stephen King' }, { id: 3, - title: "Going Postal", + title: 'Going Postal', year: 2004, - authorName: "Terry Pratchett" + authorName: 'Terry Pratchett' }, { id: 4, - title: "Small Gods", + title: 'Small Gods', year: 1992, - authorName: "Terry Pratchett" + authorName: 'Terry Pratchett' }, { id: 5, - title: "Night Watch", + title: 'Night Watch', year: 2002, - authorName: "Terry Pratchett" + authorName: 'Terry Pratchett' }, { id: 6, - title: "The Shining", + title: 'The Shining', year: 1977, - authorName: "Stephen King" + authorName: 'Stephen King' }, { id: 7, - title: "The Deathly Hallows", + title: 'The Deathly Hallows', year: 2007, - authorName: "JK Rowling" + authorName: 'JK Rowling' } -]; +] const resolvers = { Query: { hello: (root, args, context) => { - return "Hello, world!"; + return 'Hello, world!' }, allBooks: (root, args, context) => { - return books; + return books }, book: (root, args, context) => { - return find(books, { id: args.id }); + return find(books, { id: args.id }) } } -}; +} const server = new ApolloServer({ typeDefs, resolvers -}); +}) -exports.handler = server.createHandler(); +exports.handler = server.createHandler() diff --git a/src/functions-templates/js/graphql-gateway/graphql-gateway.js b/src/functions-templates/js/graphql-gateway/graphql-gateway.js index 6451e4a5bce..608edfbaf7d 100644 --- a/src/functions-templates/js/graphql-gateway/graphql-gateway.js +++ b/src/functions-templates/js/graphql-gateway/graphql-gateway.js @@ -5,19 +5,15 @@ * Of course, feel free to modify this gateway to suit your needs. */ -const { - introspectSchema, - makeRemoteExecutableSchema, - mergeSchemas -} = require("graphql-tools"); -const { createHttpLink } = require("apollo-link-http"); -const fetch = require("node-fetch"); -const { ApolloServer } = require("apollo-server-lambda"); +const { introspectSchema, makeRemoteExecutableSchema, mergeSchemas } = require('graphql-tools') +const { createHttpLink } = require('apollo-link-http') +const fetch = require('node-fetch') +const { ApolloServer } = require('apollo-server-lambda') exports.handler = async function(event, context) { - const schema1 = await getSchema("graphql-1"); // other Netlify functions which are graphql lambdas - const schema2 = await getSchema("graphql-2"); // other Netlify functions which are graphql lambdas - const schemas = [schema1, schema2]; + const schema1 = await getSchema('graphql-1') // other Netlify functions which are graphql lambdas + const schema2 = await getSchema('graphql-2') // other Netlify functions which are graphql lambdas + const schemas = [schema1, schema2] /** * resolving -between- schemas @@ -27,8 +23,8 @@ exports.handler = async function(event, context) { extend type Book { author: Author } - `; - schemas.push(linkTypeDefs); + ` + schemas.push(linkTypeDefs) const resolvers = { Book: { author: { @@ -36,39 +32,39 @@ exports.handler = async function(event, context) { resolve(book, args, context, info) { return info.mergeInfo.delegateToSchema({ schema: schema1, - operation: "query", - fieldName: "authorByName", // reuse what's implemented in schema1 + operation: 'query', + fieldName: 'authorByName', // reuse what's implemented in schema1 args: { name: book.authorName }, context, info - }); + }) } } } - }; + } // more docs https://www.apollographql.com/docs/graphql-tools/schema-stitching#api const schema = mergeSchemas({ schemas, resolvers - }); - const server = new ApolloServer({ schema }); + }) + const server = new ApolloServer({ schema }) return new Promise((yay, nay) => { - const cb = (err, args) => (err ? nay(err) : yay(args)); - server.createHandler()(event, context, cb); - }); -}; + const cb = (err, args) => (err ? nay(err) : yay(args)) + server.createHandler()(event, context, cb) + }) +} async function getSchema(endpoint) { // you can't use relative URLs within Netlify Functions so need a base URL // process.env.URL is one of many build env variables: // https://www.netlify.com/docs/continuous-deployment/#build-environment-variables // Netlify Dev only supports URL and DEPLOY URL for now - const uri = process.env.URL + "/.netlify/functions/" + endpoint; - const link = createHttpLink({ uri, fetch }); - const schema = await introspectSchema(link); - const executableSchema = makeRemoteExecutableSchema({ schema, link }); - return executableSchema; + const uri = process.env.URL + '/.netlify/functions/' + endpoint + const link = createHttpLink({ uri, fetch }) + const schema = await introspectSchema(link) + const executableSchema = makeRemoteExecutableSchema({ schema, link }) + return executableSchema } diff --git a/src/functions-templates/js/hasura-event-triggered/.netlify-function-template.js b/src/functions-templates/js/hasura-event-triggered/.netlify-function-template.js index 3701d9703d1..209be529e39 100644 --- a/src/functions-templates/js/hasura-event-triggered/.netlify-function-template.js +++ b/src/functions-templates/js/hasura-event-triggered/.netlify-function-template.js @@ -1,5 +1,4 @@ module.exports = { - name: "hasura-event-triggered", - description: - "Hasura Cleaning: process a Hasura event and fire off a GraphQL mutation with processed text data" -}; + name: 'hasura-event-triggered', + description: 'Hasura Cleaning: process a Hasura event and fire off a GraphQL mutation with processed text data' +} diff --git a/src/functions-templates/js/hasura-event-triggered/hasura-event-triggered.js b/src/functions-templates/js/hasura-event-triggered/hasura-event-triggered.js index 2b98c2222ee..086a9ed4625 100644 --- a/src/functions-templates/js/hasura-event-triggered/hasura-event-triggered.js +++ b/src/functions-templates/js/hasura-event-triggered/hasura-event-triggered.js @@ -1,8 +1,8 @@ // with thanks to https://github.com/vnovick/netlify-function-example/blob/master/functions/bad-words.js -const axios = require("axios"); -const Filter = require("bad-words"); -const filter = new Filter(); -const hgeEndpoint = "https://live-coding-netlify.herokuapp.com"; +const axios = require('axios') +const Filter = require('bad-words') +const filter = new Filter() +const hgeEndpoint = 'https://live-coding-netlify.herokuapp.com' const query = ` mutation verifiedp($id: uuid!, $title: String!, $content: String!) { @@ -13,25 +13,25 @@ mutation verifiedp($id: uuid!, $title: String!, $content: String!) { } } } -`; +` exports.handler = async (event, context) => { - let request; + let request try { - request = JSON.parse(event.body); + request = JSON.parse(event.body) } catch (e) { - return { statusCode: 400, body: "c annot parse hasura event" }; + return { statusCode: 400, body: 'c annot parse hasura event' } } const variables = { id: request.event.data.new.id, title: filter.clean(request.event.data.new.title), content: filter.clean(request.event.data.new.content) - }; + } try { - await axios.post(hgeEndpoint + "/v1alpha1/graphql", { query, variables }); - return { statusCode: 200, body: "success" }; + await axios.post(hgeEndpoint + '/v1alpha1/graphql', { query, variables }) + return { statusCode: 200, body: 'success' } } catch (err) { - return { statusCode: 500, body: err.toString() }; + return { statusCode: 500, body: err.toString() } } -}; +} diff --git a/src/functions-templates/js/hello-world/.netlify-function-template.js b/src/functions-templates/js/hello-world/.netlify-function-template.js index fcb9a19f010..120aeffec14 100644 --- a/src/functions-templates/js/hello-world/.netlify-function-template.js +++ b/src/functions-templates/js/hello-world/.netlify-function-template.js @@ -1,6 +1,5 @@ module.exports = { - name: "hello-world", + name: 'hello-world', priority: 1, - description: - "Basic function that shows async/await usage, and response formatting" -}; + description: 'Basic function that shows async/await usage, and response formatting' +} diff --git a/src/functions-templates/js/hello-world/hello-world.js b/src/functions-templates/js/hello-world/hello-world.js index 98ca5fae0ca..dd1f65483d4 100644 --- a/src/functions-templates/js/hello-world/hello-world.js +++ b/src/functions-templates/js/hello-world/hello-world.js @@ -1,15 +1,15 @@ // Docs on event and context https://www.netlify.com/docs/functions/#the-handler-method exports.handler = async (event, context) => { try { - const subject = event.queryStringParameters.name || "World"; + const subject = event.queryStringParameters.name || 'World' return { statusCode: 200, body: JSON.stringify({ message: `Hello ${subject}` }) // // more keys you can return: // headers: { "headerName": "headerValue", ... }, // isBase64Encoded: true, - }; + } } catch (err) { - return { statusCode: 500, body: err.toString() }; + return { statusCode: 500, body: err.toString() } } -}; +} diff --git a/src/functions-templates/js/identity-signup/.netlify-function-template.js b/src/functions-templates/js/identity-signup/.netlify-function-template.js index c0ce20dc37a..2685f9073cf 100644 --- a/src/functions-templates/js/identity-signup/.netlify-function-template.js +++ b/src/functions-templates/js/identity-signup/.netlify-function-template.js @@ -1,5 +1,4 @@ module.exports = { - name: "identity-signup", - description: - "Identity Signup: Triggered when a new Netlify Identity user confirms. Assigns roles and extra metadata" -}; + name: 'identity-signup', + description: 'Identity Signup: Triggered when a new Netlify Identity user confirms. Assigns roles and extra metadata' +} diff --git a/src/functions-templates/js/identity-signup/identity-signup.js b/src/functions-templates/js/identity-signup/identity-signup.js index a8f0f2ff033..a01b3ba4182 100644 --- a/src/functions-templates/js/identity-signup/identity-signup.js +++ b/src/functions-templates/js/identity-signup/identity-signup.js @@ -6,24 +6,21 @@ // https://www.netlify.com/docs/functions/#identity-and-functions exports.handler = async function(event, context) { - const data = JSON.parse(event.body); - const { user } = data; + const data = JSON.parse(event.body) + const { user } = data const responseBody = { app_metadata: { - roles: - user.email.split("@")[1] === "trust-this-company.com" - ? ["editor"] - : ["visitor"], - my_user_info: "this is some user info" + roles: user.email.split('@')[1] === 'trust-this-company.com' ? ['editor'] : ['visitor'], + my_user_info: 'this is some user info' }, user_metadata: { ...user.user_metadata, // append current user metadata - custom_data_from_function: "hurray this is some extra metadata" + custom_data_from_function: 'hurray this is some extra metadata' } - }; + } return { statusCode: 200, body: JSON.stringify(responseBody) - }; -}; + } +} diff --git a/src/functions-templates/js/node-fetch/.netlify-function-template.js b/src/functions-templates/js/node-fetch/.netlify-function-template.js index a363b9aba5a..69f03594733 100644 --- a/src/functions-templates/js/node-fetch/.netlify-function-template.js +++ b/src/functions-templates/js/node-fetch/.netlify-function-template.js @@ -1,5 +1,4 @@ module.exports = { - name: "node-fetch", - description: - "Fetch function: uses node-fetch to hit an external API without CORS issues" -}; + name: 'node-fetch', + description: 'Fetch function: uses node-fetch to hit an external API without CORS issues' +} diff --git a/src/functions-templates/js/node-fetch/node-fetch.js b/src/functions-templates/js/node-fetch/node-fetch.js index 4693b007da3..d6055444195 100644 --- a/src/functions-templates/js/node-fetch/node-fetch.js +++ b/src/functions-templates/js/node-fetch/node-fetch.js @@ -1,25 +1,25 @@ /* eslint-disable */ -const fetch = require("node-fetch"); +const fetch = require('node-fetch') exports.handler = async function(event, context) { try { - const response = await fetch("https://icanhazdadjoke.com", { - headers: { Accept: "application/json" } - }); + const response = await fetch('https://icanhazdadjoke.com', { + headers: { Accept: 'application/json' } + }) if (!response.ok) { // NOT res.status >= 200 && res.status < 300 - return { statusCode: response.status, body: response.statusText }; + return { statusCode: response.status, body: response.statusText } } - const data = await response.json(); + const data = await response.json() return { statusCode: 200, body: JSON.stringify({ msg: data.joke }) - }; + } } catch (err) { - console.log(err); // output to netlify function log + console.log(err) // output to netlify function log return { statusCode: 500, body: JSON.stringify({ msg: err.message }) // Could be a custom message or object i.e. JSON.stringify(err) - }; + } } -}; +} diff --git a/src/functions-templates/js/oauth-passport/.netlify-function-template.js b/src/functions-templates/js/oauth-passport/.netlify-function-template.js index 58a06653c50..10851b49717 100644 --- a/src/functions-templates/js/oauth-passport/.netlify-function-template.js +++ b/src/functions-templates/js/oauth-passport/.netlify-function-template.js @@ -1,5 +1,4 @@ module.exports = { - name: "oauth-passport", - description: - "oauth-passport: template for Oauth workflow using Passport + Express.js" -}; + name: 'oauth-passport', + description: 'oauth-passport: template for Oauth workflow using Passport + Express.js' +} diff --git a/src/functions-templates/js/oauth-passport/oauth-passport.js b/src/functions-templates/js/oauth-passport/oauth-passport.js index b7bc7d547cf..2a7dcfef28f 100644 --- a/src/functions-templates/js/oauth-passport/oauth-passport.js +++ b/src/functions-templates/js/oauth-passport/oauth-passport.js @@ -1,42 +1,35 @@ // details: https://markus.oberlehner.net/blog/implementing-an-authentication-flow-with-passport-and-netlify-functions/ -const bodyParser = require("body-parser"); -const cookieParser = require("cookie-parser"); -const express = require("express"); -const passport = require("passport"); -const serverless = require("serverless-http"); +const bodyParser = require('body-parser') +const cookieParser = require('cookie-parser') +const express = require('express') +const passport = require('passport') +const serverless = require('serverless-http') -require("./utils/auth"); +require('./utils/auth') -const { COOKIE_SECURE, ENDPOINT } = require("./utils/config"); +const { COOKIE_SECURE, ENDPOINT } = require('./utils/config') -const app = express(); +const app = express() -app.use(bodyParser.urlencoded({ extended: true })); -app.use(bodyParser.json()); -app.use(cookieParser()); -app.use(passport.initialize()); +app.use(bodyParser.urlencoded({ extended: true })) +app.use(bodyParser.json()) +app.use(cookieParser()) +app.use(passport.initialize()) const handleCallback = () => (req, res) => { - res - .cookie("jwt", req.user.jwt, { httpOnly: true, COOKIE_SECURE }) - .redirect("/"); -}; + res.cookie('jwt', req.user.jwt, { httpOnly: true, COOKIE_SECURE }).redirect('/') +} -app.get( - `${ENDPOINT}/auth/github`, - passport.authenticate("github", { session: false }) -); +app.get(`${ENDPOINT}/auth/github`, passport.authenticate('github', { session: false })) app.get( `${ENDPOINT}/auth/github/callback`, - passport.authenticate("github", { failureRedirect: "/", session: false }), + passport.authenticate('github', { failureRedirect: '/', session: false }), handleCallback() -); +) -app.get( - `${ENDPOINT}/auth/status`, - passport.authenticate("jwt", { session: false }), - (req, res) => res.json({ email: req.user.email }) -); +app.get(`${ENDPOINT}/auth/status`, passport.authenticate('jwt', { session: false }), (req, res) => + res.json({ email: req.user.email }) +) -module.exports.handler = serverless(app); +module.exports.handler = serverless(app) diff --git a/src/functions-templates/js/oauth-passport/utils/auth.js b/src/functions-templates/js/oauth-passport/utils/auth.js index cb7d0ccaab7..a8c839257cc 100644 --- a/src/functions-templates/js/oauth-passport/utils/auth.js +++ b/src/functions-templates/js/oauth-passport/utils/auth.js @@ -15,7 +15,7 @@ passport.use( clientID: GITHUB_CLIENT_ID, clientSecret: GITHUB_CLIENT_SECRET, callbackURL: `${BASE_URL}${ENDPOINT}/auth/github/callback`, - scope: ['user:email'], + scope: ['user:email'] }, async (accessToken, refreshToken, profile, done) => { try { @@ -28,8 +28,8 @@ passport.use( } catch (error) { return done(error) } - }, - ), + } + ) ) passport.use( @@ -39,7 +39,7 @@ passport.use( if (!req.cookies) throw new Error('Missing cookie-parser middleware') return req.cookies.jwt }, - secretOrKey: SECRET, + secretOrKey: SECRET }, async ({ user: { email } }, done) => { try { @@ -51,6 +51,6 @@ passport.use( } catch (error) { return done(error) } - }, - ), + } + ) ) diff --git a/src/functions-templates/js/protected-function/.netlify-function-template.js b/src/functions-templates/js/protected-function/.netlify-function-template.js index b5ca416ceaa..e674de9c50d 100644 --- a/src/functions-templates/js/protected-function/.netlify-function-template.js +++ b/src/functions-templates/js/protected-function/.netlify-function-template.js @@ -1,4 +1,4 @@ module.exports = { - name: "protected-function", - description: "Function protected Netlify Identity authentication" -}; + name: 'protected-function', + description: 'Function protected Netlify Identity authentication' +} diff --git a/src/functions-templates/js/protected-function/protected-function.js b/src/functions-templates/js/protected-function/protected-function.js index 7c96c71b7f3..3770737fc35 100644 --- a/src/functions-templates/js/protected-function/protected-function.js +++ b/src/functions-templates/js/protected-function/protected-function.js @@ -1,23 +1,23 @@ exports.handler = async (event, context) => { - console.log("protected function!"); + console.log('protected function!') // Reading the context.clientContext will give us the current user - const claims = context.clientContext && context.clientContext.user; - console.log("user claims", claims); + const claims = context.clientContext && context.clientContext.user + console.log('user claims', claims) if (!claims) { - console.log("No claims! Begone!"); + console.log('No claims! Begone!') return { statusCode: 401, body: JSON.stringify({ - data: "NOT ALLOWED" + data: 'NOT ALLOWED' }) - }; + } } return { statusCode: 200, body: JSON.stringify({ - data: "auth true" + data: 'auth true' }) - }; -}; + } +} diff --git a/src/functions-templates/js/send-email/.netlify-function-template.js b/src/functions-templates/js/send-email/.netlify-function-template.js index 0b5e9247b94..fa4686af5b9 100644 --- a/src/functions-templates/js/send-email/.netlify-function-template.js +++ b/src/functions-templates/js/send-email/.netlify-function-template.js @@ -1,4 +1,4 @@ module.exports = { - name: "send-email", + name: 'send-email', description: "Send Email: Send email with no SMTP server via 'sendmail' pkg" -}; +} diff --git a/src/functions-templates/js/send-email/send-email.js b/src/functions-templates/js/send-email/send-email.js index 80a4d19901f..3b4e6a3f8d6 100644 --- a/src/functions-templates/js/send-email/send-email.js +++ b/src/functions-templates/js/send-email/send-email.js @@ -1,42 +1,42 @@ // with thanks to https://github.com/Urigo/graphql-modules/blob/8cb2fd7d9938a856f83e4eee2081384533771904/website/lambda/contact.js -const sendMail = require("sendmail")(); -const { validateEmail, validateLength } = require("./validations"); +const sendMail = require('sendmail')() +const { validateEmail, validateLength } = require('./validations') exports.handler = (event, context, callback) => { if (!process.env.CONTACT_EMAIL) { return callback(null, { statusCode: 500, - body: "process.env.CONTACT_EMAIL must be defined" - }); + body: 'process.env.CONTACT_EMAIL must be defined' + }) } - const body = JSON.parse(event.body); + const body = JSON.parse(event.body) try { - validateLength("body.name", body.name, 3, 50); + validateLength('body.name', body.name, 3, 50) } catch (e) { return callback(null, { statusCode: 403, body: e.message - }); + }) } try { - validateEmail("body.email", body.email); + validateEmail('body.email', body.email) } catch (e) { return callback(null, { statusCode: 403, body: e.message - }); + }) } try { - validateLength("body.details", body.details, 10, 1000); + validateLength('body.details', body.details, 10, 1000) } catch (e) { return callback(null, { statusCode: 403, body: e.message - }); + }) } const descriptor = { @@ -44,19 +44,19 @@ exports.handler = (event, context, callback) => { to: process.env.CONTACT_EMAIL, subject: `${body.name} sent you a message from gql-modules.com`, text: body.details - }; + } sendMail(descriptor, e => { if (e) { callback(null, { statusCode: 500, body: e.message - }); + }) } else { callback(null, { statusCode: 200, - body: "" - }); + body: '' + }) } - }); -}; + }) +} diff --git a/src/functions-templates/js/send-email/validations.js b/src/functions-templates/js/send-email/validations.js index 6c52428c777..e08f04e913e 100644 --- a/src/functions-templates/js/send-email/validations.js +++ b/src/functions-templates/js/send-email/validations.js @@ -1,35 +1,35 @@ exports.validateEmail = (ctx, str) => { - if (typeof str !== "string" && !(str instanceof String)) { - throw TypeError(`${ctx} must be a string`); + if (typeof str !== 'string' && !(str instanceof String)) { + throw TypeError(`${ctx} must be a string`) } - exports.validateLength(ctx, str, 5, 30); + exports.validateLength(ctx, str, 5, 30) if (!/^[\w.-]+@[\w.-]+\.\w+$/.test(str)) { - throw TypeError(`${ctx} is not an email address`); + throw TypeError(`${ctx} is not an email address`) } -}; +} exports.validateLength = (ctx, str, ...args) => { - let min, max; + let min, max if (args.length === 1) { - min = 0; - max = args[0]; + min = 0 + max = args[0] } else { - min = args[0]; - max = args[1]; + min = args[0] + max = args[1] } - if (typeof str !== "string" && !(str instanceof String)) { - throw TypeError(`${ctx} must be a string`); + if (typeof str !== 'string' && !(str instanceof String)) { + throw TypeError(`${ctx} must be a string`) } if (str.length < min) { - throw TypeError(`${ctx} must be at least ${min} chars long`); + throw TypeError(`${ctx} must be at least ${min} chars long`) } if (str.length > max) { - throw TypeError(`${ctx} must contain ${max} chars at most`); + throw TypeError(`${ctx} must contain ${max} chars at most`) } -}; +} diff --git a/src/functions-templates/js/serverless-ssr/.netlify-function-template.js b/src/functions-templates/js/serverless-ssr/.netlify-function-template.js index e7092cf186b..ec767802c3e 100644 --- a/src/functions-templates/js/serverless-ssr/.netlify-function-template.js +++ b/src/functions-templates/js/serverless-ssr/.netlify-function-template.js @@ -1,4 +1,4 @@ module.exports = { - name: "serverless-ssr", - description: "Dynamic serverside rendering via functions" -}; + name: 'serverless-ssr', + description: 'Dynamic serverside rendering via functions' +} diff --git a/src/functions-templates/js/serverless-ssr/app/index.js b/src/functions-templates/js/serverless-ssr/app/index.js index 952511cb62f..5e2b0ad1da5 100644 --- a/src/functions-templates/js/serverless-ssr/app/index.js +++ b/src/functions-templates/js/serverless-ssr/app/index.js @@ -1,26 +1,23 @@ /* Express App */ -const express = require("express"); -const cors = require("cors"); -const morgan = require("morgan"); -const bodyParser = require("body-parser"); -const compression = require("compression"); +const express = require('express') +const cors = require('cors') +const morgan = require('morgan') +const bodyParser = require('body-parser') +const compression = require('compression') /* My express App */ module.exports = function expressApp(functionName) { - const app = express(); - const router = express.Router(); + const app = express() + const router = express.Router() // gzip responses - router.use(compression()); + router.use(compression()) // Set router base path for local dev - const routerBasePath = - process.env.NODE_ENV === "dev" - ? `/${functionName}` - : `/.netlify/functions/${functionName}/`; + const routerBasePath = process.env.NODE_ENV === 'dev' ? `/${functionName}` : `/.netlify/functions/${functionName}/` /* define routes */ - router.get("/", (req, res) => { + router.get('/', (req, res) => { const html = ` @@ -64,55 +61,55 @@ module.exports = function expressApp(functionName) { - `; - res.send(html); - }); + ` + res.send(html) + }) - router.get("/users", (req, res) => { + router.get('/users', (req, res) => { res.json({ users: [ { - name: "steve" + name: 'steve' }, { - name: "joe" + name: 'joe' } ] - }); - }); + }) + }) - router.get("/hello/", function(req, res) { - res.send("hello world"); - }); + router.get('/hello/', function(req, res) { + res.send('hello world') + }) // Attach logger - app.use(morgan(customLogger)); + app.use(morgan(customLogger)) // Setup routes - app.use(routerBasePath, router); + app.use(routerBasePath, router) // Apply express middlewares - router.use(cors()); - router.use(bodyParser.json()); - router.use(bodyParser.urlencoded({ extended: true })); + router.use(cors()) + router.use(bodyParser.json()) + router.use(bodyParser.urlencoded({ extended: true })) - return app; -}; + return app +} function customLogger(tokens, req, res) { const log = [ tokens.method(req, res), tokens.url(req, res), tokens.status(req, res), - tokens.res(req, res, "content-length"), - "-", - tokens["response-time"](req, res), - "ms" - ].join(" "); + tokens.res(req, res, 'content-length'), + '-', + tokens['response-time'](req, res), + 'ms' + ].join(' ') - if (process.env.NODE_ENV !== "dev") { + if (process.env.NODE_ENV !== 'dev') { // Log only in AWS context to get back function logs - console.log(log); + console.log(log) } - return log; + return log } diff --git a/src/functions-templates/js/serverless-ssr/serverless-http.js b/src/functions-templates/js/serverless-ssr/serverless-http.js index cb4800d246e..bff11100f5d 100644 --- a/src/functions-templates/js/serverless-ssr/serverless-http.js +++ b/src/functions-templates/js/serverless-ssr/serverless-http.js @@ -1,12 +1,12 @@ // for a full working demo check https://express-via-functions.netlify.com/.netlify/functions/serverless-http -const serverless = require("serverless-http"); -const expressApp = require("./app"); +const serverless = require('serverless-http') +const expressApp = require('./app') // We need to define our function name for express routes to set the correct base path -const functionName = "serverless-http"; +const functionName = 'serverless-http' // Initialize express app -const app = expressApp(functionName); +const app = expressApp(functionName) // Export lambda handler -exports.handler = serverless(app); +exports.handler = serverless(app) diff --git a/src/functions-templates/js/serverless-ssr/serverless-ssr.js b/src/functions-templates/js/serverless-ssr/serverless-ssr.js index cb4800d246e..bff11100f5d 100644 --- a/src/functions-templates/js/serverless-ssr/serverless-ssr.js +++ b/src/functions-templates/js/serverless-ssr/serverless-ssr.js @@ -1,12 +1,12 @@ // for a full working demo check https://express-via-functions.netlify.com/.netlify/functions/serverless-http -const serverless = require("serverless-http"); -const expressApp = require("./app"); +const serverless = require('serverless-http') +const expressApp = require('./app') // We need to define our function name for express routes to set the correct base path -const functionName = "serverless-http"; +const functionName = 'serverless-http' // Initialize express app -const app = expressApp(functionName); +const app = expressApp(functionName) // Export lambda handler -exports.handler = serverless(app); +exports.handler = serverless(app) diff --git a/src/functions-templates/js/set-cookie/.netlify-function-template.js b/src/functions-templates/js/set-cookie/.netlify-function-template.js index c0a9498127a..51b15478014 100644 --- a/src/functions-templates/js/set-cookie/.netlify-function-template.js +++ b/src/functions-templates/js/set-cookie/.netlify-function-template.js @@ -1,4 +1,4 @@ module.exports = { - name: "set-cookie", - description: "Set a cookie alongside your function" -}; + name: 'set-cookie', + description: 'Set a cookie alongside your function' +} diff --git a/src/functions-templates/js/set-cookie/set-cookie.js b/src/functions-templates/js/set-cookie/set-cookie.js index 77b6022352b..eabce5766c7 100644 --- a/src/functions-templates/js/set-cookie/set-cookie.js +++ b/src/functions-templates/js/set-cookie/set-cookie.js @@ -1,16 +1,16 @@ -const cookie = require("cookie"); +const cookie = require('cookie') exports.handler = async (event, context) => { - var hour = 3600000; - var twoWeeks = 14 * 24 * hour; - const myCookie = cookie.serialize("my_cookie", "lolHi", { + var hour = 3600000 + var twoWeeks = 14 * 24 * hour + const myCookie = cookie.serialize('my_cookie', 'lolHi', { secure: true, httpOnly: true, - path: "/", + path: '/', maxAge: twoWeeks - }); + }) - const redirectUrl = "https://google.com"; + const redirectUrl = 'https://google.com' // Do redirects via html const html = ` @@ -27,15 +27,15 @@ exports.handler = async (event, context) => { window.location.href = ${JSON.stringify(redirectUrl)} }, 0) - `; + ` return { statusCode: 200, headers: { - "Set-Cookie": myCookie, - "Cache-Control": "no-cache", - "Content-Type": "text/html" + 'Set-Cookie': myCookie, + 'Cache-Control': 'no-cache', + 'Content-Type': 'text/html' }, body: html - }; -}; + } +} diff --git a/src/functions-templates/js/slack-rate-limit/.netlify-function-template.js b/src/functions-templates/js/slack-rate-limit/.netlify-function-template.js index 49aef251ba2..c8f004b3b58 100644 --- a/src/functions-templates/js/slack-rate-limit/.netlify-function-template.js +++ b/src/functions-templates/js/slack-rate-limit/.netlify-function-template.js @@ -1,5 +1,4 @@ module.exports = { - name: "slack-rate-limit", - description: - "Slack Rate-limit: post to Slack, at most once an hour, using Netlify Identity metadata" -}; + name: 'slack-rate-limit', + description: 'Slack Rate-limit: post to Slack, at most once an hour, using Netlify Identity metadata' +} diff --git a/src/functions-templates/js/slack-rate-limit/slack-rate-limit.js b/src/functions-templates/js/slack-rate-limit/slack-rate-limit.js index 1484c1c3852..0ce48e2aa39 100644 --- a/src/functions-templates/js/slack-rate-limit/slack-rate-limit.js +++ b/src/functions-templates/js/slack-rate-limit/slack-rate-limit.js @@ -1,50 +1,50 @@ // code walkthrough: https://www.netlify.com/blog/2018/03/29/jamstack-architecture-on-netlify-how-identity-and-functions-work-together/#updating-user-data-with-the-identity-api // demo repo: https://github.com/biilmann/testing-slack-tutorial/tree/v3-one-message-an-hour // note: requires SLACK_WEBHOOK_URL environment variable -const slackURL = process.env.SLACK_WEBHOOK_URL; -const fetch = require("node-fetch"); +const slackURL = process.env.SLACK_WEBHOOK_URL +const fetch = require('node-fetch') class IdentityAPI { constructor(apiURL, token) { - this.apiURL = apiURL; - this.token = token; + this.apiURL = apiURL + this.token = token } headers(headers = {}) { return { - "Content-Type": "application/json", + 'Content-Type': 'application/json', Authorization: `Bearer ${this.token}`, ...headers - }; + } } parseJsonResponse(response) { return response.json().then(json => { if (!response.ok) { - return Promise.reject({ status: response.status, json }); + return Promise.reject({ status: response.status, json }) } - return json; - }); + return json + }) } request(path, options = {}) { - const headers = this.headers(options.headers || {}); + const headers = this.headers(options.headers || {}) return fetch(this.apiURL + path, { ...options, headers }).then(response => { - const contentType = response.headers.get("Content-Type"); + const contentType = response.headers.get('Content-Type') if (contentType && contentType.match(/json/)) { - return this.parseJsonResponse(response); + return this.parseJsonResponse(response) } if (!response.ok) { return response.text().then(data => { - return Promise.reject({ stauts: response.status, data }); - }); + return Promise.reject({ stauts: response.status, data }) + }) } return response.text().then(data => { - data; - }); - }); + data + }) + }) } } @@ -52,57 +52,55 @@ class IdentityAPI { Fetch a user from GoTrue via id */ function fetchUser(identity, id) { - const api = new IdentityAPI(identity.url, identity.token); - return api.request(`/admin/users/${id}`); + const api = new IdentityAPI(identity.url, identity.token) + return api.request(`/admin/users/${id}`) } /* Update the app_metadata of a user */ function updateUser(identity, user, app_metadata) { - const api = new IdentityAPI(identity.url, identity.token); - const new_app_metadata = { ...user.app_metadata, ...app_metadata }; + const api = new IdentityAPI(identity.url, identity.token) + const new_app_metadata = { ...user.app_metadata, ...app_metadata } return api.request(`/admin/users/${user.id}`, { - method: "PUT", + method: 'PUT', body: JSON.stringify({ app_metadata: new_app_metadata }) - }); + }) } -const oneHour = 60 * 60 * 1000; +const oneHour = 60 * 60 * 1000 export function handler(event, context, callback) { - if (event.httpMethod !== "POST") { + if (event.httpMethod !== 'POST') { return callback(null, { statusCode: 410, - body: "Unsupported Request Method" - }); + body: 'Unsupported Request Method' + }) } - const claims = context.clientContext && context.clientContext.user; + const claims = context.clientContext && context.clientContext.user if (!claims) { return callback(null, { statusCode: 401, - body: "You must be signed in to call this function" - }); + body: 'You must be signed in to call this function' + }) } fetchUser(context.clientContext.identity, claims.sub).then(user => { - const lastMessage = new Date( - user.app_metadata.last_message_at || 0 - ).getTime(); - const cutOff = new Date().getTime() - oneHour; + const lastMessage = new Date(user.app_metadata.last_message_at || 0).getTime() + const cutOff = new Date().getTime() - oneHour if (lastMessage > cutOff) { return callback(null, { statusCode: 401, - body: "Only one message an hour allowed" - }); + body: 'Only one message an hour allowed' + }) } try { - const payload = JSON.parse(event.body); + const payload = JSON.parse(event.body) fetch(slackURL, { - method: "POST", + method: 'POST', body: JSON.stringify({ text: payload.text, attachments: [{ text: `From ${user.email}` }] @@ -114,16 +112,16 @@ export function handler(event, context, callback) { }) ) .then(() => { - callback(null, { statusCode: 204 }); + callback(null, { statusCode: 204 }) }) .catch(err => { callback(null, { statusCode: 500, - body: "Internal Server Error: " + e - }); - }); + body: 'Internal Server Error: ' + e + }) + }) } catch (e) { - callback(null, { statusCode: 500, body: "Internal Server Error: " + e }); + callback(null, { statusCode: 500, body: 'Internal Server Error: ' + e }) } - }); + }) } diff --git a/src/functions-templates/js/stripe-charge/.netlify-function-template.js b/src/functions-templates/js/stripe-charge/.netlify-function-template.js index 3cf418f9457..8fc57757838 100644 --- a/src/functions-templates/js/stripe-charge/.netlify-function-template.js +++ b/src/functions-templates/js/stripe-charge/.netlify-function-template.js @@ -1,31 +1,27 @@ -const chalk = require("chalk"); +const chalk = require('chalk') module.exports = { - name: "stripe-charge", - description: "Stripe Charge: Charge a user with Stripe", + name: 'stripe-charge', + description: 'Stripe Charge: Charge a user with Stripe', async onComplete() { - console.log( - `${chalk.yellow("stripe-charge")} function created from template!` - ); + console.log(`${chalk.yellow('stripe-charge')} function created from template!`) if (!process.env.STRIPE_SECRET_KEY) { console.log( `note this function requires ${chalk.yellow( - "STRIPE_SECRET_KEY" + 'STRIPE_SECRET_KEY' )} build environment variable set in your Netlify Site.` - ); - let siteData = { name: "YOURSITENAMEHERE" }; + ) + let siteData = { name: 'YOURSITENAMEHERE' } try { siteData = await this.netlify.api.getSite({ siteId: this.netlify.site.id - }); + }) } catch (e) { // silent error, not important } console.log( - `Set it at: https://app.netlify.com/sites/${ - siteData.name - }/settings/deploys#environment-variables (must have CD setup)` - ); + `Set it at: https://app.netlify.com/sites/${siteData.name}/settings/deploys#environment-variables (must have CD setup)` + ) } } -}; +} diff --git a/src/functions-templates/js/stripe-charge/stripe-charge.js b/src/functions-templates/js/stripe-charge/stripe-charge.js index 64fa6258dbd..055c0daa23b 100644 --- a/src/functions-templates/js/stripe-charge/stripe-charge.js +++ b/src/functions-templates/js/stripe-charge/stripe-charge.js @@ -1,42 +1,42 @@ // with thanks https://github.com/alexmacarthur/netlify-lambda-function-example/blob/68a0cdc05e201d68fe80b0926b0af7ff88f15802/lambda-src/purchase.js -const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY); +const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY) -const statusCode = 200; +const statusCode = 200 const headers = { - "Access-Control-Allow-Origin": "*", - "Access-Control-Allow-Headers": "Content-Type" -}; + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'Content-Type' +} exports.handler = function(event, context, callback) { //-- We only care to do anything if this is our POST request. - if (event.httpMethod !== "POST" || !event.body) { + if (event.httpMethod !== 'POST' || !event.body) { callback(null, { statusCode, headers, - body: "" - }); + body: '' + }) } //-- Parse the body contents into an object. - const data = JSON.parse(event.body); + const data = JSON.parse(event.body) //-- Make sure we have all required data. Otherwise, escape. if (!data.token || !data.amount || !data.idempotency_key) { - console.error("Required information is missing."); + console.error('Required information is missing.') callback(null, { statusCode, headers, - body: JSON.stringify({ status: "missing-information" }) - }); + body: JSON.stringify({ status: 'missing-information' }) + }) - return; + return } stripe.charges.create( { - currency: "usd", + currency: 'usd', amount: data.amount, source: data.token.id, receipt_email: data.token.email, @@ -47,19 +47,16 @@ exports.handler = function(event, context, callback) { }, (err, charge) => { if (err !== null) { - console.log(err); + console.log(err) } - let status = - charge === null || charge.status !== "succeeded" - ? "failed" - : charge.status; + let status = charge === null || charge.status !== 'succeeded' ? 'failed' : charge.status callback(null, { statusCode, headers, body: JSON.stringify({ status }) - }); + }) } - ); -}; + ) +} diff --git a/src/functions-templates/js/stripe-subscription/.netlify-function-template.js b/src/functions-templates/js/stripe-subscription/.netlify-function-template.js index 9c8d13233b3..25088da5ab1 100644 --- a/src/functions-templates/js/stripe-subscription/.netlify-function-template.js +++ b/src/functions-templates/js/stripe-subscription/.netlify-function-template.js @@ -1,31 +1,27 @@ -const chalk = require("chalk"); +const chalk = require('chalk') module.exports = { - name: "stripe-subscription", - description: "Stripe subscription: Create a subscription with Stripe", + name: 'stripe-subscription', + description: 'Stripe subscription: Create a subscription with Stripe', async onComplete() { - console.log( - `${chalk.yellow("stripe-subscription")} function created from template!` - ); + console.log(`${chalk.yellow('stripe-subscription')} function created from template!`) if (!process.env.STRIPE_SECRET_KEY) { console.log( `note this function requires ${chalk.yellow( - "STRIPE_SECRET_KEY" + 'STRIPE_SECRET_KEY' )} build environment variable set in your Netlify Site.` - ); - let siteData = { name: "YOURSITENAMEHERE" }; + ) + let siteData = { name: 'YOURSITENAMEHERE' } try { siteData = await this.netlify.api.getSite({ siteId: this.netlify.site.id - }); + }) } catch (e) { // silent error, not important } console.log( - `Set it at: https://app.netlify.com/sites/${ - siteData.name - }/settings/deploys#environment-variables (must have CD setup)` - ); + `Set it at: https://app.netlify.com/sites/${siteData.name}/settings/deploys#environment-variables (must have CD setup)` + ) } } -}; +} diff --git a/src/functions-templates/js/stripe-subscription/stripe-subscription.js b/src/functions-templates/js/stripe-subscription/stripe-subscription.js index 020842f71b9..b05b6fa6314 100644 --- a/src/functions-templates/js/stripe-subscription/stripe-subscription.js +++ b/src/functions-templates/js/stripe-subscription/stripe-subscription.js @@ -1,58 +1,50 @@ // with thanks https://github.com/LukeMwila/stripe-subscriptions-backend/blob/master/stripe-api/index.ts -const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY); +const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY) const respond = (fulfillmentText: any): any => { return { statusCode: 200, body: JSON.stringify(fulfillmentText), headers: { - "Access-Control-Allow-Credentials": true, - "Access-Control-Allow-Origin": "*", - "Content-Type": "application/json" + 'Access-Control-Allow-Credentials': true, + 'Access-Control-Allow-Origin': '*', + 'Content-Type': 'application/json' } - }; -}; + } +} exports.handler = async function(event, context) { try { - const incoming = JSON.parse(event.body); - const { stripeToken, email, productPlan } = incoming; + const incoming = JSON.parse(event.body) + const { stripeToken, email, productPlan } = incoming } catch (err) { - console.error(`error with parsing function parameters: `, err); + console.error(`error with parsing function parameters: `, err) return { statusCode: 400, body: JSON.stringify(err) - }; + } } try { - const data = await createCustomerAndSubscribeToPlan( - stripeToken, - email, - productPlan - ); - return respond(data); + const data = await createCustomerAndSubscribeToPlan(stripeToken, email, productPlan) + return respond(data) } catch (err) { - return respond(err); + return respond(err) } -}; +} -async function createCustomerAndSubscribeToPlan( - stripeToken: string, - email: string, - productPlan: string -) { +async function createCustomerAndSubscribeToPlan(stripeToken: string, email: string, productPlan: string) { // create a customer const customer = await stripe.customers.create({ email: email, source: stripeToken - }); + }) // retrieve created customer id to add customer to subscription plan - const customerId = customer.id; + const customerId = customer.id // create a subscription for the newly created customer const subscription = await stripe.subscriptions.create({ customer: customerId, items: [{ plan: productPlan }] - }); - return subscription; + }) + return subscription } diff --git a/src/functions-templates/js/submission-created/.netlify-function-template.js b/src/functions-templates/js/submission-created/.netlify-function-template.js index 275090099f5..86f83119d62 100644 --- a/src/functions-templates/js/submission-created/.netlify-function-template.js +++ b/src/functions-templates/js/submission-created/.netlify-function-template.js @@ -1,4 +1,4 @@ module.exports = { name: 'submission-created', - description: 'submission-created: template for event triggered function when a new Netlify Form is submitted', + description: 'submission-created: template for event triggered function when a new Netlify Form is submitted' } diff --git a/src/functions-templates/js/submission-created/submission-created.js b/src/functions-templates/js/submission-created/submission-created.js index 04f1366be8c..6ee25072c11 100644 --- a/src/functions-templates/js/submission-created/submission-created.js +++ b/src/functions-templates/js/submission-created/submission-created.js @@ -6,20 +6,20 @@ // // details in https://css-tricks.com/using-netlify-forms-and-netlify-functions-to-build-an-email-sign-up-widget const fetch = require('node-fetch') const { EMAIL_TOKEN } = process.env -exports.handler = async (event) => { +exports.handler = async event => { const email = JSON.parse(event.body).payload.email console.log(`Recieved a submission: ${email}`) return fetch('https://api.buttondown.email/v1/subscribers', { method: 'POST', headers: { Authorization: `Token ${EMAIL_TOKEN}`, - 'Content-Type': 'application/json', + 'Content-Type': 'application/json' }, - body: JSON.stringify({ email }), + body: JSON.stringify({ email }) }) - .then((response) => response.json()) - .then((data) => { + .then(response => response.json()) + .then(data => { console.log(`Submitted to Buttondown:\n ${data}`) }) - .catch((error) => ({ statusCode: 422, body: String(error) })) + .catch(error => ({ statusCode: 422, body: String(error) })) } diff --git a/src/functions-templates/js/token-hider/.netlify-function-template.js b/src/functions-templates/js/token-hider/.netlify-function-template.js index 13e9fd7860a..fd532d191aa 100644 --- a/src/functions-templates/js/token-hider/.netlify-function-template.js +++ b/src/functions-templates/js/token-hider/.netlify-function-template.js @@ -1,34 +1,28 @@ -const chalk = require("chalk"); +const chalk = require('chalk') module.exports = { - name: "token-hider", - description: "Token Hider: access APIs without exposing your API keys", + name: 'token-hider', + description: 'Token Hider: access APIs without exposing your API keys', async onComplete() { - console.log( - `${chalk.yellow("token-hider")} function created from template!` - ); + console.log(`${chalk.yellow('token-hider')} function created from template!`) if (!process.env.API_URL || !process.env.API_TOKEN) { console.log( - `note this function requires ${chalk.yellow( - "API_URL" - )} and ${chalk.yellow( - "API_TOKEN" + `note this function requires ${chalk.yellow('API_URL')} and ${chalk.yellow( + 'API_TOKEN' )} build environment variables set in your Netlify Site.` - ); + ) - let siteData = { name: "YOURSITENAMEHERE" }; + let siteData = { name: 'YOURSITENAMEHERE' } try { siteData = await this.netlify.api.getSite({ siteId: this.netlify.site.id - }); + }) } catch (e) { // silent error, not important } console.log( - `Set them at: https://app.netlify.com/sites/${ - siteData.name - }/settings/deploys#environment-variables (must have CD setup)` - ); + `Set them at: https://app.netlify.com/sites/${siteData.name}/settings/deploys#environment-variables (must have CD setup)` + ) } } -}; +} diff --git a/src/functions-templates/js/token-hider/token-hider.js b/src/functions-templates/js/token-hider/token-hider.js index 39878e1ba34..f0eb394b2b6 100644 --- a/src/functions-templates/js/token-hider/token-hider.js +++ b/src/functions-templates/js/token-hider/token-hider.js @@ -1,17 +1,17 @@ -const axios = require("axios") -const qs = require("qs") +const axios = require('axios') +const qs = require('qs') exports.handler = async function(event, context) { // apply our function to the queryStringParameters and assign it to a variable const API_PARAMS = qs.stringify(event.queryStringParameters) // Get env var values defined in our Netlify site UI - + // TODO: customize your URL and API keys set in the Netlify Dashboard // this is secret too, your frontend won't see this - const { API_SECRET = "shiba" } = process.env + const { API_SECRET = 'shiba' } = process.env const URL = `https://dog.ceo/api/breed/${API_SECRET}/images` - console.log("Constructed URL is ...", URL) + console.log('Constructed URL is ...', URL) try { const { data } = await axios.get(URL) @@ -20,13 +20,13 @@ exports.handler = async function(event, context) { // axios.post('/user', { firstName: 'Fred' }) return { statusCode: 200, - body: JSON.stringify(data), + body: JSON.stringify(data) } } catch (error) { const { status, statusText, headers, data } = error.response return { statusCode: error.response.status, - body: JSON.stringify({ status, statusText, headers, data }), + body: JSON.stringify({ status, statusText, headers, data }) } } } diff --git a/src/functions-templates/js/url-shortener/.netlify-function-template.js b/src/functions-templates/js/url-shortener/.netlify-function-template.js index 9821b651ae0..3260e6160b9 100644 --- a/src/functions-templates/js/url-shortener/.netlify-function-template.js +++ b/src/functions-templates/js/url-shortener/.netlify-function-template.js @@ -1,34 +1,28 @@ -const chalk = require("chalk"); +const chalk = require('chalk') module.exports = { - name: "url-shortener", - description: "URL Shortener: simple URL shortener with Netlify Forms!", + name: 'url-shortener', + description: 'URL Shortener: simple URL shortener with Netlify Forms!', async onComplete() { - console.log( - `${chalk.yellow("url-shortener")} function created from template!` - ); + console.log(`${chalk.yellow('url-shortener')} function created from template!`) if (!process.env.ROUTES_FORM_ID || !process.env.API_AUTH) { console.log( - `note this function requires ${chalk.yellow( - "ROUTES_FORM_ID" - )} and ${chalk.yellow( - "API_AUTH" + `note this function requires ${chalk.yellow('ROUTES_FORM_ID')} and ${chalk.yellow( + 'API_AUTH' )} build environment variables set in your Netlify Site.` - ); + ) - let siteData = { name: "YOURSITENAMEHERE" }; + let siteData = { name: 'YOURSITENAMEHERE' } try { siteData = await this.netlify.api.getSite({ siteId: this.netlify.site.id - }); + }) } catch (e) { // silent error, not important } console.log( - `Set them at: https://app.netlify.com/sites/${ - siteData.name - }/settings/deploys#environment-variables (must have CD setup)` - ); + `Set them at: https://app.netlify.com/sites/${siteData.name}/settings/deploys#environment-variables (must have CD setup)` + ) } } -}; +} diff --git a/src/functions-templates/js/url-shortener/generate-route.js b/src/functions-templates/js/url-shortener/generate-route.js index 2057ca92fe2..5558c5bad92 100644 --- a/src/functions-templates/js/url-shortener/generate-route.js +++ b/src/functions-templates/js/url-shortener/generate-route.js @@ -1,53 +1,49 @@ -"use strict"; +'use strict' -var request = require("request"); -var Hashids = require("hashids"); +var request = require('request') +var Hashids = require('hashids') export function handler(event, context, callback) { // Set the root URL according to the Netlify site we are within - var rootURL = process.env.URL + "/"; + var rootURL = process.env.URL + '/' // get the details of what we are creating - var destination = event.queryStringParameters["to"]; + var destination = event.queryStringParameters['to'] // generate a unique short code (stupidly for now) - var hash = new Hashids(); - var number = Math.round(new Date().getTime() / 100); - var code = hash.encode(number); + var hash = new Hashids() + var number = Math.round(new Date().getTime() / 100) + var code = hash.encode(number) // ensure that a protocol was provided - if (destination.indexOf("://") == -1) { - destination = "http://" + destination; + if (destination.indexOf('://') == -1) { + destination = 'http://' + destination } // prepare a payload to post var payload = { - "form-name": "routes", + 'form-name': 'routes', destination: destination, code: code, - expires: "" - }; + expires: '' + } // post the new route to the Routes form - request.post({ url: rootURL, formData: payload }, function( - err, - httpResponse, - body - ) { - var msg; + request.post({ url: rootURL, formData: payload }, function(err, httpResponse, body) { + var msg if (err) { - msg = "Post to Routes stash failed: " + err; + msg = 'Post to Routes stash failed: ' + err } else { - msg = "Route registered. Site deploying to include it. " + rootURL + code; + msg = 'Route registered. Site deploying to include it. ' + rootURL + code } - console.log(msg); + console.log(msg) // tell the user what their shortcode will be return callback(null, { statusCode: 200, - headers: { "Content-Type": "application/json" }, + headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: rootURL + code }) - }); - }); + }) + }) // ENHANCEMENT: check for uniqueness of shortcode // ENHANCEMENT: let the user provide their own shortcode diff --git a/src/functions-templates/js/url-shortener/get-route.js b/src/functions-templates/js/url-shortener/get-route.js index 77ec6bc7f63..d67626d126c 100644 --- a/src/functions-templates/js/url-shortener/get-route.js +++ b/src/functions-templates/js/url-shortener/get-route.js @@ -1,47 +1,42 @@ -"use strict"; +'use strict' -var request = require("request"); +var request = require('request') export function handler(event, context, callback) { // which URL code are we trying to retrieve? - var code = event.queryStringParameters["code"]; + var code = event.queryStringParameters['code'] // where is the data? var url = - "https://api.netlify.com/api/v1/forms/" + + 'https://api.netlify.com/api/v1/forms/' + process.env.ROUTES_FORM_ID + - "/submissions/?access_token=" + - process.env.API_AUTH; + '/submissions/?access_token=' + + process.env.API_AUTH request(url, function(err, response, body) { // look for this code in our stash if (!err && response.statusCode === 200) { - var routes = JSON.parse(body); + var routes = JSON.parse(body) for (var item in routes) { // return the result when we find the match if (routes[item].data.code == code) { - console.log( - "We searched for " + - code + - " and we found " + - routes[item].data.destination - ); + console.log('We searched for ' + code + ' and we found ' + routes[item].data.destination) return callback(null, { statusCode: 200, - headers: { "Content-Type": "application/json" }, + headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code: code, url: routes[item].data.destination }) - }); + }) } } } else { return callback(null, { statusCode: 200, body: err - }); + }) } - }); + }) } diff --git a/src/functions-templates/js/url-shortener/url-shortener.js b/src/functions-templates/js/url-shortener/url-shortener.js index 887790736c8..f03f4093b1a 100644 --- a/src/functions-templates/js/url-shortener/url-shortener.js +++ b/src/functions-templates/js/url-shortener/url-shortener.js @@ -1,21 +1,21 @@ exports.handler = (event, context, callback) => { - const path = event.path.replace(/\.netlify\/functions\/[^\/]+/, ""); - const segments = path.split("/").filter(e => e); + const path = event.path.replace(/\.netlify\/functions\/[^\/]+/, '') + const segments = path.split('/').filter(e => e) switch (event.httpMethod) { - case "GET": + case 'GET': // e.g. GET /.netlify/functions/url-shortener - return require("./get-route").handler(event, context, callback); - case "POST": + return require('./get-route').handler(event, context, callback) + case 'POST': // e.g. POST /.netlify/functions/url-shortener - return require("./generate-route").handler(event, context, callback); - case "PUT": + return require('./generate-route').handler(event, context, callback) + case 'PUT': // your code here - case "DELETE": + case 'DELETE': // your code here } return callback({ statusCode: 500, - body: "unrecognized HTTP Method, must be one of GET/POST/PUT/DELETE" - }); -}; + body: 'unrecognized HTTP Method, must be one of GET/POST/PUT/DELETE' + }) +} diff --git a/src/functions-templates/js/using-middleware/.netlify-function-template.js b/src/functions-templates/js/using-middleware/.netlify-function-template.js index 39c36d3be60..1be3bb38a21 100644 --- a/src/functions-templates/js/using-middleware/.netlify-function-template.js +++ b/src/functions-templates/js/using-middleware/.netlify-function-template.js @@ -1,4 +1,4 @@ module.exports = { - name: "using-middleware", - description: "Using Middleware with middy" -}; + name: 'using-middleware', + description: 'Using Middleware with middy' +} diff --git a/src/functions-templates/js/using-middleware/using-middleware.js b/src/functions-templates/js/using-middleware/using-middleware.js index 4326c66c861..40e3e83f28d 100644 --- a/src/functions-templates/js/using-middleware/using-middleware.js +++ b/src/functions-templates/js/using-middleware/using-middleware.js @@ -1,57 +1,52 @@ -const middy = require("middy"); -const { - jsonBodyParser, - validator, - httpErrorHandler, - httpHeaderNormalizer -} = require("middy/middlewares"); +const middy = require('middy') +const { jsonBodyParser, validator, httpErrorHandler, httpHeaderNormalizer } = require('middy/middlewares') /* Normal lambda code */ const businessLogic = (event, context, callback) => { // event.body has already been turned into an object by `jsonBodyParser` middleware - const { name } = event.body; + const { name } = event.body return callback(null, { statusCode: 200, body: JSON.stringify({ - result: "success", + result: 'success', message: `Hi ${name} ⊂◉‿◉つ` }) - }); -}; + }) +} /* Input & Output Schema */ const schema = { input: { - type: "object", + type: 'object', properties: { body: { - type: "object", - required: ["name"], + type: 'object', + required: ['name'], properties: { - name: { type: "string" } + name: { type: 'string' } } } }, - required: ["body"] + required: ['body'] }, output: { - type: "object", + type: 'object', properties: { body: { - type: "string", - required: ["result", "message"], + type: 'string', + required: ['result', 'message'], properties: { - result: { type: "string" }, - message: { type: "string" } + result: { type: 'string' }, + message: { type: 'string' } } } }, - required: ["body"] + required: ['body'] } -}; +} /* Export inputSchema & outputSchema for automatic documentation */ -exports.schema = schema; +exports.schema = schema exports.handler = middy(businessLogic) .use(httpHeaderNormalizer()) @@ -60,4 +55,4 @@ exports.handler = middy(businessLogic) // validates the input .use(validator({ inputSchema: schema.input })) // handles common http errors and returns proper responses - .use(httpErrorHandler()); + .use(httpErrorHandler()) diff --git a/src/hooks/analytics.js b/src/hooks/analytics.js index c67d30dff88..d6fe558b83f 100644 --- a/src/hooks/analytics.js +++ b/src/hooks/analytics.js @@ -1,6 +1,6 @@ -const { track } = require("@netlify/cli-utils/src/utils/telemetry"); +const { track } = require('@netlify/cli-utils/src/utils/telemetry') -const hook = async function (options) { +const hook = async function(options) { track(options.eventName, options.payload) } module.exports = hook diff --git a/src/tests/addons.test.js b/src/tests/addons.test.js index 268859527c7..b7cd24db169 100644 --- a/src/tests/addons.test.js +++ b/src/tests/addons.test.js @@ -9,11 +9,16 @@ const execOptions = { stdio: [0, 1, 2], cwd: sitePath, env: Object.assign(process.env, { - NETLIFY_AUTH_TOKEN: process.env.NETLIFY_AUTH_TOKEN, - }), + NETLIFY_AUTH_TOKEN: process.env.NETLIFY_AUTH_TOKEN + }) } -const siteName = 'netlify-test-' + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 8) +const siteName = + 'netlify-test-' + + Math.random() + .toString(36) + .replace(/[^a-z]+/g, '') + .substr(0, 8) async function deleteAddon(name) { const cliResponse = await exec(`${cliPath} addons:delete ${name} -f`, execOptions) @@ -22,7 +27,10 @@ async function deleteAddon(name) { test.before(async t => { console.log('creating new site for tests: ' + siteName) - const cliResponse = await exec(`${cliPath} sites:create --name="${siteName}" --account-slug="netlify-services"`, execOptions) + const cliResponse = await exec( + `${cliPath} sites:create --name="${siteName}" --account-slug="netlify-services"`, + execOptions + ) t.is(/Site Created/.test(cliResponse.stdout), true) const matches = /Site ID:\s+([a-zA-Z0-9-]+)/m.exec(stripAnsi(cliResponse.stdout)) @@ -33,26 +41,26 @@ test.before(async t => { execOptions.env.NETLIFY_SITE_ID = matches[1] }) -test.serial('netlify addons:list', async (t) => { +test.serial('netlify addons:list', async t => { const regex = /No addons currently installed/ const cliResponse = await exec(`${cliPath} addons:list`, execOptions) t.is(regex.test(cliResponse.stdout), true) }) -test.serial('netlify addons:list --json', async (t) => { +test.serial('netlify addons:list --json', async t => { const cliResponse = await exec(`${cliPath} addons:list --json`, execOptions) const json = JSON.parse(cliResponse.stdout) t.is(Array.isArray(json), true) t.is(json.length, 0) }) -test.serial('netlify addons:create demo', async (t) => { +test.serial('netlify addons:create demo', async t => { const regex = /Add-on "demo" created/ const cliResponse = await exec(`${cliPath} addons:create demo --TWILIO_ACCOUNT_SID lol`, execOptions) t.is(regex.test(cliResponse.stdout), true) }) -test.serial('After creation netlify addons:list --json', async (t) => { +test.serial('After creation netlify addons:list --json', async t => { const cliResponse = await exec(`${cliPath} addons:list --json`, execOptions) const json = JSON.parse(cliResponse.stdout) t.is(Array.isArray(json), true) @@ -60,7 +68,7 @@ test.serial('After creation netlify addons:list --json', async (t) => { t.is(json[0].service_slug, 'demo') }) -test.serial('netlify addon:delete demo', async (t) => { +test.serial('netlify addon:delete demo', async t => { const regex = /Addon "demo" deleted/ const cliResponse = await deleteAddon('demo') t.is(regex.test(cliResponse.stdout), true) diff --git a/src/tests/utils/cliPath.js b/src/tests/utils/cliPath.js index aaac043b1b9..97f72c9bfe2 100644 --- a/src/tests/utils/cliPath.js +++ b/src/tests/utils/cliPath.js @@ -2,4 +2,4 @@ const path = require('path') const cliPath = path.join(__dirname, '..', '..', '..', 'bin/run') -module.exports = cliPath \ No newline at end of file +module.exports = cliPath diff --git a/src/tests/utils/exec.js b/src/tests/utils/exec.js index cd8e7e69f36..c7b31c68f61 100644 --- a/src/tests/utils/exec.js +++ b/src/tests/utils/exec.js @@ -2,7 +2,7 @@ const { exec } = require('child_process') module.exports = (cmd, opts) => new Promise((resolve, reject) => { - const dirOutput = (opts && opts.cwd) ? `\nDIR: ${opts.cwd}` : '' + const dirOutput = opts && opts.cwd ? `\nDIR: ${opts.cwd}` : '' console.log(`Running command...\nCMD: ${cmd}${dirOutput}`) exec(cmd, opts, (err, stdout, stderr) => { if (err) { diff --git a/src/utils/addons.js b/src/utils/addons.js index 0e8199db179..b256ae87b02 100644 --- a/src/utils/addons.js +++ b/src/utils/addons.js @@ -1,31 +1,23 @@ /* eslint no-console: 0 */ -const { getAddons, createAddon } = require("netlify/src/addons"); +const { getAddons, createAddon } = require('netlify/src/addons') // const chalk = require("chalk"); // const fetch = require("node-fetch"); /** main section - shamelessly adapted from CLI. we can extract and dedupe later. */ /** but we can DRY things up later. */ // eslint-disable-next-line max-params -module.exports.createSiteAddon = async function( - accessToken, - addonName, - siteId, - siteData, - log -) { - const addons = await getAddons(siteId, accessToken); - if (typeof addons === "object" && addons.error) { - log("API Error", addons); - return false; +module.exports.createSiteAddon = async function(accessToken, addonName, siteId, siteData, log) { + const addons = await getAddons(siteId, accessToken) + if (typeof addons === 'object' && addons.error) { + log('API Error', addons) + return false } // Filter down addons to current args.name - const currentAddon = addons.find( - addon => addon.service_path === `/.netlify/${addonName}` - ); - const rawFlags = {}; + const currentAddon = addons.find(addon => addon.service_path === `/.netlify/${addonName}`) + const rawFlags = {} if (currentAddon && currentAddon.id) { - log(`The "${addonName} add-on" already exists for ${siteData.name}`); + log(`The "${addonName} add-on" already exists for ${siteData.name}`) // // just exit // log() // const cmd = chalk.cyan(`\`netlify addons:config ${addonName}\``) @@ -33,12 +25,12 @@ module.exports.createSiteAddon = async function( // const deleteCmd = chalk.cyan(`\`netlify addons:delete ${addonName}\``) // log(`- To remove this add-on run: ${deleteCmd}`) // log() - return false; + return false } // const manifest = await getAddonManifest(addonName, accessToken); - let configValues = rawFlags; + let configValues = rawFlags // if (manifest.config) { // const required = requiredConfigValues(manifest.config); // console.log(`Starting the setup for "${addonName} add-on"`); @@ -120,30 +112,23 @@ module.exports.createSiteAddon = async function( }, accessToken, siteData - }); - return addonName; // we dont really use this right now but may be helpful to know that an addon installation was successful -}; - -async function actuallyCreateSiteAddon({ - addonName, - settings, - accessToken, - siteData -}) { - const addonResponse = await createAddon(settings, accessToken); + }) + return addonName // we dont really use this right now but may be helpful to know that an addon installation was successful +} + +async function actuallyCreateSiteAddon({ addonName, settings, accessToken, siteData }) { + const addonResponse = await createAddon(settings, accessToken) if (addonResponse.code === 404) { - console.log( - `No add-on "${addonName}" found. Please double check your add-on name and try again` - ); - return false; + console.log(`No add-on "${addonName}" found. Please double check your add-on name and try again`) + return false } - console.log(`Add-on "${addonName}" created for ${siteData.name}`); + console.log(`Add-on "${addonName}" created for ${siteData.name}`) if (addonResponse.config && addonResponse.config.message) { - console.log(); - console.log(`${addonResponse.config.message}`); + console.log() + console.log(`${addonResponse.config.message}`) } - return addonResponse; + return addonResponse } /** all the utils used in the main section */ diff --git a/src/utils/addons/api.js b/src/utils/addons/api.js index 3b2445ba8d5..0481bbe88d1 100644 --- a/src/utils/addons/api.js +++ b/src/utils/addons/api.js @@ -19,4 +19,4 @@ async function getAddonManifest(addonName, netlifyApiToken) { return data } -module.exports = getAddonManifest \ No newline at end of file +module.exports = getAddonManifest diff --git a/src/utils/addons/diffs/index.js b/src/utils/addons/diffs/index.js index 57203053233..ab9000b439b 100644 --- a/src/utils/addons/diffs/index.js +++ b/src/utils/addons/diffs/index.js @@ -15,4 +15,4 @@ module.exports = function diffValues(actual, expected) { const expectedDescriptor = result.expected || concordance.describe(expected, concordanceOptions) return formatDescriptorDiff(actualDescriptor, expectedDescriptor) -} \ No newline at end of file +} diff --git a/src/utils/addons/diffs/options.js b/src/utils/addons/diffs/options.js index 193cc6f2c36..54c651ee916 100644 --- a/src/utils/addons/diffs/options.js +++ b/src/utils/addons/diffs/options.js @@ -106,4 +106,4 @@ const plugins = [] const theme = colorTheme module.exports.concordanceOptions = { maxDepth: 3, plugins, theme } -module.exports.concordanceDiffOptions = { maxDepth: 1, plugins, theme } \ No newline at end of file +module.exports.concordanceDiffOptions = { maxDepth: 1, plugins, theme } diff --git a/src/utils/addons/prompts.js b/src/utils/addons/prompts.js index e318c56da07..721b91ce582 100644 --- a/src/utils/addons/prompts.js +++ b/src/utils/addons/prompts.js @@ -5,64 +5,67 @@ module.exports = function generatePrompts(settings) { const { config, configValues } = settings const configItems = Object.keys(config) - const prompts = configItems.map((key, i) => { - const setting = config[key] - // const { type, displayName } = setting - let prompt - // Tell user to use types - if (!setting.type) { - console.log(`⚠️ ${chalk.yellowBright(`Warning: no \`type\` is set for config key: ${configItems[i]}`)}`) - console.log(`It's highly recommended that you type your configuration values. It will help with automatic documentation, sharing of your services, and make your services configurable through a GUI`) - console.log('') - } + const prompts = configItems + .map((key, i) => { + const setting = config[key] + // const { type, displayName } = setting + let prompt + // Tell user to use types + if (!setting.type) { + console.log(`⚠️ ${chalk.yellowBright(`Warning: no \`type\` is set for config key: ${configItems[i]}`)}`) + console.log( + `It's highly recommended that you type your configuration values. It will help with automatic documentation, sharing of your services, and make your services configurable through a GUI` + ) + console.log('') + } + + // Handle shorthand config. Probably will be removed. Severly limited + not great UX + if (typeof setting === 'string' || typeof setting === 'boolean') { + if (typeof setting === 'string') { + prompt = { + type: 'input', + name: key, + message: `Enter string value for '${key}':` + } + // if current stage value set show as default + if (configValues[key]) { + prompt.default = configValues[key] + } + } else if (typeof setting === 'boolean') { + prompt = { + type: 'confirm', + name: key, + message: `Do you want '${key}':` + } + } + return prompt + } - // Handle shorthand config. Probably will be removed. Severly limited + not great UX - if (typeof setting === 'string' || typeof setting === 'boolean') { - if (typeof setting === 'string') { + // For future use. Once UX is decided + // const defaultValidation = (setting.required) ? validateRequired : noValidate + const defaultValidation = noValidate + const validateFunction = setting.pattern ? validate(setting.pattern) : defaultValidation + const isRequiredText = setting.required ? ` (${chalk.yellow('required')})` : '' + if (setting.type === 'string' || setting.type.match(/string/)) { prompt = { type: 'input', name: key, - message: `Enter string value for '${key}':`, + message: `${chalk.white(key)}${isRequiredText} - ${setting.displayName}` || `Please enter value for ${key}`, + validate: validateFunction } - // if current stage value set show as default + // if value previously set show it if (configValues[key]) { prompt.default = configValues[key] + // else show default value if provided + } else if (setting.default) { + prompt.default = setting.default } - } else if (typeof setting === 'boolean') { - prompt = { - type: 'confirm', - name: key, - message: `Do you want '${key}':`, - } + return prompt } - return prompt - } - - // For future use. Once UX is decided - // const defaultValidation = (setting.required) ? validateRequired : noValidate - const defaultValidation = noValidate - const validateFunction = (setting.pattern) ? validate(setting.pattern) : defaultValidation - const isRequiredText = (setting.required) ? ` (${chalk.yellow('required')})` : '' - if (setting.type === 'string' || setting.type.match((/string/))) { - prompt = { - type: 'input', - name: key, - message: `${chalk.white(key)}${isRequiredText} - ${setting.displayName}` || `Please enter value for ${key}`, - validate: validateFunction - } - // if value previously set show it - if (configValues[key]) { - prompt.default = configValues[key] - // else show default value if provided - } else if (setting.default) { - prompt.default = setting.default - } - return prompt - } - - }).filter((item) => { - return typeof item !== 'undefined' - }) + }) + .filter(item => { + return typeof item !== 'undefined' + }) return prompts } @@ -71,7 +74,8 @@ function noValidate() { } // Will use this soon -function validateRequired(value) { // eslint-disable-line +function validateRequired(value) { + // eslint-disable-line if (value) { return true } @@ -86,4 +90,4 @@ function validate(pattern) { } return `Please enter a value matching regex pattern: /${chalk.yellowBright(pattern)}/` } -} \ No newline at end of file +} diff --git a/src/utils/addons/render.js b/src/utils/addons/render.js index c336434a404..772af1280b0 100644 --- a/src/utils/addons/render.js +++ b/src/utils/addons/render.js @@ -2,25 +2,28 @@ const chalk = require('chalk') const AsciiTable = require('ascii-table') function missingValues(values, manifest) { - const display = values.map((item) => { - const itemDisplay = chalk.redBright.bold(`${item}`) - const niceNameDisplay = manifest.config[item].displayName - return ` - ${itemDisplay} ${niceNameDisplay}` - }).join('\n') + const display = values + .map(item => { + const itemDisplay = chalk.redBright.bold(`${item}`) + const niceNameDisplay = manifest.config[item].displayName + return ` - ${itemDisplay} ${niceNameDisplay}` + }) + .join('\n') console.log(display) } function configValues(addonName, configValues, currentValue) { - const table = new AsciiTable(`${addonName} add-on settings`) - const tableHeader = (currentValue) ? ['Setting Name', 'Current Value', 'Description'] : ['Setting Name', 'Description', 'Type', 'Required'] + const tableHeader = currentValue + ? ['Setting Name', 'Current Value', 'Description'] + : ['Setting Name', 'Description', 'Type', 'Required'] table.setHeading(...tableHeader) - Object.keys(configValues).map((key) => { + Object.keys(configValues).map(key => { const { type, displayName, required } = configValues[key] - let requiredText = (required) ? `true` : `false` + let requiredText = required ? `true` : `false` const typeInfo = type || '' const description = displayName || '' if (currentValue) { @@ -36,4 +39,4 @@ function configValues(addonName, configValues, currentValue) { module.exports = { missingValues, configValues -} \ No newline at end of file +} diff --git a/src/utils/addons/validation.js b/src/utils/addons/validation.js index c7526a7c338..89ade9ae9c9 100644 --- a/src/utils/addons/validation.js +++ b/src/utils/addons/validation.js @@ -1,12 +1,11 @@ - module.exports.requiredConfigValues = function requiredConfigValues(config) { - return Object.keys(config).filter((key) => { + return Object.keys(config).filter(key => { return config[key].required }) } module.exports.missingConfigValues = function missingConfigValues(requiredConfig, providedConfig) { - return requiredConfig.filter((key) => { + return requiredConfig.filter(key => { return !providedConfig[key] }) } @@ -20,4 +19,4 @@ module.exports.updateConfigValues = function missingConfigValues(allowedConfig, acc[key] = currentConfig[key] return acc }, {}) -} \ No newline at end of file +} diff --git a/src/utils/check-command-inputs.js b/src/utils/check-command-inputs.js index 351502831b0..2e66072266c 100644 --- a/src/utils/check-command-inputs.js +++ b/src/utils/check-command-inputs.js @@ -1,4 +1,3 @@ - // Checks for args or flags supplied to command function isEmptyCommand(flags, args) { if (!hasFlags(flags) && !hasArgs(args)) { diff --git a/src/utils/detect-functions-builder.js b/src/utils/detect-functions-builder.js index dc63b07119f..6adfc968ecd 100644 --- a/src/utils/detect-functions-builder.js +++ b/src/utils/detect-functions-builder.js @@ -1,17 +1,15 @@ -const path = require("path"); +const path = require('path') -const detectors = require("fs") - .readdirSync(path.join(__dirname, "..", "function-builder-detectors")) - .filter(x => x.endsWith(".js")) // only accept .js detector files - .map(det => - require(path.join(__dirname, "..", `function-builder-detectors/${det}`)) - ); +const detectors = require('fs') + .readdirSync(path.join(__dirname, '..', 'function-builder-detectors')) + .filter(x => x.endsWith('.js')) // only accept .js detector files + .map(det => require(path.join(__dirname, '..', `function-builder-detectors/${det}`))) module.exports.detectFunctionsBuilder = function() { for (const i in detectors) { - const settings = detectors[i](); + const settings = detectors[i]() if (settings) { - return settings; + return settings } } -}; +} diff --git a/src/utils/detect-server.js b/src/utils/detect-server.js index f56f8b791cc..9b2e22219c9 100644 --- a/src/utils/detect-server.js +++ b/src/utils/detect-server.js @@ -1,102 +1,88 @@ -const path = require("path"); -const chalk = require("chalk"); -const { NETLIFYDEVLOG } = require("netlify-cli-logo"); -const inquirer = require("inquirer"); -const fs = require("fs"); +const path = require('path') +const chalk = require('chalk') +const { NETLIFYDEVLOG } = require('netlify-cli-logo') +const inquirer = require('inquirer') +const fs = require('fs') const detectors = fs - .readdirSync(path.join(__dirname, "..", "detectors")) - .filter(x => x.endsWith(".js")) // only accept .js detector files + .readdirSync(path.join(__dirname, '..', 'detectors')) + .filter(x => x.endsWith('.js')) // only accept .js detector files .map(det => { try { - return require(path.join(__dirname, "..", `detectors/${det}`)); + return require(path.join(__dirname, '..', `detectors/${det}`)) } catch (err) { console.error( `failed to load detector: ${chalk.yellow( det )}, this is likely a bug in the detector, please file an issue in netlify-dev-plugin`, err - ); - return null; + ) + return null } }) - .filter(Boolean); + .filter(Boolean) module.exports.serverSettings = async devConfig => { - let settingsArr = []; - let settings = null; + let settingsArr = [] + let settings = null for (const i in detectors) { - const detectorResult = detectors[i](); - if (detectorResult) settingsArr.push(detectorResult); + const detectorResult = detectors[i]() + if (detectorResult) settingsArr.push(detectorResult) } if (settingsArr.length === 1) { // vast majority of projects will only have one matching detector - settings = settingsArr[0]; - settings.args = settings.possibleArgsArrs[0]; // just pick the first one + settings = settingsArr[0] + settings.args = settings.possibleArgsArrs[0] // just pick the first one if (!settings.args) { - const { scripts } = JSON.parse( - fs.readFileSync("package.json", { encoding: "utf8" }) - ); + const { scripts } = JSON.parse(fs.readFileSync('package.json', { encoding: 'utf8' })) // eslint-disable-next-line no-console console.error( - "empty args assigned, this is an internal Netlify Dev bug, please report your settings and scripts so we can improve", + 'empty args assigned, this is an internal Netlify Dev bug, please report your settings and scripts so we can improve', { scripts, settings } - ); + ) // eslint-disable-next-line no-process-exit - process.exit(1); + process.exit(1) } } else if (settingsArr.length > 1) { /** multiple matching detectors, make the user choose */ // lazy loading on purpose - inquirer.registerPrompt( - "autocomplete", - require("inquirer-autocomplete-prompt") - ); - const fuzzy = require("fuzzy"); - const scriptInquirerOptions = formatSettingsArrForInquirer(settingsArr); + inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt')) + const fuzzy = require('fuzzy') + const scriptInquirerOptions = formatSettingsArrForInquirer(settingsArr) const { chosenSetting } = await inquirer.prompt({ - name: "chosenSetting", + name: 'chosenSetting', message: `Multiple possible start commands found`, - type: "autocomplete", + type: 'autocomplete', source: async function(_, input) { - if (!input || input === "") { - return scriptInquirerOptions; + if (!input || input === '') { + return scriptInquirerOptions } // only show filtered results - return filterSettings(scriptInquirerOptions, input); + return filterSettings(scriptInquirerOptions, input) } - }); - settings = chosenSetting; // finally! we have a selected option + }) + settings = chosenSetting // finally! we have a selected option // TODO: offer to save this setting to netlify.toml so you dont keep doing this /** utiltities for the inquirer section above */ function filterSettings(scriptInquirerOptions, input) { - const filteredSettings = fuzzy.filter( - input, - scriptInquirerOptions.map(x => x.name) - ); - const filteredSettingNames = filteredSettings.map(x => - input ? x.string : x - ); - return scriptInquirerOptions.filter(t => - filteredSettingNames.includes(t.name) - ); + const filteredSettings = fuzzy.filter(input, scriptInquirerOptions.map(x => x.name)) + const filteredSettingNames = filteredSettings.map(x => (input ? x.string : x)) + return scriptInquirerOptions.filter(t => filteredSettingNames.includes(t.name)) } /** utiltities for the inquirer section above */ function formatSettingsArrForInquirer(settingsArr) { - let ans = []; + let ans = [] settingsArr.forEach(setting => { setting.possibleArgsArrs.forEach(args => { ans.push({ - name: `[${chalk.yellow(setting.type)}] ${ - setting.command - } ${args.join(" ")}`, + name: `[${chalk.yellow(setting.type)}] ${setting.command} ${args.join(' ')}`, value: { ...setting, args }, - short: setting.type + "-" + args.join(" ") - }); - }); - }); - return ans; + short: setting.type + '-' + args.join(' ') + }) + }) + }) + return ans } } @@ -104,40 +90,28 @@ module.exports.serverSettings = async devConfig => { const tellUser = settingsField => dV => // eslint-disable-next-line no-console console.log( - `${NETLIFYDEVLOG} Overriding ${chalk.yellow( - settingsField - )} with setting derived from netlify.toml [dev] block: `, + `${NETLIFYDEVLOG} Overriding ${chalk.yellow(settingsField)} with setting derived from netlify.toml [dev] block: `, dV - ); + ) if (devConfig) { - settings = settings || {}; + settings = settings || {} if (devConfig.command) { - settings.command = assignLoudly( - devConfig.command.split(/\s/)[0], - settings.command || null, - tellUser("command") - ); // if settings.command is empty, its bc no settings matched - let devConfigArgs = devConfig.command.split(/\s/).slice(1); - if (devConfigArgs[0] === "run") devConfigArgs = devConfigArgs.slice(1); - settings.args = assignLoudly( - devConfigArgs, - settings.command || null, - tellUser("command") - ); // if settings.command is empty, its bc no settings matched + settings.command = assignLoudly(devConfig.command.split(/\s/)[0], settings.command || null, tellUser('command')) // if settings.command is empty, its bc no settings matched + let devConfigArgs = devConfig.command.split(/\s/).slice(1) + if (devConfigArgs[0] === 'run') devConfigArgs = devConfigArgs.slice(1) + settings.args = assignLoudly(devConfigArgs, settings.command || null, tellUser('command')) // if settings.command is empty, its bc no settings matched } if (devConfig.port) { - settings.proxyPort = devConfig.port || settings.proxyPort; - const regexp = - devConfig.urlRegexp || - new RegExp(`(http://)([^:]+:)${devConfig.port}(/)?`, "g"); - settings.urlRegexp = settings.urlRegexp || regexp; + settings.proxyPort = devConfig.port || settings.proxyPort + const regexp = devConfig.urlRegexp || new RegExp(`(http://)([^:]+:)${devConfig.port}(/)?`, 'g') + settings.urlRegexp = settings.urlRegexp || regexp } if (devConfig.functionsPort) settings.functionsPort = devConfig.functionsPort - settings.dist = devConfig.publish || settings.dist; // dont loudassign if they dont need it + settings.dist = devConfig.publish || settings.dist // dont loudassign if they dont need it } - return settings; -}; + return settings +} // if first arg is undefined, use default, but tell user about it in case it is unintentional function assignLoudly( @@ -146,10 +120,10 @@ function assignLoudly( // eslint-disable-next-line no-console tellUser = dV => console.log(`No value specified, using fallback of `, dV) ) { - if (defaultValue === undefined) throw new Error("must have a defaultValue"); + if (defaultValue === undefined) throw new Error('must have a defaultValue') if (defaultValue !== optionalValue && optionalValue === undefined) { - tellUser(defaultValue); - return defaultValue; + tellUser(defaultValue) + return defaultValue } - return optionalValue; + return optionalValue } diff --git a/src/utils/dev.js b/src/utils/dev.js index eee38db7a76..4751b54abbf 100644 --- a/src/utils/dev.js +++ b/src/utils/dev.js @@ -2,13 +2,13 @@ // reusable code for netlify dev // bit of a hasty abstraction but recommended by oclif -const { getAddons } = require("netlify/src/addons"); -const chalk = require("chalk"); +const { getAddons } = require('netlify/src/addons') +const chalk = require('chalk') const { NETLIFYDEVLOG, // NETLIFYDEVWARN, NETLIFYDEVERR -} = require("netlify-cli-logo"); +} = require('netlify-cli-logo') /** * inject environment variables from netlify addons and buildbot * into your local dev process.env @@ -25,83 +25,69 @@ const { */ async function addEnvVariables(api, site, accessToken) { /** from addons */ - const addonUrls = {}; + const addonUrls = {} const addons = await getAddons(site.id, accessToken).catch(error => { - console.error(error); + console.error(error) switch (error.status) { default: console.error( `${NETLIFYDEVERR} Error retrieving addons data for site ${chalk.yellow( site.id )}. Double-check your login status with 'netlify status' or contact support with details of your error.` - ); - process.exit(); + ) + process.exit() } - }); + }) if (Array.isArray(addons)) { addons.forEach(addon => { - addonUrls[addon.slug] = `${addon.config.site_url}/.netlify/${addon.slug}`; + addonUrls[addon.slug] = `${addon.config.site_url}/.netlify/${addon.slug}` for (const key in addon.env) { const msg = () => - console.log( - `${NETLIFYDEVLOG} Injected ${chalk.yellow.bold("addon")} env var: `, - chalk.yellow(key) - ); - process.env[key] = assignLoudly(process.env[key], addon.env[key], msg); + console.log(`${NETLIFYDEVLOG} Injected ${chalk.yellow.bold('addon')} env var: `, chalk.yellow(key)) + process.env[key] = assignLoudly(process.env[key], addon.env[key], msg) } - }); + }) } /** from web UI */ const apiSite = await api.getSite({ site_id: site.id }).catch(error => { - console.error(error); + console.error(error) switch (error.status) { case 401: console.error( - `${NETLIFYDEVERR} Unauthorized error: This Site ID ${chalk.yellow( - site.id - )} does not belong to your account.` - ); + `${NETLIFYDEVERR} Unauthorized error: This Site ID ${chalk.yellow(site.id)} does not belong to your account.` + ) console.error( `${NETLIFYDEVERR} If you cloned someone else's code, try running 'npm unlink' and then 'npm init' or 'npm link'.` - ); + ) - process.exit(); + process.exit() default: console.error( `${NETLIFYDEVERR} Error retrieving site data for site ${chalk.yellow( site.id )}. Double-check your login status with 'netlify status' or contact support with details of your error.` - ); - process.exit(); + ) + process.exit() } - }); + }) // TODO: We should move the environment outside of build settings and possibly have a // `/api/v1/sites/:site_id/environment` endpoint for it that we can also gate access to // In the future and that we could make context dependend if (apiSite.build_settings && apiSite.build_settings.env) { for (const key in apiSite.build_settings.env) { const msg = () => - console.log( - `${NETLIFYDEVLOG} Injected ${chalk.blue.bold( - "build setting" - )} env var: `, - chalk.yellow(key) - ); - process.env[key] = assignLoudly( - process.env[key], - apiSite.build_settings.env[key], - msg - ); + console.log(`${NETLIFYDEVLOG} Injected ${chalk.blue.bold('build setting')} env var: `, chalk.yellow(key)) + process.env[key] = assignLoudly(process.env[key], apiSite.build_settings.env[key], msg) } } - return addonUrls; + return addonUrls } module.exports = { addEnvVariables -}; +} // if first arg is undefined, use default, but tell user about it in case it is unintentional function assignLoudly( @@ -109,10 +95,10 @@ function assignLoudly( defaultValue, tellUser = dV => console.log(`No value specified, using fallback of `, dV) ) { - if (defaultValue === undefined) throw new Error("must have a defaultValue"); + if (defaultValue === undefined) throw new Error('must have a defaultValue') if (defaultValue !== optionalValue && optionalValue === undefined) { - tellUser(defaultValue); - return defaultValue; + tellUser(defaultValue) + return defaultValue } - return optionalValue; + return optionalValue } diff --git a/src/utils/finders.js b/src/utils/finders.js index 56d86e92700..965ad7ebe2b 100644 --- a/src/utils/finders.js +++ b/src/utils/finders.js @@ -1,189 +1,178 @@ -const path = require("path"); -const fs = require("fs"); -const packList = require("npm-packlist"); -const precinct = require("precinct"); -const resolve = require("resolve"); -const readPkgUp = require("read-pkg-up"); -const requirePackageName = require("require-package-name"); -const alwaysIgnored = new Set(["aws-sdk"]); -const debug = require("debug")("netlify-dev-plugin:src/utils/finders"); +const path = require('path') +const fs = require('fs') +const packList = require('npm-packlist') +const precinct = require('precinct') +const resolve = require('resolve') +const readPkgUp = require('read-pkg-up') +const requirePackageName = require('require-package-name') +const alwaysIgnored = new Set(['aws-sdk']) +const debug = require('debug')('netlify-dev-plugin:src/utils/finders') const ignoredExtensions = new Set([ - ".log", - ".lock", - ".html", - ".md", - ".map", - ".ts", - ".png", - ".jpeg", - ".jpg", - ".gif", - ".css", - ".patch" -]); + '.log', + '.lock', + '.html', + '.md', + '.map', + '.ts', + '.png', + '.jpeg', + '.jpg', + '.gif', + '.css', + '.patch' +]) function ignoreMissing(dependency, optional) { - return alwaysIgnored.has(dependency) || (optional && dependency in optional); + return alwaysIgnored.has(dependency) || (optional && dependency in optional) } function includeModuleFile(packageJson, moduleFilePath) { if (packageJson.files) { - return true; + return true } - return !ignoredExtensions.has(path.extname(moduleFilePath)); + return !ignoredExtensions.has(path.extname(moduleFilePath)) } function getDependencies(filename, basedir) { - const servicePath = basedir; + const servicePath = basedir - const filePaths = new Set(); - const modulePaths = new Set(); - const pkgs = {}; + const filePaths = new Set() + const modulePaths = new Set() + const pkgs = {} - const modulesToProcess = []; - const localFilesToProcess = [filename]; + const modulesToProcess = [] + const localFilesToProcess = [filename] function handle(name, basedir, optionalDependencies) { - const moduleName = requirePackageName(name.replace(/\\/, "/")); + const moduleName = requirePackageName(name.replace(/\\/, '/')) if (alwaysIgnored.has(moduleName)) { - return; + return } try { - const pathToModule = resolve.sync(path.join(moduleName, "package.json"), { + const pathToModule = resolve.sync(path.join(moduleName, 'package.json'), { basedir - }); - const pkg = readPkgUp.sync({ cwd: pathToModule }); + }) + const pkg = readPkgUp.sync({ cwd: pathToModule }) if (pkg) { - modulesToProcess.push(pkg); + modulesToProcess.push(pkg) } } catch (e) { - if (e.code === "MODULE_NOT_FOUND") { + if (e.code === 'MODULE_NOT_FOUND') { if (ignoreMissing(moduleName, optionalDependencies)) { - debug(`WARNING missing optional dependency: ${moduleName}`); - return null; + debug(`WARNING missing optional dependency: ${moduleName}`) + return null } try { // this resolves the requested import also against any set up NODE_PATH extensions, etc. - const resolved = require.resolve(name); - localFilesToProcess.push(resolved); - return; + const resolved = require.resolve(name) + localFilesToProcess.push(resolved) + return } catch (e) { throw new Error(`Could not find "${moduleName}" module in file: ${filename.replace( path.dirname(basedir), - "" + '' )}. -Please ensure "${moduleName}" is installed in the project.`); +Please ensure "${moduleName}" is installed in the project.`) } } - throw e; + throw e } } while (localFilesToProcess.length) { - const currentLocalFile = localFilesToProcess.pop(); + const currentLocalFile = localFilesToProcess.pop() if (filePaths.has(currentLocalFile)) { - continue; + continue } - filePaths.add(currentLocalFile); - precinct - .paperwork(currentLocalFile, { includeCore: false }) - .forEach(dependency => { - if (dependency.indexOf(".") === 0) { - const abs = resolve.sync(dependency, { - basedir: path.dirname(currentLocalFile) - }); - localFilesToProcess.push(abs); - } else { - handle(dependency, servicePath); - } - }); + filePaths.add(currentLocalFile) + precinct.paperwork(currentLocalFile, { includeCore: false }).forEach(dependency => { + if (dependency.indexOf('.') === 0) { + const abs = resolve.sync(dependency, { + basedir: path.dirname(currentLocalFile) + }) + localFilesToProcess.push(abs) + } else { + handle(dependency, servicePath) + } + }) } while (modulesToProcess.length) { - const currentModule = modulesToProcess.pop(); - const currentModulePath = path.join(currentModule.path, ".."); - const packageJson = currentModule.pkg; + const currentModule = modulesToProcess.pop() + const currentModulePath = path.join(currentModule.path, '..') + const packageJson = currentModule.pkg if (modulePaths.has(currentModulePath)) { - continue; + continue } - modulePaths.add(currentModulePath); - pkgs[currentModulePath] = packageJson; - ["dependencies", "peerDependencies", "optionalDependencies"].forEach( - key => { - const dependencies = packageJson[key]; - - if (dependencies) { - Object.keys(dependencies).forEach(dependency => { - handle( - dependency, - currentModulePath, - packageJson.optionalDependencies - ); - }); - } + modulePaths.add(currentModulePath) + pkgs[currentModulePath] = packageJson + ;['dependencies', 'peerDependencies', 'optionalDependencies'].forEach(key => { + const dependencies = packageJson[key] + + if (dependencies) { + Object.keys(dependencies).forEach(dependency => { + handle(dependency, currentModulePath, packageJson.optionalDependencies) + }) } - ); + }) } modulePaths.forEach(modulePath => { - const packageJson = pkgs[modulePath]; - let moduleFilePaths; + const packageJson = pkgs[modulePath] + let moduleFilePaths - moduleFilePaths = packList.sync({ path: modulePath }); + moduleFilePaths = packList.sync({ path: modulePath }) moduleFilePaths.forEach(moduleFilePath => { if (includeModuleFile(packageJson, moduleFilePath)) { - filePaths.add(path.join(modulePath, moduleFilePath)); + filePaths.add(path.join(modulePath, moduleFilePath)) } - }); - }); + }) + }) // TODO: get rid of this - const sizes = {}; + const sizes = {} filePaths.forEach(filepath => { - const stat = fs.lstatSync(filepath); - const ext = path.extname(filepath); - sizes[ext] = (sizes[ext] || 0) + stat.size; - }); - debug("Sizes per extension: ", sizes); + const stat = fs.lstatSync(filepath) + const ext = path.extname(filepath) + sizes[ext] = (sizes[ext] || 0) + stat.size + }) + debug('Sizes per extension: ', sizes) - return [...filePaths]; + return [...filePaths] } function findModuleDir(dir) { - let basedir = dir; - while (!fs.existsSync(path.join(basedir, "package.json"))) { - const newBasedir = path.dirname(basedir); + let basedir = dir + while (!fs.existsSync(path.join(basedir, 'package.json'))) { + const newBasedir = path.dirname(basedir) if (newBasedir === basedir) { - return null; + return null } - basedir = newBasedir; + basedir = newBasedir } - return basedir; + return basedir } function findHandler(functionPath) { if (fs.lstatSync(functionPath).isFile()) { - return functionPath; + return functionPath } - const handlerPath = path.join( - functionPath, - `${path.basename(functionPath)}.js` - ); + const handlerPath = path.join(functionPath, `${path.basename(functionPath)}.js`) if (!fs.existsSync(handlerPath)) { - return; + return } - return handlerPath; + return handlerPath } -module.exports = { getDependencies, findModuleDir, findHandler }; +module.exports = { getDependencies, findModuleDir, findHandler } diff --git a/src/utils/get-functions.js b/src/utils/get-functions.js index 0c1ae7c296d..220ad1a23d3 100644 --- a/src/utils/get-functions.js +++ b/src/utils/get-functions.js @@ -1,33 +1,33 @@ -const fs = require("fs"); -const path = require("path"); -const { findModuleDir, findHandler } = require("./finders"); +const fs = require('fs') +const path = require('path') +const { findModuleDir, findHandler } = require('./finders') module.exports = { getFunctions(dir) { - const functions = {}; + const functions = {} if (fs.existsSync(dir)) { fs.readdirSync(dir).forEach(file => { - if (dir === "node_modules") { - return; + if (dir === 'node_modules') { + return } - const functionPath = path.resolve(path.join(dir, file)); - const handlerPath = findHandler(functionPath); + const functionPath = path.resolve(path.join(dir, file)) + const handlerPath = findHandler(functionPath) if (!handlerPath) { - return; + return } - if (path.extname(functionPath) === ".js") { - functions[file.replace(/\.js$/, "")] = { + if (path.extname(functionPath) === '.js') { + functions[file.replace(/\.js$/, '')] = { functionPath, moduleDir: findModuleDir(functionPath) - }; + } } else if (fs.lstatSync(functionPath).isDirectory()) { functions[file] = { functionPath: handlerPath, moduleDir: findModuleDir(functionPath) - }; + } } - }); + }) } - return functions; + return functions } -}; +} diff --git a/src/utils/get-repo-data.js b/src/utils/get-repo-data.js index 11169f6c799..0445e5ae211 100644 --- a/src/utils/get-repo-data.js +++ b/src/utils/get-repo-data.js @@ -8,7 +8,6 @@ async function getRepoData() { const cwd = process.cwd() let repo = {} try { - const remoteUrl = await gitRemoteOriginUrl() const gitDirectory = findUp.sync(['.git'], { cwd: cwd }) const baseGitPath = path.dirname(gitDirectory) @@ -35,7 +34,7 @@ async function getRepoData() { repo_path: remoteData.path, repo_branch: repoData.branch, allowed_branches: [repoData.branch], - host: remoteData.host, + host: remoteData.host } switch (remoteData.host) { diff --git a/src/utils/gh-auth.js b/src/utils/gh-auth.js index ffc1fe61f0b..292879b90cf 100644 --- a/src/utils/gh-auth.js +++ b/src/utils/gh-auth.js @@ -27,8 +27,8 @@ async function getGitHubToken(opts) { type: 'input', name: 'otp', message: 'Your GitHub OTP/2FA Code:', - filter: input => input.trim(), - }, + filter: input => input.trim() + } ]) return otp } @@ -41,28 +41,32 @@ async function getGitHubToken(opts) { { type: 'list', name: 'initChoice', - message: 'Netlify CLI needs access to your GitHub account to configure Webhooks and Deploy Keys. ' + + message: + 'Netlify CLI needs access to your GitHub account to configure Webhooks and Deploy Keys. ' + 'What would you like to do?', - choices: authChoices, - }, + choices: authChoices + } ]) if (initChoice === authChoiceNetlify) { const port = await getPort({ port: 3000 }) let deferredResolve let deferredReject - const deferredPromise = new Promise(function (resolve, reject) { + const deferredPromise = new Promise(function(resolve, reject) { deferredResolve = resolve deferredReject = reject }) - const server = http.createServer(function (req, res) { + const server = http.createServer(function(req, res) { const parameters = querystring.parse(req.url.slice(req.url.indexOf('?') + 1)) if (parameters.token) { deferredResolve(parameters) - res.end("" + - "

Logged In

You're now logged into Netlify CLI with your " + - parameters.provider + " credentials. Please close this window.

") + res.end( + "" + + "

Logged In

You're now logged into Netlify CLI with your " + + parameters.provider + + ' credentials. Please close this window.

' + ) server.close() return } @@ -71,22 +75,26 @@ async function getGitHubToken(opts) { deferredReject(new Error('Got invalid parameters for CLI login')) }) - await new Promise(function (resolve, reject) { + await new Promise(function(resolve, reject) { server.on('error', reject) server.listen(port, resolve) }) const webUI = process.env.NETLIFY_WEB_UI || 'https://app.netlify.com' - const url = webUI + '/cli?' + querystring.encode({ - host: 'http://localhost:' + port, - provider: 'github', - }) + const url = + webUI + + '/cli?' + + querystring.encode({ + host: 'http://localhost:' + port, + provider: 'github' + }) try { await open(url) } catch (err) { - console.log('Netlify CLI could not open the browser for you.' + - ' Please visit this URL in a browser on this device: ' + url) + console.log( + 'Netlify CLI could not open the browser for you.' + ' Please visit this URL in a browser on this device: ' + url + ) } return await deferredPromise @@ -96,18 +104,17 @@ async function getGitHubToken(opts) { type: 'input', name: 'username', message: 'Your GitHub username:', - filter: input => input.trim(), + filter: input => input.trim() }, { type: 'password', name: 'password', message: 'Your GitHub password:', mask: '*', - filter: input => input.trim(), - }, + filter: input => input.trim() + } ]) - // configure basic auth const octokit = new Octokit({ auth: { @@ -115,8 +122,8 @@ async function getGitHubToken(opts) { password, async on2fa() { return promptForOTP() - }, - }, + } + } }) let response = await octokit.oauthAuthorizations.createAuthorization({ @@ -124,8 +131,8 @@ async function getGitHubToken(opts) { note_url: 'https://cli.netlify.com/', scopes: opts.scopes, headers: { - 'User-Agent': opts.userAgent, - }, + 'User-Agent': opts.userAgent + } }) if (get(response, 'data.token')) { diff --git a/src/utils/gitignore.js b/src/utils/gitignore.js index 51277f94d10..139a5cb45a1 100644 --- a/src/utils/gitignore.js +++ b/src/utils/gitignore.js @@ -7,7 +7,7 @@ const writeFile = promisify(fs.writeFile) function fileExists(filePath) { return new Promise((resolve, reject) => { - fs.access(filePath, fs.F_OK, (err) => { + fs.access(filePath, fs.F_OK, err => { if (err) return resolve(false) return resolve(true) }) @@ -42,7 +42,7 @@ function parser(input, fn = line => line) { } function stringify(state) { - return parseIgnore.stringify(state.sections, (section) => { + return parseIgnore.stringify(state.sections, section => { if (!section.patterns.length) { return '' } @@ -54,7 +54,7 @@ function stringify(state) { function parse(input, fn) { const state = parser(input, fn) - state.concat = (i) => { + state.concat = i => { const newState = parser(i, fn) for (let s2 in newState.sections) { @@ -88,7 +88,7 @@ async function ensureNetlifyIgnore(dir) { const ignoreContent = '# Local Netlify folder\n.netlify' /* No .gitignore file. Create one and ignore .netlify folder */ - if (!await hasGitIgnore(dir)) { + if (!(await hasGitIgnore(dir))) { await writeFile(gitIgnorePath, ignoreContent, 'utf8') return false } diff --git a/src/utils/link/link-by-prompt.js b/src/utils/link/link-by-prompt.js index 50a8ffb99e2..6b5c8077e1a 100644 --- a/src/utils/link/link-by-prompt.js +++ b/src/utils/link/link-by-prompt.js @@ -58,7 +58,9 @@ module.exports = async function linkPrompts(context) { const sites = await api.listSites({ filter: 'all' }) if (isEmpty(sites)) { - context.error(new Error(`You don't have any sites yet. Run ${chalk.cyanBright('netlify sites:create')} to create a site.`)) + context.error( + new Error(`You don't have any sites yet. Run ${chalk.cyanBright('netlify sites:create')} to create a site.`) + ) } const matchingSites = sites.filter(s => { @@ -92,9 +94,9 @@ Run ${chalk.cyanBright('git remote -v')} to see a list of your git remotes.`) type: 'list', name: 'selectedSite', message: 'Which site do you want to link?', - choices: matchingSites.map(site => ({ - name: `${site.name} - ${site.ssl_url}`, - value: site + choices: matchingSites.map(site => ({ + name: `${site.name} - ${site.ssl_url}`, + value: site })) } ]) diff --git a/src/utils/live-tunnel.js b/src/utils/live-tunnel.js index 5cd510eaa15..b0150340390 100644 --- a/src/utils/live-tunnel.js +++ b/src/utils/live-tunnel.js @@ -1,144 +1,128 @@ -const fetch = require("node-fetch"); -const fs = require("fs"); -const os = require("os"); -const path = require("path"); -const execa = require("execa"); -const chalk = require("chalk"); -const { fetchLatest, updateAvailable } = require("gh-release-fetch"); +const fetch = require('node-fetch') +const fs = require('fs') +const os = require('os') +const path = require('path') +const execa = require('execa') +const chalk = require('chalk') +const { fetchLatest, updateAvailable } = require('gh-release-fetch') const { NETLIFYDEVLOG, // NETLIFYDEVWARN, NETLIFYDEVERR -} = require("netlify-cli-logo"); +} = require('netlify-cli-logo') async function createTunnel(siteId, netlifyApiToken, log) { - await installTunnelClient(log); + await installTunnelClient(log) if (!siteId) { // eslint-disable-next-line no-console console.error( `${NETLIFYDEVERR} Error: no siteId defined, did you forget to run ${chalk.yellow( - "netlify init" - )} or ${chalk.yellow("netlify link")}?` - ); - process.exit(1); + 'netlify init' + )} or ${chalk.yellow('netlify link')}?` + ) + process.exit(1) } - log(`${NETLIFYDEVLOG} Creating Live Tunnel for ` + siteId); - const url = `https://api.netlify.com/api/v1/live_sessions?site_id=${siteId}`; + log(`${NETLIFYDEVLOG} Creating Live Tunnel for ` + siteId) + const url = `https://api.netlify.com/api/v1/live_sessions?site_id=${siteId}` const response = await fetch(url, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', Authorization: `Bearer ${netlifyApiToken}` }, body: JSON.stringify({}) - }); + }) - const data = await response.json(); + const data = await response.json() if (response.status !== 201) { - throw new Error(data.message); + throw new Error(data.message) } - return data; + return data } async function connectTunnel(session, netlifyApiToken, localPort, log) { - const execPath = path.join( - os.homedir(), - ".netlify", - "tunnel", - "bin", - "live-tunnel-client" - ); - const args = [ - "connect", - "-s", - session.id, - "-t", - netlifyApiToken, - "-l", - localPort - ]; + const execPath = path.join(os.homedir(), '.netlify', 'tunnel', 'bin', 'live-tunnel-client') + const args = ['connect', '-s', session.id, '-t', netlifyApiToken, '-l', localPort] if (process.env.DEBUG) { - args.push("-v"); - log(execPath, args); + args.push('-v') + log(execPath, args) } - const ps = execa(execPath, args, { stdio: "inherit" }); - ps.on("close", code => process.exit(code)); - ps.on("SIGINT", process.exit); - ps.on("SIGTERM", process.exit); + const ps = execa(execPath, args, { stdio: 'inherit' }) + ps.on('close', code => process.exit(code)) + ps.on('SIGINT', process.exit) + ps.on('SIGTERM', process.exit) } async function installTunnelClient(log) { - const win = isWindows(); - const binPath = path.join(os.homedir(), ".netlify", "tunnel", "bin"); - const execName = win ? "live-tunnel-client.exe" : "live-tunnel-client"; - const execPath = path.join(binPath, execName); - const newVersion = await fetchTunnelClient(execPath); + const win = isWindows() + const binPath = path.join(os.homedir(), '.netlify', 'tunnel', 'bin') + const execName = win ? 'live-tunnel-client.exe' : 'live-tunnel-client' + const execPath = path.join(binPath, execName) + const newVersion = await fetchTunnelClient(execPath) if (!newVersion) { - return; + return } - log(`${NETLIFYDEVLOG} Installing Live Tunnel Client`); + log(`${NETLIFYDEVLOG} Installing Live Tunnel Client`) - const platform = win ? "windows" : process.platform; - const extension = win ? "zip" : "tar.gz"; + const platform = win ? 'windows' : process.platform + const extension = win ? 'zip' : 'tar.gz' const release = { - repository: "netlify/live-tunnel-client", + repository: 'netlify/live-tunnel-client', package: `live-tunnel-client-${platform}-amd64.${extension}`, destination: binPath, extract: true - }; - await fetchLatest(release); + } + await fetchLatest(release) } async function fetchTunnelClient(execPath) { if (!execExist(execPath)) { - return true; + return true } - const { stdout } = await execa(execPath, ["version"]); + const { stdout } = await execa(execPath, ['version']) if (!stdout) { - return false; + return false } - const match = stdout.match(/^live-tunnel-client\/v?([^\s]+)/); + const match = stdout.match(/^live-tunnel-client\/v?([^\s]+)/) if (!match) { - return false; + return false } - return updateAvailable("netlify/live-tunnel-client", match[1]); + return updateAvailable('netlify/live-tunnel-client', match[1]) } function execExist(binPath) { if (!fs.existsSync(binPath)) { - return false; + return false } - const stat = fs.statSync(binPath); - return stat && stat.isFile() && isExe(stat.mode, stat.gid, stat.uid); + const stat = fs.statSync(binPath) + return stat && stat.isFile() && isExe(stat.mode, stat.gid, stat.uid) } function isExe(mode, gid, uid) { if (isWindows()) { - return true; + return true } - const isGroup = gid ? process.getgid && gid === process.getgid() : true; - const isUser = uid ? process.getuid && uid === process.getuid() : true; + const isGroup = gid ? process.getgid && gid === process.getgid() : true + const isUser = uid ? process.getuid && uid === process.getuid() : true - return Boolean( - mode & 0o0001 || (mode & 0o0010 && isGroup) || (mode & 0o0100 && isUser) - ); + return Boolean(mode & 0o0001 || (mode & 0o0010 && isGroup) || (mode & 0o0100 && isUser)) } function isWindows() { - return process.platform === "win32"; + return process.platform === 'win32' } module.exports = { createTunnel: createTunnel, connectTunnel: connectTunnel -}; +} diff --git a/src/utils/read-repo-url.js b/src/utils/read-repo-url.js index 09d6f4e1ba4..04db0dae5c8 100644 --- a/src/utils/read-repo-url.js +++ b/src/utils/read-repo-url.js @@ -1,9 +1,9 @@ -const url = require("url"); -const fetch = require("node-fetch"); -const { safeJoin } = require("safe-join"); +const url = require('url') +const fetch = require('node-fetch') +const { safeJoin } = require('safe-join') // supported repo host types -const GITHUB = Symbol("GITHUB"); +const GITHUB = Symbol('GITHUB') // const BITBUCKET = Symbol('BITBUCKET') // const GITLAB = Symbol('GITLAB') @@ -12,55 +12,45 @@ const GITHUB = Symbol("GITHUB"); * and returns https://api.github.com/repos/netlify-labs/all-the-functions/contents/functions/9-using-middleware */ async function readRepoURL(_url) { - const URL = url.parse(_url); - const repoHost = validateRepoURL(_url); - if (repoHost !== GITHUB) - throw new Error("only github repos are supported for now"); - const [owner_and_repo, contents_path] = parseRepoURL(repoHost, URL); - const folderContents = await getRepoURLContents( - repoHost, - owner_and_repo, - contents_path - ); - return folderContents; + const URL = url.parse(_url) + const repoHost = validateRepoURL(_url) + if (repoHost !== GITHUB) throw new Error('only github repos are supported for now') + const [owner_and_repo, contents_path] = parseRepoURL(repoHost, URL) + const folderContents = await getRepoURLContents(repoHost, owner_and_repo, contents_path) + return folderContents } async function getRepoURLContents(repoHost, owner_and_repo, contents_path) { // naive joining strategy for now if (repoHost === GITHUB) { // https://developer.github.com/v3/repos/contents/#get-contents - const APIURL = safeJoin( - "https://api.github.com/repos", - owner_and_repo, - "contents", - contents_path - ); + const APIURL = safeJoin('https://api.github.com/repos', owner_and_repo, 'contents', contents_path) return fetch(APIURL) .then(x => x.json()) .catch( - error => console.error("Error occurred while fetching ", APIURL, error) // eslint-disable-line no-console - ); + error => console.error('Error occurred while fetching ', APIURL, error) // eslint-disable-line no-console + ) } - throw new Error("unsupported host ", repoHost); + throw new Error('unsupported host ', repoHost) } function validateRepoURL(_url) { - const URL = url.parse(_url); - if (URL.host !== "github.com") return null; + const URL = url.parse(_url) + if (URL.host !== 'github.com') return null // other validation logic here - return GITHUB; + return GITHUB } function parseRepoURL(repoHost, URL) { // naive splitting strategy for now if (repoHost === GITHUB) { // https://developer.github.com/v3/repos/contents/#get-contents - const [owner_and_repo, contents_path] = URL.path.split("/tree/master"); // what if it's not master? note that our contents retrieval may assume it is master - return [owner_and_repo, contents_path]; + const [owner_and_repo, contents_path] = URL.path.split('/tree/master') // what if it's not master? note that our contents retrieval may assume it is master + return [owner_and_repo, contents_path] } - throw new Error("unsupported host ", repoHost); + throw new Error('unsupported host ', repoHost) } module.exports = { readRepoURL, validateRepoURL -}; +} diff --git a/src/utils/redirect-parser/common.js b/src/utils/redirect-parser/common.js index 9cf6a350ffe..378a9c600e2 100644 --- a/src/utils/redirect-parser/common.js +++ b/src/utils/redirect-parser/common.js @@ -17,10 +17,7 @@ module.exports = { return redirect.path.match(/^\/\.netlify/) }, isProxy: function(redirect) { - return ( - redirect.proxy || - (redirect.to.match(/^https?:\/\//) && redirect.status === 200) - ) + return redirect.proxy || (redirect.to.match(/^https?:\/\//) && redirect.status === 200) }, parseFullOrigin: function(origin) { let url = null @@ -33,7 +30,7 @@ module.exports = { return { host: url.host, scheme: url.protocol.replace(/:$/, ''), - path: url.path, + path: url.path } - }, + } } diff --git a/src/utils/redirect-parser/line-parser.js b/src/utils/redirect-parser/line-parser.js index bbe5dc8a667..b29298075ba 100644 --- a/src/utils/redirect-parser/line-parser.js +++ b/src/utils/redirect-parser/line-parser.js @@ -2,10 +2,7 @@ const Result = require('./result') const common = require('./common') function splatForwardRule(redirect, nextPart) { - return ( - redirect.path.match(/\/\*$/) && - nextPart.match(common.FORWARD_STATUS_MATCHER) - ) + return redirect.path.match(/\/\*$/) && nextPart.match(common.FORWARD_STATUS_MATCHER) } function arrayToObj(source) { @@ -38,9 +35,7 @@ function redirectMatch(line) { } const origin = parts.shift() - const redirect = origin.match(common.FULL_URL_MATCHER) - ? common.parseFullOrigin(origin) - : { path: origin } + const redirect = origin.match(common.FULL_URL_MATCHER) ? common.parseFullOrigin(origin) : { path: origin } if (redirect == null || !parts.length) { return null } @@ -48,9 +43,7 @@ function redirectMatch(line) { if (splatForwardRule(redirect, parts[0])) { redirect.to = redirect.path.replace(/\/\*$/, '/:splat') } else { - const newHostRuleIdx = parts.findIndex( - el => el.match(/^\//) || el.match(common.FULL_URL_MATCHER) - ) + const newHostRuleIdx = parts.findIndex(el => el.match(/^\//) || el.match(common.FULL_URL_MATCHER)) if (newHostRuleIdx < 0) { return null } @@ -107,7 +100,7 @@ function parse(text) { if (common.isInvalidSource(redirect)) { result.addError(idx, line, { - reason: 'Invalid /.netlify path in redirect source', + reason: 'Invalid /.netlify path in redirect source' }) return } diff --git a/src/utils/redirect-parser/line-parser.test.js b/src/utils/redirect-parser/line-parser.test.js index 2c00c7bfc0b..e8e9a053b12 100644 --- a/src/utils/redirect-parser/line-parser.test.js +++ b/src/utils/redirect-parser/line-parser.test.js @@ -18,7 +18,7 @@ test('simple redirects', t => { { path: '/home', to: '/' }, { path: '/blog/my-post.php', to: '/blog/my-post' }, { path: '/blog/my-post-ads.php', to: '/blog/my-post#ads' }, - { path: '/news', to: '/blog' }, + { path: '/news', to: '/blog' } ], result.success ) @@ -38,7 +38,7 @@ test('redirects with status codes', t => { { path: '/home', to: '/', status: 301 }, { path: '/my-redirect', to: '/', status: 302 }, { path: '/pass-through', to: '/', status: 200 }, - { path: '/ecommerce', to: '/store-closed', status: 404 }, + { path: '/ecommerce', to: '/store-closed', status: 404 } ], result.success ) @@ -59,8 +59,8 @@ test('redirects with parameter matches', t => { path: '/', to: '/about', params: { _escaped_fragment_: '/about' }, - status: 301, - }, + status: 301 + } ], result.success ) @@ -76,8 +76,8 @@ test('redirects with full hostname', t => { host: 'hello.bitballoon.com', scheme: 'http', path: '/*', - to: 'http://www.hello.com/:splat', - }, + to: 'http://www.hello.com/:splat' + } ], result.success ) @@ -93,8 +93,8 @@ test('proxy instruction', t => { path: '/api/*', to: 'https://api.bitballoon.com/*', status: 200, - proxy: true, - }, + proxy: true + } ], result.success ) @@ -110,8 +110,8 @@ test('redirect with country conditions', t => { path: '/', to: '/china', status: 302, - conditions: { Country: 'ch,tw' }, - }, + conditions: { Country: 'ch,tw' } + } ], result.success ) @@ -127,8 +127,8 @@ test('redirect with country and language conditions', t => { path: '/', to: '/china', status: 302, - conditions: { Country: 'il', Language: 'en' }, - }, + conditions: { Country: 'il', Language: 'en' } + } ], result.success ) @@ -138,10 +138,7 @@ test('splat based redirect with no force instruction', t => { const source = `/* https://www.bitballoon.com/:splat 301` const result = parser.parse(source) - t.deepEqual( - [{ path: '/*', to: 'https://www.bitballoon.com/:splat', status: 301 }], - result.success - ) + t.deepEqual([{ path: '/*', to: 'https://www.bitballoon.com/:splat', status: 301 }], result.success) }) test('splat based redirect with force instruction', t => { @@ -154,8 +151,8 @@ test('splat based redirect with force instruction', t => { path: '/*', to: 'https://www.bitballoon.com/:splat', status: 301, - force: true, - }, + force: true + } ], result.success ) @@ -170,8 +167,8 @@ test('redirect rule with equal', t => { { path: '/test', to: 'https://www.bitballoon.com/test=hello', - status: 301, - }, + status: 301 + } ], result.success ) @@ -187,9 +184,9 @@ test('some real world edge case rules', t => { to: '/donate/usa?source=:source&email=:email', params: { source: ':source', email: ':email' }, status: 302, - conditions: { Country: 'us' }, - }, - ], + conditions: { Country: 'us' } + } + ] }, { source: `/ https://origin.wework.com 200`, @@ -198,16 +195,14 @@ test('some real world edge case rules', t => { path: '/', to: 'https://origin.wework.com', status: 200, - proxy: true, - }, - ], + proxy: true + } + ] }, { source: `/:lang/locations/* /locations/:splat 200`, - result: [ - { path: '/:lang/locations/*', to: '/locations/:splat', status: 200 }, - ], - }, + result: [{ path: '/:lang/locations/*', to: '/locations/:splat', status: 200 }] + } ] cases.forEach(testcase => { const result = parser.parse(testcase.source) @@ -277,14 +272,11 @@ test('complicated _redirects file', t => { test('long _redirects file', t => { const source = fs.readFileSync(__dirname + '/test-files/redirects', { - encoding: 'utf-8', + encoding: 'utf-8' }) const result = parser.parse(source) - t.deepEqual( - [640, 734, 917, 918, 919, 920, 987], - result.errors.map(e => e.lineNum) - ) + t.deepEqual([640, 734, 917, 918, 919, 920, 987], result.errors.map(e => e.lineNum)) t.truthy(result.success.length > 0) }) @@ -299,7 +291,7 @@ test('redirect with proxy signing', t => { status: 200, force: true, signed: 'API_SECRET', - proxy: true, + proxy: true }, result.success[0] ) @@ -327,7 +319,7 @@ https://www.ximble.com/* https://www.ximble.com/au/:splat 301! Country=au to: 'https://www.ximble.com/au/:splat', status: 301, force: true, - conditions: { Country: 'au' }, + conditions: { Country: 'au' } }, result.success[0] ) @@ -343,8 +335,8 @@ test('redirect role conditions', t => { path: '/admin/*', to: '/admin/:splat', status: 200, - conditions: { Role: 'admin' }, - }, + conditions: { Role: 'admin' } + } ], result.success ) @@ -360,8 +352,8 @@ test('redirect with multiple roles', t => { path: '/member/*', to: '/member/:splat', status: 200, - conditions: { Role: 'admin,member' }, - }, + conditions: { Role: 'admin,member' } + } ], result.success ) @@ -376,7 +368,7 @@ test('parse forward rule', t => { t.deepEqual( [ { path: '/admin/*', to: '/admin/:splat', status: 200 }, - { path: '/admin/*', to: '/admin/:splat', status: 200, force: true }, + { path: '/admin/*', to: '/admin/:splat', status: 200, force: true } ], result.success ) diff --git a/src/utils/redirect-parser/result.js b/src/utils/redirect-parser/result.js index 6da73cf120b..91a85048ab5 100644 --- a/src/utils/redirect-parser/result.js +++ b/src/utils/redirect-parser/result.js @@ -13,7 +13,7 @@ class Result { this.errors.push({ lineNum: idx + 1, line, - reason, + reason }) } } diff --git a/src/utils/redirect-parser/toml-parser.js b/src/utils/redirect-parser/toml-parser.js index 6788bdef3b9..80134a4bd16 100644 --- a/src/utils/redirect-parser/toml-parser.js +++ b/src/utils/redirect-parser/toml-parser.js @@ -3,14 +3,7 @@ const Result = require('./result') const common = require('./common') function splatForwardRule(path, obj, dest) { - return ( - path.match(/\/\*$/) && - dest == null && - obj.status && - obj.status >= 200 && - obj.status < 300 && - obj.force - ) + return path.match(/\/\*$/) && dest == null && obj.status && obj.status >= 200 && obj.status < 300 && obj.force } function isPlainObj(o) { @@ -28,10 +21,7 @@ function fetch(obj, options) { function redirectMatch(obj) { const origin = fetch(obj, ['from', 'origin']) - const redirect = - origin && origin.match(common.FULL_URL_MATCHER) - ? common.parseFullOrigin(origin) - : { path: origin } + const redirect = origin && origin.match(common.FULL_URL_MATCHER) ? common.parseFullOrigin(origin) : { path: origin } if (redirect == null || (redirect.path == null && redirect.host == null)) { return null } @@ -89,7 +79,7 @@ function parse(source) { if (common.isInvalidSource(redirect)) { result.addError(idx, JSON.stringify(obj), { - reason: 'Invalid /.netlify path in redirect source', + reason: 'Invalid /.netlify path in redirect source' }) return } diff --git a/src/utils/redirect-parser/toml-parser.test.js b/src/utils/redirect-parser/toml-parser.test.js index bdaa23404cb..63cc528148a 100644 --- a/src/utils/redirect-parser/toml-parser.test.js +++ b/src/utils/redirect-parser/toml-parser.test.js @@ -16,7 +16,7 @@ redirects = [ { path: '/home', to: '/' }, { path: '/admin/*', to: '/admin/:splat', status: 200, force: true }, { path: '/index', to: '/', status: 302 }, - { path: '/from', to: '/to', status: 302 }, + { path: '/from', to: '/to', status: 302 } ], result.success ) @@ -40,8 +40,8 @@ test('redirects with parameter matches', t => { path: '/', to: '/about', params: { _escaped_fragment_: '/about' }, - status: 301, - }, + status: 301 + } ], result.success ) @@ -61,8 +61,8 @@ redirects = [ host: 'hello.bitballoon.com', scheme: 'http', path: '/*', - to: 'http://www.hello.com/:splat', - }, + to: 'http://www.hello.com/:splat' + } ], result.success ) @@ -82,8 +82,8 @@ test('proxy instruction', t => { path: '/api/*', to: 'https://api.bitballoon.com/*', status: 200, - proxy: true, - }, + proxy: true + } ], result.success ) @@ -104,8 +104,8 @@ test('headers on proxy rule', t => { to: 'https://api.bitballoon.com', status: 200, headers: { anything: 'something' }, - proxy: true, - }, + proxy: true + } ], result.success ) @@ -126,14 +126,14 @@ test('redirect country conditions', t => { path: '/', to: '/china', status: 302, - conditions: { Country: ['ch', 'tw'] }, + conditions: { Country: ['ch', 'tw'] } }, { path: '/', to: '/china', status: 302, - conditions: { Country: ['il'], Language: ['en'] }, - }, + conditions: { Country: ['il'], Language: ['en'] } + } ], result.success ) @@ -166,14 +166,14 @@ test('redirect role conditions', t => { path: '/admin/*', to: '/admin/:splat', status: 200, - conditions: { Role: ['admin'] }, + conditions: { Role: ['admin'] } }, { path: '/admin/*', to: '/admin/:splat', status: 200, - conditions: { Role: ['admin', 'member'] }, - }, + conditions: { Role: ['admin', 'member'] } + } ], result.success ) diff --git a/src/utils/rules-proxy.js b/src/utils/rules-proxy.js index 034e1cb0c90..f24b31a9f35 100644 --- a/src/utils/rules-proxy.js +++ b/src/utils/rules-proxy.js @@ -6,11 +6,7 @@ const chokidar = require('chokidar') const proxy = require('http-proxy-middleware') const cookie = require('cookie') const redirectParser = require('./redirect-parser') -const { - NETLIFYDEVLOG, - NETLIFYDEVERR, - NETLIFYDEVWARN, -} = require('netlify-cli-logo') +const { NETLIFYDEVLOG, NETLIFYDEVERR, NETLIFYDEVWARN } = require('netlify-cli-logo') function isExternal(match) { return match.to && match.to.match(/^https?:\/\//) @@ -37,44 +33,28 @@ function parseRules(projectDir, publicDir) { const generatedRedirectsPath = path.resolve(publicDir, '_redirects') if (fs.existsSync(generatedRedirectsPath)) { rules = rules.concat( - parseFile( - redirectParser.parseRedirectsFormat, - '_redirects', - fs.readFileSync(generatedRedirectsPath, 'utf-8') - ) + parseFile(redirectParser.parseRedirectsFormat, '_redirects', fs.readFileSync(generatedRedirectsPath, 'utf-8')) ) } const baseRedirectsPath = path.resolve(projectDir, '_redirects') if (fs.existsSync(baseRedirectsPath)) { rules = rules.concat( - parseFile( - redirectParser.parseRedirectsFormat, - '_redirects', - fs.readFileSync(baseRedirectsPath, 'utf-8') - ) + parseFile(redirectParser.parseRedirectsFormat, '_redirects', fs.readFileSync(baseRedirectsPath, 'utf-8')) ) } const generatedTOMLPath = path.resolve(projectDir, 'netlify.toml') if (fs.existsSync(generatedTOMLPath)) { rules = rules.concat( - parseFile( - redirectParser.parseTomlFormat, - 'generated netlify.toml', - fs.readFileSync(generatedTOMLPath, 'utf-8') - ) + parseFile(redirectParser.parseTomlFormat, 'generated netlify.toml', fs.readFileSync(generatedTOMLPath, 'utf-8')) ) } const baseTOMLPath = path.resolve(projectDir, 'netlify.toml') if (fs.existsSync(baseTOMLPath)) { rules = rules.concat( - parseFile( - redirectParser.parseTomlFormat, - 'base netlify.toml', - fs.readFileSync(baseTOMLPath, 'utf-8') - ) + parseFile(redirectParser.parseTomlFormat, 'base netlify.toml', fs.readFileSync(baseTOMLPath, 'utf-8')) ) } return rules @@ -104,28 +84,32 @@ module.exports = function(config) { let matcher = null const projectDir = path.resolve(config.baseFolder || process.cwd()) - onChanges([ - path.resolve(projectDir, 'netlify.toml'), - path.resolve(projectDir, '_redirects'), - path.resolve(config.publicFolder, 'netlify.toml'), - path.resolve(config.publicFolder, '_redirects'), - ], () => { - matcher = null - }) + onChanges( + [ + path.resolve(projectDir, 'netlify.toml'), + path.resolve(projectDir, '_redirects'), + path.resolve(config.publicFolder, 'netlify.toml'), + path.resolve(config.publicFolder, '_redirects') + ], + () => { + matcher = null + } + ) const getMatcher = () => { if (matcher) { return Promise.resolve(matcher) } - const rules = parseRules(projectDir, config.publicFolder) - .filter(r => !(r.path === '/*' && r.to === '/index.html' && r.status === 200)) + const rules = parseRules(projectDir, config.publicFolder).filter( + r => !(r.path === '/*' && r.to === '/index.html' && r.status === 200) + ) if (rules.length) { return redirector .parseJSON(JSON.stringify(rules), { jwtSecret: config.jwtSecret || 'secret', - jwtRole: config.jwtRole || 'app_metadata.authorization.roles', + jwtRole: config.jwtRole || 'app_metadata.authorization.roles' }) .then(m => { matcher = m @@ -135,7 +119,7 @@ module.exports = function(config) { return Promise.resolve({ match() { return null - }, + } }) } @@ -157,7 +141,7 @@ module.exports = function(config) { const reqUrl = new url.URL( req.url, `${req.protocol || (req.headers.scheme && req.headers.scheme + ':') || 'http:'}//${req.hostname || - req.headers['host']}` + req.headers['host']}` ) const cookies = cookie.parse(req.headers.cookie || '') const matchReq = { @@ -171,8 +155,8 @@ module.exports = function(config) { ({ 'x-language': cookies.nf_lang || getLanguage(req), 'x-country': cookies.nf_country || getCountry(req), - ...req.headers, - }[name.toLowerCase()]), + ...req.headers + }[name.toLowerCase()]) } const match = matcher.match(matchReq) @@ -184,17 +168,14 @@ module.exports = function(config) { } if (match.force || notStatic(reqUrl.pathname)) { - const dest = new url.URL( - match.to, - `${reqUrl.protocol}//${reqUrl.host}` - ) + const dest = new url.URL(match.to, `${reqUrl.protocol}//${reqUrl.host}`) reqUrl.searchParams.forEach((v, k) => { dest.searchParams.append(k, v) }) if (isRedirect(match)) { res.writeHead(match.status, { Location: match.to, - 'Cache-Control': 'no-cache', + 'Cache-Control': 'no-cache' }) res.end(`Redirecting to ${match.to}`) return @@ -205,8 +186,7 @@ module.exports = function(config) { const handler = proxy({ target: `${dest.protocol}//${dest.host}`, changeOrigin: true, - pathRewrite: (path, req) => - match.to.replace(/https?:\/\/[^\/]+/, ''), + pathRewrite: (path, req) => match.to.replace(/https?:\/\/[^\/]+/, '') }) return handler(req, res, next) } else { diff --git a/src/utils/serve-functions.js b/src/utils/serve-functions.js index 7a710069038..c98a4b1877a 100644 --- a/src/utils/serve-functions.js +++ b/src/utils/serve-functions.js @@ -1,26 +1,24 @@ -const express = require("express"); -const bodyParser = require("body-parser"); -const expressLogging = require("express-logging"); -const queryString = require("querystring"); -const getPort = require("get-port"); -const chokidar = require("chokidar"); -const jwtDecode = require("jwt-decode"); +const express = require('express') +const bodyParser = require('body-parser') +const expressLogging = require('express-logging') +const queryString = require('querystring') +const getPort = require('get-port') +const chokidar = require('chokidar') +const jwtDecode = require('jwt-decode') const { NETLIFYDEVLOG, // NETLIFYDEVWARN, NETLIFYDEVERR -} = require("netlify-cli-logo"); -const { getFunctions } = require("./get-functions"); +} = require('netlify-cli-logo') +const { getFunctions } = require('./get-functions') -const defaultPort = 34567; +const defaultPort = 34567 function handleErr(err, response) { - response.statusCode = 500; - response.write( - `${NETLIFYDEVERR} Function invocation failed: ` + err.toString() - ); - response.end(); - console.log(`${NETLIFYDEVERR} Error during invocation: `, err); // eslint-disable-line no-console + response.statusCode = 500 + response.write(`${NETLIFYDEVERR} Function invocation failed: ` + err.toString()) + response.end() + console.log(`${NETLIFYDEVERR} Error during invocation: `, err) // eslint-disable-line no-console } // function getHandlerPath(functionPath) { @@ -32,18 +30,17 @@ function handleErr(err, response) { function buildClientContext(headers) { // inject a client context based on auth header, ported over from netlify-lambda (https://github.com/netlify/netlify-lambda/pull/57) - if (!headers.authorization) return; + if (!headers.authorization) return - const parts = headers.authorization.split(" "); - if (parts.length !== 2 || parts[0] !== "Bearer") return; + const parts = headers.authorization.split(' ') + if (parts.length !== 2 || parts[0] !== 'Bearer') return try { return { identity: { - url: - "https://netlify-dev-locally-emulated-identity.netlify.com/.netlify/identity", + url: 'https://netlify-dev-locally-emulated-identity.netlify.com/.netlify/identity', token: - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb3VyY2UiOiJuZXRsaWZ5IGRldiIsInRlc3REYXRhIjoiTkVUTElGWV9ERVZfTE9DQUxMWV9FTVVMQVRFRF9JREVOVElUWSJ9.2eSDqUOZAOBsx39FHFePjYj12k0LrxldvGnlvDu3GMI" + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb3VyY2UiOiJuZXRsaWZ5IGRldiIsInRlc3REYXRhIjoiTkVUTElGWV9ERVZfTE9DQUxMWV9FTVVMQVRFRF9JREVOVElUWSJ9.2eSDqUOZAOBsx39FHFePjYj12k0LrxldvGnlvDu3GMI' // you can decode this with https://jwt.io/ // just says // { @@ -52,61 +49,61 @@ function buildClientContext(headers) { // } }, user: jwtDecode(parts[1]) - }; + } } catch (_) { // Ignore errors - bearer token is not a JWT, probably not intended for us } } function createHandler(dir) { - const functions = getFunctions(dir); + const functions = getFunctions(dir) const clearCache = action => path => { - console.log(`${NETLIFYDEVLOG} ${path} ${action}, reloading...`); // eslint-disable-line no-console + console.log(`${NETLIFYDEVLOG} ${path} ${action}, reloading...`) // eslint-disable-line no-console Object.keys(require.cache).forEach(k => { - delete require.cache[k]; - }); - }; - const watcher = chokidar.watch(dir, { ignored: /node_modules/ }); - watcher - .on("change", clearCache("modified")) - .on("unlink", clearCache("deleted")); + delete require.cache[k] + }) + } + const watcher = chokidar.watch(dir, { ignored: /node_modules/ }) + watcher.on('change', clearCache('modified')).on('unlink', clearCache('deleted')) return function(request, response) { // handle proxies without path re-writes (http-servr) - const cleanPath = request.path.replace(/^\/.netlify\/functions/, ""); + const cleanPath = request.path.replace(/^\/.netlify\/functions/, '') - const func = cleanPath.split("/").filter(function(e) { - return e; - })[0]; + const func = cleanPath.split('/').filter(function(e) { + return e + })[0] if (!functions[func]) { - response.statusCode = 404; - response.end("Function not found..."); - return; + response.statusCode = 404 + response.end('Function not found...') + return } - const { functionPath, moduleDir } = functions[func]; - let handler; - let before = module.paths; + const { functionPath, moduleDir } = functions[func] + let handler + let before = module.paths try { - module.paths = [moduleDir]; - handler = require(functionPath); - if (typeof handler.handler !== "function") { - throw new Error( - `function ${functionPath} must export a function named handler` - ); + module.paths = [moduleDir] + handler = require(functionPath) + if (typeof handler.handler !== 'function') { + throw new Error(`function ${functionPath} must export a function named handler`) } - module.paths = before; + module.paths = before } catch (error) { - module.paths = before; - handleErr(error, response); - return; + module.paths = before + handleErr(error, response) + return } - const body = request.body.toString(); - var isBase64Encoded = Buffer.from(body, 'base64').toString('base64') === body; + const body = request.body.toString() + var isBase64Encoded = Buffer.from(body, 'base64').toString('base64') === body - let remoteAddress = (request.headers['x-forwarded-for'] || request.headers['X-Forwarded-for'] || request.connection.remoteAddress || '') - remoteAddress = remoteAddress.split(remoteAddress.includes('.') ? ':' : ',').pop().trim() + let remoteAddress = + request.headers['x-forwarded-for'] || request.headers['X-Forwarded-for'] || request.connection.remoteAddress || '' + remoteAddress = remoteAddress + .split(remoteAddress.includes('.') ? ':' : ',') + .pop() + .trim() const lambdaRequest = { path: request.path, @@ -115,142 +112,133 @@ function createHandler(dir) { headers: Object.assign({}, request.headers, { 'client-ip': remoteAddress }), body: body, isBase64Encoded: isBase64Encoded - }; + } - let callbackWasCalled = false; - const callback = createCallback(response); + let callbackWasCalled = false + const callback = createCallback(response) // we already checked that it exports a function named handler above const promise = handler.handler( lambdaRequest, { clientContext: buildClientContext(request.headers) || {} }, callback - ); + ) /** guard against using BOTH async and callback */ - if (callbackWasCalled && promise && typeof promise.then === "function") { + if (callbackWasCalled && promise && typeof promise.then === 'function') { throw new Error( - "Error: your function seems to be using both a callback and returning a promise (aka async function). This is invalid, pick one. (Hint: async!)" - ); + 'Error: your function seems to be using both a callback and returning a promise (aka async function). This is invalid, pick one. (Hint: async!)' + ) } else { // it is definitely an async function with no callback called, good. - promiseCallback(promise, callback); + promiseCallback(promise, callback) } /** need to keep createCallback in scope so we can know if cb was called AND handler is async */ function createCallback(response) { return function(err, lambdaResponse) { - callbackWasCalled = true; + callbackWasCalled = true if (err) { - return handleErr(err, response); + return handleErr(err, response) } if (lambdaResponse === undefined) { - return handleErr( - "lambda response was undefined. check your function code again.", - response - ); + return handleErr('lambda response was undefined. check your function code again.', response) } if (!Number(lambdaResponse.statusCode)) { console.log( `${NETLIFYDEVERR} Your function response must have a numerical statusCode. You gave: $`, lambdaResponse.statusCode - ); - return handleErr("Incorrect function response statusCode", response); + ) + return handleErr('Incorrect function response statusCode', response) } - if (typeof lambdaResponse.body !== "string") { - console.log( - `${NETLIFYDEVERR} Your function response must have a string body. You gave:`, - lambdaResponse.body - ); - return handleErr("Incorrect function response body", response); + if (typeof lambdaResponse.body !== 'string') { + console.log(`${NETLIFYDEVERR} Your function response must have a string body. You gave:`, lambdaResponse.body) + return handleErr('Incorrect function response body', response) } - response.statusCode = lambdaResponse.statusCode; + response.statusCode = lambdaResponse.statusCode // eslint-disable-line guard-for-in for (const key in lambdaResponse.headers) { - response.setHeader(key, lambdaResponse.headers[key]); + response.setHeader(key, lambdaResponse.headers[key]) } for (const key in lambdaResponse.multiValueHeaders) { - const items = lambdaResponse.multiValueHeaders[key]; - response.setHeader(key, items); + const items = lambdaResponse.multiValueHeaders[key] + response.setHeader(key, items) } response.write( - lambdaResponse.isBase64Encoded - ? Buffer.from(lambdaResponse.body, "base64") - : lambdaResponse.body - ); - response.end(); - }; + lambdaResponse.isBase64Encoded ? Buffer.from(lambdaResponse.body, 'base64') : lambdaResponse.body + ) + response.end() + } } - }; + } } function promiseCallback(promise, callback) { - if (!promise) return; // means no handler was written - if (typeof promise.then !== "function") return; - if (typeof callback !== "function") return; + if (!promise) return // means no handler was written + if (typeof promise.then !== 'function') return + if (typeof callback !== 'function') return promise.then( function(data) { - callback(null, data); + callback(null, data) }, function(err) { - callback(err, null); + callback(err, null) } - ); + ) } async function serveFunctions(settings) { - const app = express(); - const dir = settings.functionsDir; + const app = express() + const dir = settings.functionsDir const port = await getPort({ port: assignLoudly(settings.port, defaultPort) - }); + }) app.use( bodyParser.text({ - limit: "6mb", - type: ["text/*", "application/json", "multipart/form-data"] + limit: '6mb', + type: ['text/*', 'application/json', 'multipart/form-data'] }) - ); - app.use(bodyParser.raw({ limit: "6mb", type: "*/*" })); + ) + app.use(bodyParser.raw({ limit: '6mb', type: '*/*' })) app.use( expressLogging(console, { - blacklist: ["/favicon.ico"] + blacklist: ['/favicon.ico'] }) - ); + ) - app.get("/favicon.ico", function(req, res) { - res.status(204).end(); - }); - app.all("*", createHandler(dir)); + app.get('/favicon.ico', function(req, res) { + res.status(204).end() + }) + app.all('*', createHandler(dir)) app.listen(port, function(err) { if (err) { - console.error(`${NETLIFYDEVERR} Unable to start lambda server: `, err); // eslint-disable-line no-console - process.exit(1); + console.error(`${NETLIFYDEVERR} Unable to start lambda server: `, err) // eslint-disable-line no-console + process.exit(1) } // add newline because this often appears alongside the client devserver's output - console.log(`\n${NETLIFYDEVLOG} Lambda server is listening on ${port}`); // eslint-disable-line no-console - }); + console.log(`\n${NETLIFYDEVLOG} Lambda server is listening on ${port}`) // eslint-disable-line no-console + }) return Promise.resolve({ port - }); + }) } -module.exports = { serveFunctions }; +module.exports = { serveFunctions } // if first arg is undefined, use default, but tell user about it in case it is unintentional function assignLoudly( optionalValue, fallbackValue, - tellUser = dV => - console.log(`${NETLIFYDEVLOG} No port specified, using defaultPort of `, dV) // eslint-disable-line no-console + tellUser = dV => console.log(`${NETLIFYDEVLOG} No port specified, using defaultPort of `, dV) // eslint-disable-line no-console ) { - if (fallbackValue === undefined) throw new Error("must have a fallbackValue"); + if (fallbackValue === undefined) throw new Error('must have a fallbackValue') if (fallbackValue !== optionalValue && optionalValue === undefined) { - tellUser(fallbackValue); - return fallbackValue; + tellUser(fallbackValue) + return fallbackValue } - return optionalValue; + return optionalValue } diff --git a/src/utils/telemetry/validation.js b/src/utils/telemetry/validation.js index d3672061529..99db077012e 100644 --- a/src/utils/telemetry/validation.js +++ b/src/utils/telemetry/validation.js @@ -2,7 +2,7 @@ * Utility to validating analytic event names for clean data */ - module.exports = function isValidEventName(eventName, config) { +module.exports = function isValidEventName(eventName, config) { const validProject = [config.projectName] || [] const validObjects = config.objects || [] const matches = eventName.match(/([a-zA-Z]*):([a-zA-Z]*)_([a-zA-Z]*$)/) @@ -28,20 +28,20 @@ return formattingWarning(eventName, error) } return true - } +} function containsSeparators(eventName) { - const underscores = (eventName.match(/_/g) || []).length - if (underscores !== 1) { - console.log(`Event name must have single underscore. "${eventName}" contains ${underscores}`) // eslint-disable-line - return false - } - const colons = (eventName.match(/:/g) || []).length - if (colons !== 1) { - console.log(`Event name must have single colon. "${eventName}" contains ${colons}`) // eslint-disable-line - return false - } - return true + const underscores = (eventName.match(/_/g) || []).length + if (underscores !== 1) { + console.log(`Event name must have single underscore. "${eventName}" contains ${underscores}`) // eslint-disable-line + return false + } + const colons = (eventName.match(/:/g) || []).length + if (colons !== 1) { + console.log(`Event name must have single colon. "${eventName}" contains ${colons}`) // eslint-disable-line + return false + } + return true } function formattingWarning(eventName, errorMsg) {