chore: drop Node.js v6 support (#5045)

Node.js v6 was end-of-life'd in April, 2019, with AWS Lambda prohibiting updaets to the Node.js v6 runtime since June 30, 2019.

This makes it quite safe for us to remove the Node 6 support from the repository.
This commit is contained in:
Mathias Bynens 2019-10-16 17:00:20 +02:00 committed by GitHub
parent c0ba8f9a19
commit 11ff374ca3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 48 additions and 494 deletions

View File

@ -1,8 +1,6 @@
environment: environment:
matrix: matrix:
- nodejs_version: "6.12.3" - nodejs_version: "8.16.0"
FLAKINESS_DASHBOARD_NAME: Appveyor Chromium (Win + node6)
- nodejs_version: "8.11.3"
FLAKINESS_DASHBOARD_NAME: Appveyor Chromium (Win + node8) FLAKINESS_DASHBOARD_NAME: Appveyor Chromium (Win + node8)
FLAKINESS_DASHBOARD_PASSWORD: FLAKINESS_DASHBOARD_PASSWORD:
secure: g66jP+j6C+hkXLutBV9fdxB5fRJgcQQzy93SgQzXUmcCl/RjkJwnzyHvX0xfCVnv secure: g66jP+j6C+hkXLutBV9fdxB5fRJgcQQzy93SgQzXUmcCl/RjkJwnzyHvX0xfCVnv
@ -13,11 +11,9 @@ install:
- ps: $env:FLAKINESS_DASHBOARD_BUILD_URL="https://ci.appveyor.com/project/aslushnikov/puppeteer/builds/$env:APPVEYOR_BUILD_ID/job/$env:APPVEYOR_JOB_ID" - ps: $env:FLAKINESS_DASHBOARD_BUILD_URL="https://ci.appveyor.com/project/aslushnikov/puppeteer/builds/$env:APPVEYOR_BUILD_ID/job/$env:APPVEYOR_JOB_ID"
- ps: Install-Product node $env:nodejs_version - ps: Install-Product node $env:nodejs_version
- npm install - npm install
- if "%nodejs_version%" == "8.11.3" ( - if "%nodejs_version%" == "8.16.0" (
npm run lint && npm run lint &&
npm run coverage && npm run coverage &&
npm run test-doclint && npm run test-doclint &&
npm run test-types npm run test-types
) else (
npm run unit-node6
) )

View File

@ -1,17 +0,0 @@
FROM node:6.12.3
RUN apt-get update && \
apt-get -y install xvfb gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 \
libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 \
libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 \
libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 \
libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget && \
rm -rf /var/lib/apt/lists/*
# Add user so we don't need --no-sandbox.
RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
&& mkdir -p /home/pptruser/Downloads \
&& chown -R pptruser:pptruser /home/pptruser
# Run everything after as non-privileged user.
USER pptruser

View File

@ -4,15 +4,6 @@ env:
FLAKINESS_DASHBOARD_NAME: Cirrus ${CIRRUS_TASK_NAME} FLAKINESS_DASHBOARD_NAME: Cirrus ${CIRRUS_TASK_NAME}
FLAKINESS_DASHBOARD_BUILD_URL: https://cirrus-ci.com/task/${CIRRUS_TASK_ID} FLAKINESS_DASHBOARD_BUILD_URL: https://cirrus-ci.com/task/${CIRRUS_TASK_ID}
task:
matrix:
- name: Chromium (node6 + linux)
container:
dockerfile: .ci/node6/Dockerfile.linux
xvfb_start_background_script: Xvfb :99 -ac -screen 0 1024x768x24
install_script: npm install --unsafe-perm
test_script: npm run unit-node6
task: task:
matrix: matrix:
- name: Chromium (node8 + linux) - name: Chromium (node8 + linux)

View File

@ -24,24 +24,18 @@ script:
- 'if [ "$NODE8" = "true" ]; then npm run test-types; fi' - 'if [ "$NODE8" = "true" ]; then npm run test-types; fi'
- 'if [ "$NODE8" = "true" ]; then npm run bundle; fi' - 'if [ "$NODE8" = "true" ]; then npm run bundle; fi'
- 'if [ "$NODE8" = "true" ]; then npm run unit-bundle; fi' - 'if [ "$NODE8" = "true" ]; then npm run unit-bundle; fi'
- 'if [ "$NODE6" = "true" ]; then npm run unit-node6; fi'
jobs: jobs:
include: include:
- node_js: "8.11.3" - node_js: "8.16.0"
env: env:
- NODE8=true - NODE8=true
- FLAKINESS_DASHBOARD_NAME="Travis Chromium (node8 + linux)" - FLAKINESS_DASHBOARD_NAME="Travis Chromium (node8 + linux)"
- FLAKINESS_DASHBOARD_BUILD_URL="${TRAVIS_JOB_WEB_URL}" - FLAKINESS_DASHBOARD_BUILD_URL="${TRAVIS_JOB_WEB_URL}"
- node_js: "8.11.3" - node_js: "8.16.0"
env: env:
- FIREFOX=true - FIREFOX=true
- FLAKINESS_DASHBOARD_NAME="Travis Firefox (node8 + linux)" - FLAKINESS_DASHBOARD_NAME="Travis Firefox (node8 + linux)"
- FLAKINESS_DASHBOARD_BUILD_URL="${TRAVIS_JOB_WEB_URL}" - FLAKINESS_DASHBOARD_BUILD_URL="${TRAVIS_JOB_WEB_URL}"
- node_js: "6.12.3"
env:
- NODE6=true
- FLAKINESS_DASHBOARD_NAME="Travis Chromium (node6 + linux)"
- FLAKINESS_DASHBOARD_BUILD_URL="${TRAVIS_JOB_WEB_URL}"
before_deploy: "npm run apply-next-version" before_deploy: "npm run apply-next-version"
deploy: deploy:
provider: npm provider: npm

View File

@ -14,15 +14,4 @@
* limitations under the License. * limitations under the License.
*/ */
let asyncawait = true;
try {
new Function('async function test(){await 1}');
} catch (error) {
asyncawait = false;
}
// If node does not support async await, use the compiled version.
if (asyncawait)
module.exports = require('./lib/DeviceDescriptors'); module.exports = require('./lib/DeviceDescriptors');
else
module.exports = require('./node6/lib/DeviceDescriptors');

View File

@ -14,15 +14,4 @@
* limitations under the License. * limitations under the License.
*/ */
let asyncawait = true;
try {
new Function('async function test(){await 1}');
} catch (error) {
asyncawait = false;
}
// If node does not support async await, use the compiled version.
if (asyncawait)
module.exports = require('./lib/Errors'); module.exports = require('./lib/Errors');
else
module.exports = require('./node6/lib/Errors');

View File

@ -57,7 +57,10 @@ See [puppeteer vs puppeteer-core](https://github.com/GoogleChrome/puppeteer/blob
### Usage ### Usage
Note: Puppeteer requires at least Node v6.4.0, but the examples below use async/await which is only supported in Node v7.6.0 or greater. Puppeteer follows the latest [maintenance LTS](https://github.com/nodejs/Release#release-schedule) version of Node.
Note: Prior to v1.18.1, Puppeteer required at least Node v6.4.0. All subsequent versions rely on
Node 8.9.0+. All examples below use async/await which is only supported in Node v7.6.0 or greater.
Puppeteer will be familiar to people using other browser testing frameworks. You create an instance Puppeteer will be familiar to people using other browser testing frameworks. You create an instance
of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/GoogleChrome/puppeteer/blob/v1.20.0/docs/api.md#). of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/GoogleChrome/puppeteer/blob/v1.20.0/docs/api.md#).

View File

@ -14,15 +14,4 @@
* limitations under the License. * limitations under the License.
*/ */
let asyncawait = true;
try {
new Function('async function test(){await 1}');
} catch (error) {
asyncawait = false;
}
// If node does not support async await, use the compiled version.
if (asyncawait)
module.exports = require('./lib/DeviceDescriptors'); module.exports = require('./lib/DeviceDescriptors');
else
module.exports = require('./node6/lib/DeviceDescriptors');

View File

@ -4,7 +4,6 @@ const {Dialog} = require('./Dialog');
const {TimeoutError} = require('./Errors'); const {TimeoutError} = require('./Errors');
const fs = require('fs'); const fs = require('fs');
const mime = require('mime'); const mime = require('mime');
const util = require('util');
const EventEmitter = require('events'); const EventEmitter = require('events');
const {createHandle} = require('./JSHandle'); const {createHandle} = require('./JSHandle');
const {Events} = require('./Events'); const {Events} = require('./Events');
@ -15,7 +14,7 @@ const {TimeoutSettings} = require('./TimeoutSettings');
const {NavigationWatchdog} = require('./NavigationWatchdog'); const {NavigationWatchdog} = require('./NavigationWatchdog');
const {Accessibility} = require('./Accessibility'); const {Accessibility} = require('./Accessibility');
const writeFileAsync = util.promisify(fs.writeFile); const writeFileAsync = helper.promisify(fs.writeFile);
class Page extends EventEmitter { class Page extends EventEmitter {
/** /**

View File

@ -65,6 +65,10 @@ class Helper {
} }
} }
/**
* @param {function} nodeFunction
* @return {function}
*/
static promisify(nodeFunction) { static promisify(nodeFunction) {
function promisified(...args) { function promisified(...args) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {

View File

@ -1,14 +1,14 @@
const os = require('os'); const os = require('os');
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const util = require('util');
// Install browser preferences after downloading and unpacking // Install browser preferences after downloading and unpacking
// firefox instances. // firefox instances.
// Based on: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Enterprise_deployment_before_60#Configuration // Based on: https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Enterprise_deployment_before_60#Configuration
async function installFirefoxPreferences(executablePath) { async function installFirefoxPreferences(executablePath) {
const firefoxFolder = path.dirname(executablePath); const firefoxFolder = path.dirname(executablePath);
const {helper} = require('../lib/helper'); const mkdirAsync = util.promisify(fs.mkdir.bind(fs));
const mkdirAsync = helper.promisify(fs.mkdir.bind(fs));
let prefPath = ''; let prefPath = '';
let configPath = ''; let configPath = '';

View File

@ -14,14 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
let asyncawait = true;
try {
new Function('async function test(){await 1}');
} catch (error) {
asyncawait = false;
}
if (asyncawait) {
const {helper} = require('./lib/helper'); const {helper} = require('./lib/helper');
const api = require('./lib/api'); const api = require('./lib/api');
for (const className in api) { for (const className in api) {
@ -29,10 +21,9 @@ if (asyncawait) {
if (typeof api[className] === 'function') if (typeof api[className] === 'function')
helper.installAsyncStackHooks(api[className]); helper.installAsyncStackHooks(api[className]);
} }
}
// If node does not support async await, use the compiled version. // If node does not support async await, use the compiled version.
const Puppeteer = asyncawait ? require('./lib/Puppeteer') : require('./node6/lib/Puppeteer'); const Puppeteer = require('./lib/Puppeteer');
const packageJson = require('./package.json'); const packageJson = require('./package.json');
const preferredRevision = packageJson.puppeteer.chromium_revision; const preferredRevision = packageJson.puppeteer.chromium_revision;
const isPuppeteerCore = packageJson.name === 'puppeteer-core'; const isPuppeteerCore = packageJson.name === 'puppeteer-core';

View File

@ -18,8 +18,6 @@
if (require('./package.json').name === 'puppeteer-core') if (require('./package.json').name === 'puppeteer-core')
return; return;
buildNode6IfNecessary();
if (process.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD) { if (process.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD) {
logPolitely('**INFO** Skipping Chromium download. "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" environment variable was found.'); logPolitely('**INFO** Skipping Chromium download. "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD" environment variable was found.');
return; return;
@ -109,34 +107,7 @@ function toMegabytes(bytes) {
return `${Math.round(mb * 10) / 10} Mb`; return `${Math.round(mb * 10) / 10} Mb`;
} }
function buildNode6IfNecessary() {
const fs = require('fs');
const path = require('path');
// if this package is installed from NPM, then it already has up-to-date node6
// folder.
if (!fs.existsSync(path.join('utils', 'node6-transform')))
return;
// if async/await is supported, then node6 is not needed.
if (supportsAsyncAwait())
return;
// Re-build node6/ folder.
logPolitely('Building Puppeteer for Node 6');
require(path.join(__dirname, 'utils', 'node6-transform'));
}
function supportsAsyncAwait() {
try {
new Function('async function test(){await 1}');
} catch (error) {
return false;
}
return true;
}
function generateProtocolTypesIfNecessary(updated) { function generateProtocolTypesIfNecessary(updated) {
if (!supportsAsyncAwait())
return;
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
if (!fs.existsSync(path.join(__dirname, 'utils', 'protocol-types-generator'))) if (!fs.existsSync(path.join(__dirname, 'utils', 'protocol-types-generator')))

View File

@ -17,8 +17,8 @@
const os = require('os'); const os = require('os');
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const extract = require('extract-zip');
const util = require('util'); const util = require('util');
const extract = require('extract-zip');
const URL = require('url'); const URL = require('url');
const {helper, assert} = require('./helper'); const {helper, assert} = require('./helper');
const removeRecursive = require('rimraf'); const removeRecursive = require('rimraf');

View File

@ -31,6 +31,7 @@ const {Worker} = require('./Worker');
const {createJSHandle} = require('./JSHandle'); const {createJSHandle} = require('./JSHandle');
const {Accessibility} = require('./Accessibility'); const {Accessibility} = require('./Accessibility');
const {TimeoutSettings} = require('./TimeoutSettings'); const {TimeoutSettings} = require('./TimeoutSettings');
const writeFileAsync = helper.promisify(fs.writeFile); const writeFileAsync = helper.promisify(fs.writeFile);
class Page extends EventEmitter { class Page extends EventEmitter {

View File

@ -156,6 +156,10 @@ class Helper {
return typeof obj === 'number' || obj instanceof Number; return typeof obj === 'number' || obj instanceof Number;
} }
/**
* @param {function} nodeFunction
* @return {function}
*/
static promisify(nodeFunction) { static promisify(nodeFunction) {
function promisified(...args) { function promisified(...args) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {

View File

@ -5,7 +5,7 @@
"main": "index.js", "main": "index.js",
"repository": "github:GoogleChrome/puppeteer", "repository": "github:GoogleChrome/puppeteer",
"engines": { "engines": {
"node": ">=6.4.0" "node": ">=8.16.0"
}, },
"puppeteer": { "puppeteer": {
"chromium_revision": "686378" "chromium_revision": "686378"
@ -15,14 +15,11 @@
"funit": "BROWSER=firefox node test/test.js", "funit": "BROWSER=firefox node test/test.js",
"debug-unit": "node --inspect-brk test/test.js", "debug-unit": "node --inspect-brk test/test.js",
"test-doclint": "node utils/doclint/check_public_api/test/test.js && node utils/doclint/preprocessor/test.js", "test-doclint": "node utils/doclint/check_public_api/test/test.js && node utils/doclint/preprocessor/test.js",
"test": "npm run lint --silent && npm run coverage && npm run test-doclint && npm run test-node6-transformer && npm run test-types && node utils/testrunner/test/test.js", "test": "npm run lint --silent && npm run coverage && npm run test-doclint && npm run test-types && node utils/testrunner/test/test.js",
"install": "node install.js", "install": "node install.js",
"lint": "([ \"$CI\" = true ] && eslint --quiet -f codeframe . || eslint .) && npm run tsc && npm run doc", "lint": "([ \"$CI\" = true ] && eslint --quiet -f codeframe . || eslint .) && npm run tsc && npm run doc",
"doc": "node utils/doclint/cli.js", "doc": "node utils/doclint/cli.js",
"coverage": "cross-env COVERAGE=true npm run unit", "coverage": "cross-env COVERAGE=true npm run unit",
"test-node6-transformer": "node utils/node6-transform/test/test.js",
"build": "node utils/node6-transform/index.js && node utils/doclint/generate_types",
"unit-node6": "node node6/test/test.js",
"tsc": "tsc -p .", "tsc": "tsc -p .",
"prepublishOnly": "npm run build", "prepublishOnly": "npm run build",
"apply-next-version": "node utils/apply_next_version.js", "apply-next-version": "node utils/apply_next_version.js",
@ -63,7 +60,6 @@
}, },
"browser": { "browser": {
"./lib/BrowserFetcher.js": false, "./lib/BrowserFetcher.js": false,
"./node6/lib/Puppeteer": false,
"ws": "./utils/browser/WebSocket", "ws": "./utils/browser/WebSocket",
"fs": false, "fs": false,
"child_process": false, "child_process": false,

View File

@ -16,13 +16,6 @@
const utils = require('./utils'); const utils = require('./utils');
let asyncawait = true;
try {
new Function('async function foo() {await 1}');
} catch (e) {
asyncawait = false;
}
const bigint = typeof BigInt !== 'undefined'; const bigint = typeof BigInt !== 'undefined';
module.exports.addTests = function({testRunner, expect}) { module.exports.addTests = function({testRunner, expect}) {
@ -74,14 +67,12 @@ module.exports.addTests = function({testRunner, expect}) {
it_fails_ffox('should return undefined for objects with symbols', async({page, server}) => { it_fails_ffox('should return undefined for objects with symbols', async({page, server}) => {
expect(await page.evaluate(() => [Symbol('foo4')])).toBe(undefined); expect(await page.evaluate(() => [Symbol('foo4')])).toBe(undefined);
}); });
(asyncawait ? it : xit)('should work with function shorthands', async({page, server}) => { it('should work with function shorthands', async({page, server}) => {
// trick node6 transpiler to not touch our object. const a = {
// TODO(lushnikov): remove eval once Node6 is dropped.
const a = eval(`({
sum(a, b) { return a + b; }, sum(a, b) { return a + b; },
async mult(a, b) { return a * b; } async mult(a, b) { return a * b; }
})`); };
expect(await page.evaluate(a.sum, 1, 2)).toBe(3); expect(await page.evaluate(a.sum, 1, 2)).toBe(3);
expect(await page.evaluate(a.mult, 2, 4)).toBe(8); expect(await page.evaluate(a.mult, 2, 4)).toBe(8);
}); });

View File

@ -17,11 +17,12 @@
const path = require('path'); const path = require('path');
const os = require('os'); const os = require('os');
const fs = require('fs'); const fs = require('fs');
const {helper} = require('../lib/helper'); const util = require('util');
const rmAsync = helper.promisify(require('rimraf'));
const utils = require('./utils'); const utils = require('./utils');
const {waitEvent} = utils; const {waitEvent} = utils;
const mkdtempAsync = helper.promisify(fs.mkdtemp);
const rmAsync = util.promisify(require('rimraf'));
const mkdtempAsync = util.promisify(fs.mkdtemp);
const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-'); const TMP_FOLDER = path.join(os.tmpdir(), 'pptr_tmp_folder-');

View File

@ -233,9 +233,10 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p
const browser = await puppeteer.launch(options); const browser = await puppeteer.launch(options);
const pages = await browser.pages(); const pages = await browser.pages();
expect(pages.length).toBe(1); expect(pages.length).toBe(1);
if (pages[0].url() !== server.EMPTY_PAGE) const page = pages[0];
await pages[0].waitForNavigation(); if (page.url() !== server.EMPTY_PAGE)
expect(pages[0].url()).toBe(server.EMPTY_PAGE); await page.waitForNavigation();
expect(page.url()).toBe(server.EMPTY_PAGE);
await browser.close(); await browser.close();
}); });
it('should set the default viewport', async() => { it('should set the default viewport', async() => {

View File

@ -15,11 +15,12 @@
*/ */
const path = require('path'); const path = require('path');
const util = require('util');
const fs = require('fs'); const fs = require('fs');
const readFileAsync = promisify(fs.readFile); const readFileAsync = util.promisify(fs.readFile);
const readdirAsync = promisify(fs.readdir); const readdirAsync = util.promisify(fs.readdir);
const writeFileAsync = promisify(fs.writeFile); const writeFileAsync = util.promisify(fs.writeFile);
const PROJECT_DIR = path.join(__dirname, '..', '..'); const PROJECT_DIR = path.join(__dirname, '..', '..');
@ -110,26 +111,3 @@ class Source {
} }
module.exports = Source; module.exports = Source;
/**
* @param {function(?)} nodeFunction
* @return {function(?):!Promise<?>}
*/
function promisify(nodeFunction) {
/**
* @param {!Array<?>} options
* @return {!Promise<?>}
*/
return function(...options) {
return new Promise(function(fulfill, reject) {
options.push(callback);
nodeFunction.call(null, ...options);
function callback(err, result) {
if (err)
reject(err);
else
fulfill(result);
}
});
};
}

View File

@ -1,156 +0,0 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const esprima = require('esprima');
const ESTreeWalker = require('../ESTreeWalker');
// This is converted from Babel's "transform-async-to-generator"
// https://babeljs.io/docs/plugins/transform-async-to-generator/
const asyncToGenerator = fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
};
/**
* @param {string} text
* @return {string}
*/
function transformAsyncFunctions(text) {
/**
* @type {!Array<{from: number, to: number, replacement: string}>}
*/
const edits = [];
const ast = esprima.parseScript(text, {range: true, tolerant: true});
const walker = new ESTreeWalker(node => {
if (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration' || node.type === 'ArrowFunctionExpression')
onBeforeFunction(node);
else if (node.type === 'AwaitExpression')
onBeforeAwait(node);
}, node => {
if (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration' || node.type === 'ArrowFunctionExpression')
onAfterFunction(node);
else if (node.type === 'AwaitExpression')
onAfterAwait(node);
});
walker.walk(ast);
edits.reverse();
for (const {replacement, from, to} of edits)
text = text.substring(0, from) + replacement + text.substring(to);
return text;
/**
* @param {ESTree.Node} node
*/
function onBeforeFunction(node) {
if (!node.async) return;
let range;
if (node.parent.type === 'MethodDefinition')
range = node.parent.range;
else
range = node.range;
const index = text.substring(range[0], range[1]).indexOf('async') + range[0];
insertText(index, index + 'async'.length, '/* async */');
let before = `{return (${asyncToGenerator.toString()})(function*()`;
if (node.body.type !== 'BlockStatement') {
before += `{ return `;
// Remove parentheses that might wrap an arrow function
const beforeBody = text.substring(node.range[0], node.body.range[0]);
if (/\(\s*$/.test(beforeBody)) {
const openParen = node.range[0] + beforeBody.lastIndexOf('(');
insertText(openParen, openParen + 1, ' ');
}
}
insertText(node.body.range[0], node.body.range[0], before);
}
/**
* @param {ESTree.Node} node
*/
function onAfterFunction(node) {
if (!node.async) return;
let after = `);}`;
if (node.body.type !== 'BlockStatement')
after = `; }` + after;
insertText(node.body.range[1], node.body.range[1], after);
if (node.body.type !== 'BlockStatement') {
// Remove parentheses that might wrap an arrow function
const beforeBody = text.substring(node.range[0], node.body.range[0]);
if (/\(\s*$/.test(beforeBody)) {
const afterBody = text.substring(node.body.range[1], node.range[1]);
const closeParen = node.body.range[1] + afterBody.indexOf(')');
insertText(closeParen, closeParen + 1, ' ');
}
}
}
/**
* @param {ESTree.Node} node
*/
function onBeforeAwait(node) {
const index = text.substring(node.range[0], node.range[1]).indexOf('await') + node.range[0];
insertText(index, index + 'await'.length, '(yield');
}
/**
* @param {ESTree.Node} node
*/
function onAfterAwait(node) {
insertText(node.range[1], node.range[1], ')');
}
/**
* @param {number} from
* @param {number} to
*/
function insertText(from, to, replacement) {
edits.push({from, to, replacement});
}
}
module.exports = transformAsyncFunctions;

View File

@ -1,64 +0,0 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const fs = require('fs');
const path = require('path');
const removeRecursive = require('rimraf').sync;
const transformAsyncFunctions = require('./TransformAsyncFunctions');
const root = path.join(__dirname, '..', '..');
const dest = path.join(__dirname, '..', '..', 'node6');
const excludes = [
path.resolve(root, 'test', 'assets'),
];
if (fs.existsSync(dest))
removeRecursive(dest);
fs.mkdirSync(dest);
fs.mkdirSync(path.join(dest, 'utils'));
copyFolder(path.join(root, 'lib'), path.join(dest, 'lib'));
copyFolder(path.join(root, 'test'), path.join(dest, 'test'));
copyFolder(path.join(root, 'utils', 'testrunner'), path.join(dest, 'utils', 'testrunner'));
copyFolder(path.join(root, 'utils', 'testserver'), path.join(dest, 'utils', 'testserver'));
copyFolder(path.join(root, 'utils', 'flakiness-dashboard'), path.join(dest, 'utils', 'flakiness-dashboard'));
function copyFolder(source, target) {
if (fs.existsSync(target))
removeRecursive(target);
fs.mkdirSync(target);
fs.readdirSync(source).forEach(file => {
const from = path.join(source, file);
const to = path.join(target, file);
if (fs.lstatSync(from).isDirectory())
copyFolder(from, to);
else
copyFile(from, to);
});
}
function copyFile(from, to) {
let text = fs.readFileSync(from);
const isExcluded = excludes.some(exclude => from.startsWith(exclude));
if (!isExcluded && from.endsWith('.js')) {
text = text.toString();
const prefix = text.startsWith('#!') ? text.substring(0, text.indexOf('\n')) : '';
text = prefix + transformAsyncFunctions(text.substring(prefix.length));
}
fs.writeFileSync(to, text);
}

View File

@ -1,97 +0,0 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const transformAsyncFunctions = require('../TransformAsyncFunctions');
const {TestRunner, Reporter, Matchers} = require('../../testrunner/');
const runner = new TestRunner();
new Reporter(runner);
const {describe, xdescribe, fdescribe} = runner;
const {it, fit, xit} = runner;
const {beforeAll, beforeEach, afterAll, afterEach} = runner;
const {expect} = new Matchers();
describe('TransformAsyncFunctions', function() {
it('should convert a function expression', function(done) {
const input = `(async function(){ return 123 })()`;
const output = eval(transformAsyncFunctions(input));
expect(output instanceof Promise).toBe(true);
output.then(result => expect(result).toBe(123)).then(done);
});
it('should convert an arrow function', function(done) {
const input = `(async () => 123)()`;
const output = eval(transformAsyncFunctions(input));
expect(output instanceof Promise).toBe(true);
output.then(result => expect(result).toBe(123)).then(done);
});
it('should convert an arrow function with curly braces', function(done) {
const input = `(async () => { return 123 })()`;
const output = eval(transformAsyncFunctions(input));
expect(output instanceof Promise).toBe(true);
output.then(result => expect(result).toBe(123)).then(done);
});
it('should convert a function declaration', function(done) {
const input = `async function f(){ return 123; } f();`;
const output = eval(transformAsyncFunctions(input));
expect(output instanceof Promise).toBe(true);
output.then(result => expect(result).toBe(123)).then(done);
});
it('should convert await', function(done) {
const input = `async function f(){ return 23 + await Promise.resolve(100); } f();`;
const output = eval(transformAsyncFunctions(input));
expect(output instanceof Promise).toBe(true);
output.then(result => expect(result).toBe(123)).then(done);
});
it('should convert method', function(done) {
const input = `class X{async f() { return 123 }} (new X()).f();`;
const output = eval(transformAsyncFunctions(input));
expect(output instanceof Promise).toBe(true);
output.then(result => expect(result).toBe(123)).then(done);
});
it('should pass arguments', function(done) {
const input = `(async function(a, b){ return await a + await b })(Promise.resolve(100), 23)`;
const output = eval(transformAsyncFunctions(input));
expect(output instanceof Promise).toBe(true);
output.then(result => expect(result).toBe(123)).then(done);
});
it('should still work across eval', function(done) {
const input = `var str = (async function(){ return 123; }).toString(); eval('(' + str + ')')();`;
const output = eval(transformAsyncFunctions(input));
expect(output instanceof Promise).toBe(true);
output.then(result => expect(result).toBe(123)).then(done);
});
it('should work with double await', function(done) {
const input = `async function f(){ return 23 + await Promise.resolve(50 + await Promise.resolve(50)); } f();`;
const output = eval(transformAsyncFunctions(input));
expect(output instanceof Promise).toBe(true);
output.then(result => expect(result).toBe(123)).then(done);
});
it('should work paren around arrow function', function(done) {
const input = `(async x => ( 123))()`;
const output = eval(transformAsyncFunctions(input));
expect(output instanceof Promise).toBe(true);
output.then(result => expect(result).toBe(123)).then(done);
});
it('should work async arrow with await', function(done) {
const input = `(async() => await 123)()`;
const output = eval(transformAsyncFunctions(input));
expect(output instanceof Promise).toBe(true);
output.then(result => expect(result).toBe(123)).then(done);
});
});
runner.run();