Wolfgang Beyer | e57322c | 2024-02-08 12:04:24 | [diff] [blame] | 1 | // Copyright 2024 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | 'use strict'; |
| 6 | |
| 7 | const fs = require('fs'); |
| 8 | const path = require('path'); |
| 9 | const ts = require('typescript'); |
| 10 | |
| 11 | function findEnumNode(root, predicate) { |
| 12 | const nodesToVisit = [root]; |
| 13 | while (nodesToVisit.length) { |
| 14 | const currentNode = nodesToVisit.shift(); |
| 15 | if (predicate(currentNode)) { |
| 16 | return currentNode; |
| 17 | } |
| 18 | nodesToVisit.push(...currentNode.getChildren()); |
| 19 | } |
| 20 | } |
| 21 | |
| 22 | function extractHistogramsFromHostApi(nodes) { |
| 23 | const histograms = new Map(); |
| 24 | for (const node of nodes) { |
| 25 | const stringLiteralNode = node.getChildren()[2]; |
| 26 | if (stringLiteralNode.kind === ts.SyntaxKind.StringLiteral) { |
| 27 | histograms.set(node.name.escapedText, stringLiteralNode.getText().replace(/(^')|('$)/g, '')); |
| 28 | } |
| 29 | } |
| 30 | return histograms; |
| 31 | } |
| 32 | |
| 33 | function extractHistogramsFromCompatibility(root) { |
| 34 | const histograms = new Map(); |
| 35 | const nodesToVisit = [root]; |
| 36 | while (nodesToVisit.length) { |
| 37 | const currentNode = nodesToVisit.shift(); |
| 38 | if (ts.isPropertyAssignment(currentNode)) { |
| 39 | histograms.set(currentNode.name.escapedText, currentNode.initializer.text); |
| 40 | } |
| 41 | nodesToVisit.push(...currentNode.getChildren()); |
| 42 | } |
| 43 | return histograms; |
| 44 | } |
| 45 | |
| 46 | function compare(hostApiHistograms, compatibilityHistograms) { |
| 47 | const errorMessages = []; |
| 48 | for (const [id, value] of hostApiHistograms) { |
| 49 | if (!compatibilityHistograms.has(id)) { |
| 50 | errorMessages.push(`The enum in 'devtools_compatibility.js' is missing a '${id}' entry.`); |
| 51 | } else if (compatibilityHistograms.get(id) !== value) { |
| 52 | errorMessages.push(`The values for '${id}' are not equal: '${value}' vs. '${compatibilityHistograms.get(id)}'.`); |
| 53 | } |
| 54 | } |
| 55 | for (const id of compatibilityHistograms.keys()) { |
| 56 | if (!hostApiHistograms.has(id)) { |
| 57 | errorMessages.push(`The enum in 'InspectorFrontendHostAPI.ts' is missing a '${id}' entry.`); |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | if (errorMessages.length) { |
| 62 | console.error( |
| 63 | '\'EnumeratedHistogram\` enums in \'InspectorFrontendHostAPI.ts\' and \'devtools_compatibility.js\' do not have the same content:'); |
| 64 | for (const errorMessage of errorMessages) { |
| 65 | console.error(errorMessage); |
| 66 | } |
| 67 | console.error('Please ensure both enums have exactly the same content.'); |
| 68 | process.exit(1); |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | function main() { |
| 73 | const hostApiPath = path.resolve(__dirname, '..', 'front_end', 'core', 'host', 'InspectorFrontendHostAPI.ts'); |
| 74 | const hostApiFile = fs.readFileSync(hostApiPath, 'utf8'); |
| 75 | const hostApiSourceFile = ts.createSourceFile(hostApiPath, hostApiFile, ts.ScriptTarget.ESNext, true); |
| 76 | const hostApiEnumNode = findEnumNode( |
| 77 | hostApiSourceFile, node => ts.isEnumDeclaration(node) && node.name.escapedText === 'EnumeratedHistogram'); |
| 78 | const hostApiHistograms = extractHistogramsFromHostApi(hostApiEnumNode.members); |
| 79 | if (!hostApiHistograms.size) { |
| 80 | console.error('Could not find \'EnumeratedHistogram\` enum entries in \'InspectorFrontendHostAPI.ts\'.'); |
| 81 | process.exit(1); |
| 82 | } |
| 83 | |
| 84 | const compatibilityPath = path.resolve(__dirname, '..', 'front_end', 'devtools_compatibility.js'); |
| 85 | const compatibilityFile = fs.readFileSync(compatibilityPath, 'utf8'); |
| 86 | const compatibilitySourceFile = |
| 87 | ts.createSourceFile(compatibilityPath, compatibilityFile, ts.ScriptTarget.ESNext, true); |
| 88 | const compatibilityEnumNode = findEnumNode( |
| 89 | compatibilitySourceFile, |
| 90 | node => ts.isVariableDeclaration(node) && node.name.escapedText === 'EnumeratedHistogram'); |
| 91 | const compatibilityHistograms = extractHistogramsFromCompatibility(compatibilityEnumNode); |
| 92 | if (!compatibilityHistograms.size) { |
| 93 | console.error('Could not find \'EnumeratedHistogram\` enum entries in \'devtools_compatibility.js\'.'); |
| 94 | process.exit(1); |
| 95 | } |
| 96 | |
| 97 | compare(hostApiHistograms, compatibilityHistograms); |
| 98 | console.log('DevTools UMA Enumerated Histograms checker passed.'); |
| 99 | } |
| 100 | |
| 101 | main(); |