chore: cleanup our build system (#4903)
- Consolidate our build and watch to a single build.js file. - Update contributing docs. - Remove unused scripts and package.json script entries.
This commit is contained in:
parent
2311c282d6
commit
4ff7e1a419
2
.gitattributes
vendored
2
.gitattributes
vendored
|
|
@ -1,3 +1,5 @@
|
||||||
# text files must be lf for golden file tests to work
|
# text files must be lf for golden file tests to work
|
||||||
*.txt eol=lf
|
*.txt eol=lf
|
||||||
*.json eol=lf
|
*.json eol=lf
|
||||||
|
*.md eol=lf
|
||||||
|
*.yml eol=lf
|
||||||
|
|
|
||||||
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
|
|
@ -38,7 +38,7 @@ jobs:
|
||||||
# XVFB-RUN merges both STDOUT and STDERR, whereas we need only STDERR
|
# XVFB-RUN merges both STDOUT and STDERR, whereas we need only STDERR
|
||||||
# Wrap `npm run` in a subshell to redirect STDERR to file.
|
# Wrap `npm run` in a subshell to redirect STDERR to file.
|
||||||
# Enable core dumps in the subshell.
|
# Enable core dumps in the subshell.
|
||||||
- run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- bash -c "ulimit -c unlimited && npx folio test/ --workers=1 --forbid-only --global-timeout=5400000 --retries=3 --reporter=dot,json && npm run coverage"
|
- run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- bash -c "ulimit -c unlimited && npx folio test/ --workers=1 --forbid-only --global-timeout=5400000 --retries=3 --reporter=dot,json && node test/checkCoverage.js"
|
||||||
env:
|
env:
|
||||||
BROWSER: ${{ matrix.browser }}
|
BROWSER: ${{ matrix.browser }}
|
||||||
FOLIO_JSON_OUTPUT_NAME: "test-results/report.json"
|
FOLIO_JSON_OUTPUT_NAME: "test-results/report.json"
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ Fixes #123, fixes #234
|
||||||
|
|
||||||
### Writing Documentation
|
### Writing Documentation
|
||||||
|
|
||||||
All public API should have a descriptive entry in [`docs/api.md`](https://github.com/microsoft/playwright/blob/master/docs/api.md). There's a [documentation linter](https://github.com/microsoft/playwright/tree/master/utils/doclint) which makes sure documentation is aligned with the codebase.
|
All API classes, methods and events should have description in [`docs/src`](https://github.com/microsoft/playwright/blob/master/docs/src). There's a [documentation linter](https://github.com/microsoft/playwright/tree/master/utils/doclint) which makes sure documentation is aligned with the codebase.
|
||||||
|
|
||||||
To run the documentation linter, use:
|
To run the documentation linter, use:
|
||||||
|
|
||||||
|
|
@ -130,8 +130,7 @@ A barrier for introducing new installation dependencies is especially high:
|
||||||
- Tests should be *hermetic*. Tests should not depend on external services.
|
- Tests should be *hermetic*. Tests should not depend on external services.
|
||||||
- Tests should work on all three platforms: Mac, Linux and Win. This is especially important for screenshot tests.
|
- Tests should work on all three platforms: Mac, Linux and Win. This is especially important for screenshot tests.
|
||||||
|
|
||||||
Playwright tests are located in [`test/test.js`](https://github.com/microsoft/playwright/blob/master/test/test.js)
|
Playwright tests are located in [`test`](https://github.com/microsoft/playwright/blob/master/test) and use [Folio](https://github.com/microsoft/folio) test runner.
|
||||||
and are written with a [TestRunner](https://github.com/microsoft/playwright/tree/master/utils/testrunner) framework.
|
|
||||||
These are integration tests, making sure public API methods and events work as expected.
|
These are integration tests, making sure public API methods and events work as expected.
|
||||||
|
|
||||||
- To run all tests:
|
- To run all tests:
|
||||||
|
|
@ -145,36 +144,23 @@ npm run test
|
||||||
npm run ctest # also `ftest` for firefox and `wtest` for WebKit
|
npm run ctest # also `ftest` for firefox and `wtest` for WebKit
|
||||||
```
|
```
|
||||||
|
|
||||||
- To run tests in parallel, use `-j` flag:
|
- To run a specific test, substitute `it` with `it.only`:
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run wtest -- -j 4
|
|
||||||
```
|
|
||||||
|
|
||||||
- To run tests in "verbose" mode or to stop testrunner on first failure:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run ftest -- --verbose
|
|
||||||
npm run ftest -- --break-on-failure
|
|
||||||
```
|
|
||||||
|
|
||||||
- To run a specific test, substitute the `it` with `fit` (mnemonic rule: '*focus it*'):
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
...
|
...
|
||||||
// Using "fit" to run specific test
|
// Using "it.only" to run a specific test
|
||||||
fit('should work', async ({server, page}) => {
|
it.only('should work', async ({server, page}) => {
|
||||||
const response = await page.goto(server.EMPTY_PAGE);
|
const response = await page.goto(server.EMPTY_PAGE);
|
||||||
expect(response.ok).toBe(true);
|
expect(response.ok).toBe(true);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
- To disable a specific test, substitute the `it` with `xit` (mnemonic rule: '*cross it*'):
|
- To disable a specific test, substitute `it` with `it.skip`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
...
|
...
|
||||||
// Using "xit" to skip specific test
|
// Using "it.skip" to skip a specific test
|
||||||
xit('should work', async ({server, page}) => {
|
it.skip('should work', async ({server, page}) => {
|
||||||
const response = await page.goto(server.EMPTY_PAGE);
|
const response = await page.goto(server.EMPTY_PAGE);
|
||||||
expect(response.ok).toBe(true);
|
expect(response.ok).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
@ -198,12 +184,6 @@ CRPATH=<path-to-executable> npm run ctest
|
||||||
HEADLESS=false SLOW_MO=500 npm run wtest
|
HEADLESS=false SLOW_MO=500 npm run wtest
|
||||||
```
|
```
|
||||||
|
|
||||||
- To debug a test, "focus" a test first and then run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
BROWSER=chromium node --inspect-brk test/test.js
|
|
||||||
```
|
|
||||||
|
|
||||||
- When should a test be marked with `skip` or `fail`?
|
- When should a test be marked with `skip` or `fail`?
|
||||||
|
|
||||||
- **`skip(condition)`**: This test *should ***never*** work* for `condition`
|
- **`skip(condition)`**: This test *should ***never*** work* for `condition`
|
||||||
|
|
@ -224,18 +204,6 @@ BROWSER=chromium node --inspect-brk test/test.js
|
||||||
currently diverges from what a user would experience driving a Chromium or
|
currently diverges from what a user would experience driving a Chromium or
|
||||||
WebKit.
|
WebKit.
|
||||||
|
|
||||||
### Public API Coverage
|
|
||||||
|
|
||||||
Every public API method or event should be called at least once in tests. To ensure this, there's a `coverage` command which tracks calls to public API and reports back if some methods/events were not called.
|
|
||||||
|
|
||||||
Run all tests for all browsers with coverage enabled:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run coverage
|
|
||||||
```
|
|
||||||
|
|
||||||
There are also per-browser commands:" `npm run ccoverage`, `npm run fcoverage` and `npm run wcoverage`.
|
|
||||||
|
|
||||||
## Contributor License Agreement
|
## Contributor License Agreement
|
||||||
|
|
||||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||||
|
|
|
||||||
|
|
@ -18,16 +18,13 @@
|
||||||
"tsc": "tsc -p .",
|
"tsc": "tsc -p .",
|
||||||
"tsc-installer": "tsc -p ./src/install/tsconfig.json",
|
"tsc-installer": "tsc -p ./src/install/tsconfig.json",
|
||||||
"doc": "node utils/doclint/cli.js",
|
"doc": "node utils/doclint/cli.js",
|
||||||
"lint": "npm run eslint && npm run tsc && npm run doc && npm run check-deps && npm run generate-channels && node utils/generate_types/ --check-clean && npm run test-types && folio utils/doclint/test/",
|
"lint": "npm run eslint && npm run tsc && npm run doc && npm run check-deps && node utils/generate_channels.js && node utils/generate_types/ --check-clean && npm run test-types && folio utils/doclint/test/",
|
||||||
"clean": "rimraf lib",
|
"clean": "rimraf lib",
|
||||||
"prepare": "node install-from-github.js",
|
"prepare": "node install-from-github.js",
|
||||||
"build": "node utils/runWebpack.js --mode='development' && tsc -p . && npm run generate-api-json",
|
"build": "node utils/build/build.js",
|
||||||
"watch": "node utils/watch.js",
|
"watch": "node utils/build/build.js --watch",
|
||||||
"test-types": "node utils/generate_types/ && npx -p typescript@3.7.5 tsc -p utils/generate_types/test/tsconfig.json && tsc -p ./test/",
|
"test-types": "node utils/generate_types/ && npx -p typescript@3.7.5 tsc -p utils/generate_types/test/tsconfig.json && tsc -p ./test/",
|
||||||
"generate-channels": "node utils/generate_channels.js",
|
|
||||||
"generate-api-json": "node utils/doclint/generateApiJson.js",
|
|
||||||
"roll-browser": "node utils/roll_browser.js",
|
"roll-browser": "node utils/roll_browser.js",
|
||||||
"coverage": "node test/checkCoverage.js",
|
|
||||||
"check-deps": "node utils/check_deps.js",
|
"check-deps": "node utils/check_deps.js",
|
||||||
"build-android-driver": "./utils/build_android_driver.sh"
|
"build-android-driver": "./utils/build_android_driver.sh"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @unrestricted
|
|
||||||
*/
|
|
||||||
class ESTreeWalker {
|
|
||||||
/**
|
|
||||||
* @param {function(!ESTree.Node):(!Object|undefined)} beforeVisit
|
|
||||||
* @param {function(!ESTree.Node)=} afterVisit
|
|
||||||
*/
|
|
||||||
constructor(beforeVisit, afterVisit) {
|
|
||||||
this._beforeVisit = beforeVisit;
|
|
||||||
this._afterVisit = afterVisit || new Function();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {!ESTree.Node} ast
|
|
||||||
*/
|
|
||||||
walk(ast) {
|
|
||||||
this._innerWalk(ast, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {!ESTree.Node} node
|
|
||||||
* @param {?ESTree.Node} parent
|
|
||||||
*/
|
|
||||||
_innerWalk(node, parent) {
|
|
||||||
if (!node)
|
|
||||||
return;
|
|
||||||
node.parent = parent;
|
|
||||||
|
|
||||||
if (this._beforeVisit.call(null, node) === ESTreeWalker.SkipSubtree) {
|
|
||||||
this._afterVisit.call(null, node);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const walkOrder = ESTreeWalker._walkOrder[node.type];
|
|
||||||
if (!walkOrder)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (node.type === 'TemplateLiteral') {
|
|
||||||
const templateLiteral = /** @type {!ESTree.TemplateLiteralNode} */ (node);
|
|
||||||
const expressionsLength = templateLiteral.expressions.length;
|
|
||||||
for (let i = 0; i < expressionsLength; ++i) {
|
|
||||||
this._innerWalk(templateLiteral.quasis[i], templateLiteral);
|
|
||||||
this._innerWalk(templateLiteral.expressions[i], templateLiteral);
|
|
||||||
}
|
|
||||||
this._innerWalk(templateLiteral.quasis[expressionsLength], templateLiteral);
|
|
||||||
} else {
|
|
||||||
for (let i = 0; i < walkOrder.length; ++i) {
|
|
||||||
const entity = node[walkOrder[i]];
|
|
||||||
if (Array.isArray(entity))
|
|
||||||
this._walkArray(entity, node);
|
|
||||||
else
|
|
||||||
this._innerWalk(entity, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this._afterVisit.call(null, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {!Array.<!ESTree.Node>} nodeArray
|
|
||||||
* @param {?ESTree.Node} parentNode
|
|
||||||
*/
|
|
||||||
_walkArray(nodeArray, parentNode) {
|
|
||||||
for (let i = 0; i < nodeArray.length; ++i)
|
|
||||||
this._innerWalk(nodeArray[i], parentNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @typedef {!Object} ESTreeWalker.SkipSubtree */
|
|
||||||
ESTreeWalker.SkipSubtree = {};
|
|
||||||
|
|
||||||
/** @enum {!Array.<string>} */
|
|
||||||
ESTreeWalker._walkOrder = {
|
|
||||||
'AwaitExpression': ['argument'],
|
|
||||||
'ArrayExpression': ['elements'],
|
|
||||||
'ArrowFunctionExpression': ['params', 'body'],
|
|
||||||
'AssignmentExpression': ['left', 'right'],
|
|
||||||
'AssignmentPattern': ['left', 'right'],
|
|
||||||
'BinaryExpression': ['left', 'right'],
|
|
||||||
'BlockStatement': ['body'],
|
|
||||||
'BreakStatement': ['label'],
|
|
||||||
'CallExpression': ['callee', 'arguments'],
|
|
||||||
'CatchClause': ['param', 'body'],
|
|
||||||
'ClassBody': ['body'],
|
|
||||||
'ClassDeclaration': ['id', 'superClass', 'body'],
|
|
||||||
'ClassExpression': ['id', 'superClass', 'body'],
|
|
||||||
'ConditionalExpression': ['test', 'consequent', 'alternate'],
|
|
||||||
'ContinueStatement': ['label'],
|
|
||||||
'DebuggerStatement': [],
|
|
||||||
'DoWhileStatement': ['body', 'test'],
|
|
||||||
'EmptyStatement': [],
|
|
||||||
'ExpressionStatement': ['expression'],
|
|
||||||
'ForInStatement': ['left', 'right', 'body'],
|
|
||||||
'ForOfStatement': ['left', 'right', 'body'],
|
|
||||||
'ForStatement': ['init', 'test', 'update', 'body'],
|
|
||||||
'FunctionDeclaration': ['id', 'params', 'body'],
|
|
||||||
'FunctionExpression': ['id', 'params', 'body'],
|
|
||||||
'Identifier': [],
|
|
||||||
'IfStatement': ['test', 'consequent', 'alternate'],
|
|
||||||
'LabeledStatement': ['label', 'body'],
|
|
||||||
'Literal': [],
|
|
||||||
'LogicalExpression': ['left', 'right'],
|
|
||||||
'MemberExpression': ['object', 'property'],
|
|
||||||
'MethodDefinition': ['key', 'value'],
|
|
||||||
'NewExpression': ['callee', 'arguments'],
|
|
||||||
'ObjectExpression': ['properties'],
|
|
||||||
'ObjectPattern': ['properties'],
|
|
||||||
'ParenthesizedExpression': ['expression'],
|
|
||||||
'Program': ['body'],
|
|
||||||
'Property': ['key', 'value'],
|
|
||||||
'ReturnStatement': ['argument'],
|
|
||||||
'SequenceExpression': ['expressions'],
|
|
||||||
'Super': [],
|
|
||||||
'SwitchCase': ['test', 'consequent'],
|
|
||||||
'SwitchStatement': ['discriminant', 'cases'],
|
|
||||||
'TaggedTemplateExpression': ['tag', 'quasi'],
|
|
||||||
'TemplateElement': [],
|
|
||||||
'TemplateLiteral': ['quasis', 'expressions'],
|
|
||||||
'ThisExpression': [],
|
|
||||||
'ThrowStatement': ['argument'],
|
|
||||||
'TryStatement': ['block', 'handler', 'finalizer'],
|
|
||||||
'UnaryExpression': ['argument'],
|
|
||||||
'UpdateExpression': ['argument'],
|
|
||||||
'VariableDeclaration': ['declarations'],
|
|
||||||
'VariableDeclarator': ['id', 'init'],
|
|
||||||
'WhileStatement': ['test', 'body'],
|
|
||||||
'WithStatement': ['object', 'body'],
|
|
||||||
'YieldExpression': ['argument']
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = ESTreeWalker;
|
|
||||||
125
utils/build/build.js
Normal file
125
utils/build/build.js
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
*
|
||||||
|
* 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 child_process = require('child_process');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const steps = [];
|
||||||
|
const onChanges = [];
|
||||||
|
|
||||||
|
const watchMode = process.argv.slice(2).includes('--watch');
|
||||||
|
const ROOT = path.join(__dirname, '..', '..');
|
||||||
|
|
||||||
|
function filePath(relative) {
|
||||||
|
return path.join(ROOT, ...relative.split('/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function runWatch() {
|
||||||
|
function runOnChanges(paths, nodeFile) {
|
||||||
|
for (const p of [...paths, nodeFile]) {
|
||||||
|
const file = filePath(p);
|
||||||
|
if (!fs.existsSync(file)) {
|
||||||
|
console.error('could not find file', file);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
fs.watchFile(file, callback);
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
function callback() {
|
||||||
|
child_process.spawnSync('node', [filePath(nodeFile)], { stdio: 'inherit' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const spawns = [];
|
||||||
|
for (const step of steps)
|
||||||
|
spawns.push(child_process.spawn(step.command, step.args, { stdio: 'inherit', shell: step.shell }));
|
||||||
|
process.on('exit', () => spawns.forEach(s => s.kill()));
|
||||||
|
for (const onChange of onChanges)
|
||||||
|
runOnChanges(onChange.inputs, onChange.script);
|
||||||
|
}
|
||||||
|
|
||||||
|
function runBuild() {
|
||||||
|
function runStep(command, args, shell) {
|
||||||
|
const out = child_process.spawnSync(command, args, { stdio: 'inherit', shell });
|
||||||
|
if (out.status)
|
||||||
|
process.exit(out.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const step of steps)
|
||||||
|
runStep(step.command, step.args, step.shell);
|
||||||
|
for (const onChange of onChanges) {
|
||||||
|
if (!onChange.committed)
|
||||||
|
runStep('node', [filePath(onChange.script)], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build injected scripts.
|
||||||
|
const webPackFiles = [
|
||||||
|
'src/server/injected/injectedScript.webpack.config.js',
|
||||||
|
'src/server/injected/utilityScript.webpack.config.js',
|
||||||
|
'src/debug/injected/consoleApi.webpack.config.js',
|
||||||
|
'src/cli/injected/recorder.webpack.config.js',
|
||||||
|
];
|
||||||
|
for (const file of webPackFiles) {
|
||||||
|
steps.push({
|
||||||
|
command: 'npx',
|
||||||
|
args: ['webpack', '--config', filePath(file), '--mode', 'development', ...(watchMode ? ['--watch', '--silent'] : [])],
|
||||||
|
shell: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run typescript.
|
||||||
|
steps.push({
|
||||||
|
command: 'npx',
|
||||||
|
args: ['tsc', ...(watchMode ? ['-w', '--preserveWatchOutput'] : []), '-p', filePath('.')],
|
||||||
|
shell: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Generate api.json.
|
||||||
|
onChanges.push({
|
||||||
|
committed: false,
|
||||||
|
inputs: [
|
||||||
|
'docs/src/api-body.md',
|
||||||
|
'docs/src/api-params.md',
|
||||||
|
],
|
||||||
|
script: 'utils/doclint/generateApiJson.js',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Generate channels.
|
||||||
|
onChanges.push({
|
||||||
|
committed: false,
|
||||||
|
inputs: [
|
||||||
|
'src/protocol/protocol.yml'
|
||||||
|
],
|
||||||
|
script: 'utils/generate_channels.js',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Generate types.
|
||||||
|
onChanges.push({
|
||||||
|
committed: false,
|
||||||
|
inputs: [
|
||||||
|
'docs/src/api-body.md',
|
||||||
|
'docs/src/api-params.md',
|
||||||
|
'utils/generate_types/overrides.d.ts',
|
||||||
|
'utils/generate_types/exported.json',
|
||||||
|
'src/server/chromium/protocol.ts',
|
||||||
|
'src/trace/traceTypes.ts',
|
||||||
|
],
|
||||||
|
script: 'utils/generate_types/index.js',
|
||||||
|
});
|
||||||
|
|
||||||
|
watchMode ? runWatch() : runBuild();
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const yaml = require('yaml');
|
const yaml = require('yaml');
|
||||||
|
|
||||||
|
|
@ -110,7 +111,7 @@ const channels_ts = [
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// This file is generated by ${path.basename(__filename)}, do not edit manually.
|
// This file is generated by ${path.basename(__filename).split(path.sep).join(path.posix.sep)}, do not edit manually.
|
||||||
|
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
|
||||||
|
|
@ -234,6 +235,8 @@ validator_ts.push(`
|
||||||
let hasChanges = false;
|
let hasChanges = false;
|
||||||
|
|
||||||
function writeFile(filePath, content) {
|
function writeFile(filePath, content) {
|
||||||
|
if (os.platform() === 'win32')
|
||||||
|
content = content.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');
|
||||||
const existing = fs.readFileSync(filePath, 'utf8');
|
const existing = fs.readFileSync(filePath, 'utf8');
|
||||||
if (existing === content)
|
if (existing === content)
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
//@ts-check
|
//@ts-check
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const os = require('os');
|
||||||
const {devices} = require('../..');
|
const {devices} = require('../..');
|
||||||
const Documentation = require('../doclint/Documentation');
|
const Documentation = require('../doclint/Documentation');
|
||||||
const PROJECT_DIR = path.join(__dirname, '..', '..');
|
const PROJECT_DIR = path.join(__dirname, '..', '..');
|
||||||
|
|
@ -108,6 +109,8 @@ ${generateDevicesTypes()}
|
||||||
});
|
});
|
||||||
|
|
||||||
function writeFile(filePath, content) {
|
function writeFile(filePath, content) {
|
||||||
|
if (os.platform() === 'win32')
|
||||||
|
content = content.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');
|
||||||
const existing = fs.readFileSync(filePath, 'utf8');
|
const existing = fs.readFileSync(filePath, 'utf8');
|
||||||
if (existing === content)
|
if (existing === content)
|
||||||
return;
|
return;
|
||||||
|
|
@ -260,7 +263,7 @@ function parentClass(classDesc) {
|
||||||
|
|
||||||
function writeComment(comment, indent = '') {
|
function writeComment(comment, indent = '') {
|
||||||
const parts = [];
|
const parts = [];
|
||||||
|
|
||||||
comment = comment.replace(/\[`([^`]+)`\]\(#([^\)]+)\)/g, '[$1](https://github.com/microsoft/playwright/blob/master/docs/api.md#$2)');
|
comment = comment.replace(/\[`([^`]+)`\]\(#([^\)]+)\)/g, '[$1](https://github.com/microsoft/playwright/blob/master/docs/api.md#$2)');
|
||||||
comment = comment.replace(/\[([^\]]+)\]\(#([^\)]+)\)/g, '[$1](https://github.com/microsoft/playwright/blob/master/docs/api.md#$2)');
|
comment = comment.replace(/\[([^\]]+)\]\(#([^\)]+)\)/g, '[$1](https://github.com/microsoft/playwright/blob/master/docs/api.md#$2)');
|
||||||
comment = comment.replace(/\[`([^`]+)`\]\(\.\/([^\)]+)\)/g, '[$1](https://github.com/microsoft/playwright/blob/master/docs/$2)');
|
comment = comment.replace(/\[`([^`]+)`\]\(\.\/([^\)]+)\)/g, '[$1](https://github.com/microsoft/playwright/blob/master/docs/$2)');
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
* }} MarkdownNode */
|
* }} MarkdownNode */
|
||||||
|
|
||||||
function flattenWrappedLines(content) {
|
function flattenWrappedLines(content) {
|
||||||
const inLines = content.replace(/\r\n/g, '\n').split('\n');
|
const inLines = content.split('\n');
|
||||||
let inCodeBlock = false;
|
let inCodeBlock = false;
|
||||||
const outLines = [];
|
const outLines = [];
|
||||||
let outLineTokens = [];
|
let outLineTokens = [];
|
||||||
|
|
@ -159,7 +159,7 @@ function buildTree(lines) {
|
||||||
node.liType = 'ordinal';
|
node.liType = 'ordinal';
|
||||||
else if (content.startsWith('*'))
|
else if (content.startsWith('*'))
|
||||||
node.liType = 'bullet';
|
node.liType = 'bullet';
|
||||||
else
|
else
|
||||||
node.liType = 'default';
|
node.liType = 'default';
|
||||||
}
|
}
|
||||||
appendNode(indent, node);
|
appendNode(indent, node);
|
||||||
|
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Microsoft Corporation.
|
|
||||||
*
|
|
||||||
* 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 child_process = require('child_process');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const files = [
|
|
||||||
path.join('src', 'server', 'injected', 'injectedScript.webpack.config.js'),
|
|
||||||
path.join('src', 'server', 'injected', 'utilityScript.webpack.config.js'),
|
|
||||||
path.join('src', 'debug', 'injected', 'consoleApi.webpack.config.js'),
|
|
||||||
path.join('src', 'cli', 'injected', 'recorder.webpack.config.js'),
|
|
||||||
];
|
|
||||||
|
|
||||||
function runOne(runner, file) {
|
|
||||||
return runner('npx', ['webpack', '--config', file, ...process.argv.slice(2)], { stdio: 'inherit', shell: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
const args = process.argv.slice(2);
|
|
||||||
if (args.includes('--watch')) {
|
|
||||||
const spawns = files.map(file => runOne(child_process.spawn, file));
|
|
||||||
process.on('exit', () => spawns.forEach(s => s.kill()));
|
|
||||||
} else {
|
|
||||||
for (const file of files) {
|
|
||||||
const out = runOne(child_process.spawnSync, file);
|
|
||||||
if (out.status)
|
|
||||||
process.exit(out.status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Microsoft Corporation.
|
|
||||||
*
|
|
||||||
* 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 child_process = require('child_process');
|
|
||||||
const path = require('path');
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
const spawns = [
|
|
||||||
child_process.spawn('node', [path.join(__dirname, 'runWebpack.js'), '--mode="development"', '--watch', '--silent'], { stdio: 'inherit', shell: true }),
|
|
||||||
child_process.spawn('npx', ['tsc', '-w', '--preserveWatchOutput', '-p', path.join(__dirname, '..')], { stdio: 'inherit', shell: true }),
|
|
||||||
];
|
|
||||||
process.on('exit', () => spawns.forEach(s => s.kill()));
|
|
||||||
|
|
||||||
runOnChanges(['src/protocol/protocol.yml'], 'utils/generate_channels.js');
|
|
||||||
runOnChanges([
|
|
||||||
'docs/src/api-body.md',
|
|
||||||
'docs/src/api-params.md',
|
|
||||||
'utils/generate_types/overrides.d.ts',
|
|
||||||
'utils/generate_types/exported.json',
|
|
||||||
'src/server/chromium/protocol.ts',
|
|
||||||
'src/trace/traceTypes.ts',
|
|
||||||
], 'utils/generate_types/index.js');
|
|
||||||
runOnChanges([
|
|
||||||
'docs/src/api-body.md',
|
|
||||||
'docs/src/api-params.md',
|
|
||||||
], 'utils/doclint/generateApiJson.js');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string[][]} paths
|
|
||||||
* @param {string} nodeFile
|
|
||||||
*/
|
|
||||||
function runOnChanges(paths, nodeFile) {
|
|
||||||
for (const p of [...paths, nodeFile]) {
|
|
||||||
const filePath = path.join(__dirname, '..', ...p.split('/'));
|
|
||||||
if (!fs.existsSync(filePath)) {
|
|
||||||
console.error('could not find file', filePath);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
fs.watchFile(filePath, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
callback();
|
|
||||||
|
|
||||||
function callback() {
|
|
||||||
child_process.spawnSync('node', [path.join(__dirname, '..', ...nodeFile.split('/'))]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue