mirror of
				https://github.com/microsoft/playwright.git
				synced 2025-06-26 21:40:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			180 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			180 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env node
 | |
| /**
 | |
|  * 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.
 | |
|  */
 | |
| 
 | |
| //@ts-check
 | |
| 
 | |
| const playwright = require('playwright-core');
 | |
| const fs = require('fs');
 | |
| const path = require('path');
 | |
| const { parseApi } = require('./api_parser');
 | |
| const missingDocs = require('./missingDocs');
 | |
| const md = require('../markdown');
 | |
| 
 | |
| /** @typedef {import('./documentation').Type} Type */
 | |
| /** @typedef {import('../markdown').MarkdownNode} MarkdownNode */
 | |
| 
 | |
| const PROJECT_DIR = path.join(__dirname, '..', '..');
 | |
| 
 | |
| const dirtyFiles = new Set();
 | |
| 
 | |
| run().catch(e => {
 | |
|   console.error(e);
 | |
|   process.exit(1);
 | |
| });;
 | |
| 
 | |
| async function run() {
 | |
|   // Patch README.md
 | |
|   const versions = await getBrowserVersions();
 | |
|   {
 | |
|     const params = new Map();
 | |
|     const { chromium, firefox, webkit } = versions;
 | |
|     params.set('chromium-version', chromium);
 | |
|     params.set('firefox-version', firefox);
 | |
|     params.set('webkit-version', webkit);
 | |
|     params.set('chromium-version-badge', `[](https://www.chromium.org/Home)`);
 | |
|     params.set('firefox-version-badge', `[](https://www.mozilla.org/en-US/firefox/new/)`);
 | |
|     params.set('webkit-version-badge', `[](https://webkit.org/)`);
 | |
| 
 | |
|     let content = fs.readFileSync(path.join(PROJECT_DIR, 'README.md')).toString();
 | |
|     content = content.replace(/<!-- GEN:([^ ]+) -->([^<]*)<!-- GEN:stop -->/ig, (match, p1) => {
 | |
|       if (!params.has(p1)) {
 | |
|         console.log(`ERROR: Invalid generate parameter "${p1}" in "${match}"`);
 | |
|         process.exit(1);
 | |
|       }
 | |
|       return `<!-- GEN:${p1} -->${params.get(p1)}<!-- GEN:stop -->`;
 | |
|     });
 | |
|     writeAssumeNoop(path.join(PROJECT_DIR, 'README.md'), content, dirtyFiles);
 | |
|   }
 | |
| 
 | |
|   // Update device descriptors
 | |
|   {
 | |
|     const devicesDescriptorsSourceFile = path.join(PROJECT_DIR, 'packages', 'playwright-core', 'src', 'server', 'deviceDescriptorsSource.json')
 | |
|     const devicesDescriptors = require(devicesDescriptorsSourceFile)
 | |
|     for (const deviceName of Object.keys(devicesDescriptors)) {
 | |
|       switch (devicesDescriptors[deviceName].defaultBrowserType) {
 | |
|         case 'chromium':
 | |
|           devicesDescriptors[deviceName].userAgent = devicesDescriptors[deviceName].userAgent.replace(
 | |
|             /(.*Chrome\/)(.*?)( .*)/,
 | |
|             `$1${versions.chromium}$3`
 | |
|           ).replace(
 | |
|             /(.*Edg\/)(.*?)$/,
 | |
|             `$1${versions.chromium}`
 | |
|           )
 | |
|           break;
 | |
|         case 'firefox':
 | |
|           devicesDescriptors[deviceName].userAgent = devicesDescriptors[deviceName].userAgent.replace(
 | |
|             /^(.*Firefox\/)(.*?)( .*?)?$/,
 | |
|             `$1${versions.firefox}$3`
 | |
|           ).replace(/^(.*rv:)(.*)(\).*?)$/, `$1${versions.firefox}$3`)
 | |
|           break;
 | |
|         case 'webkit':
 | |
|           devicesDescriptors[deviceName].userAgent = devicesDescriptors[deviceName].userAgent.replace(
 | |
|             /(.*Version\/)(.*?)( .*)/,
 | |
|             `$1${versions.webkit}$3`
 | |
|           )
 | |
|           break;
 | |
|         default:
 | |
|           break;
 | |
|       }
 | |
|     }
 | |
|     writeAssumeNoop(devicesDescriptorsSourceFile, JSON.stringify(devicesDescriptors, null, 2), dirtyFiles);
 | |
|   }
 | |
| 
 | |
|   // Validate links
 | |
|   {
 | |
|     const langs = ['js', 'java', 'python', 'csharp'];
 | |
|     for (const lang of langs) {
 | |
|       try {
 | |
|         let documentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'api'));
 | |
|         documentation.filterForLanguage(lang);
 | |
|         if (lang === 'js') {
 | |
|           const testDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-api'), path.join(PROJECT_DIR, 'docs', 'src', 'api', 'params.md'));
 | |
|           testDocumentation.filterForLanguage('js');
 | |
|           const testRerpoterDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'test-reporter-api'));
 | |
|           testRerpoterDocumentation.filterForLanguage('js');
 | |
|           documentation = documentation.mergeWith(testDocumentation).mergeWith(testRerpoterDocumentation);
 | |
|         }
 | |
| 
 | |
|         // This validates member links.
 | |
|         documentation.setLinkRenderer(() => undefined);
 | |
| 
 | |
|         for (const file of fs.readdirSync(path.join(PROJECT_DIR, 'docs', 'src'))) {
 | |
|           if (!file.endsWith('.md'))
 | |
|             continue;
 | |
|           if (langs.some(other => other !== lang && file.endsWith(`-${other}.md`)))
 | |
|             continue;
 | |
|           const data = fs.readFileSync(path.join(PROJECT_DIR, 'docs', 'src', file)).toString();
 | |
|           documentation.renderLinksInText(md.filterNodesForLanguage(md.parse(data), lang));
 | |
|         }
 | |
|       } catch (e) {
 | |
|         e.message = `While processing "${lang}"\n` + e.message;
 | |
|         throw e;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Check for missing docs
 | |
|   {
 | |
|     const apiDocumentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'api'));
 | |
|     apiDocumentation.filterForLanguage('js');
 | |
|     const srcClient = path.join(PROJECT_DIR, 'packages', 'playwright-core', 'src', 'client');
 | |
|     const sources = fs.readdirSync(srcClient).map(n => path.join(srcClient, n));
 | |
|     const errors = missingDocs(apiDocumentation, sources, path.join(srcClient, 'api.ts'));
 | |
|     if (errors.length) {
 | |
|       console.log('============================');
 | |
|       console.log('ERROR: missing documentation:');
 | |
|       errors.forEach(e => console.log(e));
 | |
|       console.log('============================')
 | |
|       process.exit(1);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (dirtyFiles.size) {
 | |
|     console.log('============================')
 | |
|     console.log('ERROR: generated files have changed, this is only error if happens in CI:');
 | |
|     [...dirtyFiles].forEach(f => console.log(f));
 | |
|     console.log('============================')
 | |
|     process.exit(1);
 | |
|   }
 | |
|   process.exit(0);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @param {string} name
 | |
|  * @param {string} content
 | |
|  * @param {Set<string>} dirtyFiles
 | |
|  */
 | |
| function writeAssumeNoop(name, content, dirtyFiles) {
 | |
|   fs.mkdirSync(path.dirname(name), { recursive: true });
 | |
|   const oldContent = fs.existsSync(name) ? fs.readFileSync(name).toString() : '';
 | |
|   if (oldContent !== content) {
 | |
|     fs.writeFileSync(name, content);
 | |
|     dirtyFiles.add(name);
 | |
|   }
 | |
| }
 | |
| 
 | |
| async function getBrowserVersions() {
 | |
|   const names = ['chromium', 'firefox', 'webkit'];
 | |
|   const browsers = await Promise.all(names.map(name => playwright[name].launch()));
 | |
|   const result = {};
 | |
|   for (let i = 0; i < names.length; i++) {
 | |
|     result[names[i]] = browsers[i].version();
 | |
|   }
 | |
|   await Promise.all(browsers.map(browser => browser.close()));
 | |
|   return result;
 | |
| }
 | 
