Files

17 lines
8.5 KiB
JavaScript

"use strict";
/**
* @license
* Copyright 2025 Google LLC
*
* 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.
*/var __awaiter=this&&this.__awaiter||function(thisArg,_arguments,P,generator){function adopt(value){return value instanceof P?value:new P((function(resolve){resolve(value)}))}return new(P||(P=Promise))((function(resolve,reject){function fulfilled(value){try{step(generator.next(value))}catch(e){reject(e)}}function rejected(value){try{step(generator["throw"](value))}catch(e){reject(e)}}function step(result){result.done?resolve(result.value):adopt(result.value).then(fulfilled,rejected)}step((generator=generator.apply(thisArg,_arguments||[])).next())}))};var __generator=this&&this.__generator||function(thisArg,body){var _={label:0,sent:function(){if(t[0]&1)throw t[1];return t[1]},trys:[],ops:[]},f,y,t,g;return g={next:verb(0),throw:verb(1),return:verb(2)},typeof Symbol==="function"&&(g[Symbol.iterator]=function(){return this}),g;function verb(n){return function(v){return step([n,v])}}function step(op){if(f)throw new TypeError("Generator is already executing.");while(g&&(g=0,op[0]&&(_=0)),_)try{if(f=1,y&&(t=op[0]&2?y["return"]:op[0]?y["throw"]||((t=y["return"])&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;if(y=0,t)op=[op[0]&2,t.value];switch(op[0]){case 0:case 1:t=op;break;case 4:_.label++;return{value:op[1],done:false};case 5:_.label++;y=op[1];op=[0];continue;case 7:op=_.ops.pop();_.trys.pop();continue;default:if(!(t=_.trys,t=t.length>0&&t[t.length-1])&&(op[0]===6||op[0]===2)){_=0;continue}if(op[0]===3&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(op[0]===6&&_.label<t[1]){_.label=t[1];t=op;break}if(t&&_.label<t[2]){_.label=t[2];_.ops.push(op);break}if(t[2])_.ops.pop();_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e];y=0}finally{f=t=0}if(op[0]&5)throw op[1];return{value:op[0]?op[1]:void 0,done:true}}};Object.defineProperty(exports,"__esModule",{value:true});var fs=require("fs");var path=require("path");var ts=require("typescript");var yargs_1=require("yargs");var helpers_1=require("yargs/helpers");var isVerbose=false;function log(message){if(isVerbose){console.log(message)}}var targetFunctionNames=new Set(["fail","hardAssert"]);function getTsFilesRecursive(dirPath){var tsFiles=[];try{var entries=fs.readdirSync(dirPath,{withFileTypes:true});for(var _i=0,entries_1=entries;_i<entries_1.length;_i++){var entry=entries_1[_i];var fullPath=path.join(dirPath,entry.name);if(entry.isDirectory()){if(entry.name==="node_modules"){continue}tsFiles=tsFiles.concat(getTsFilesRecursive(fullPath))}else if(entry.isFile()&&entry.name.endsWith(".ts")){if(!entry.name.endsWith(".d.ts")){tsFiles.push(fullPath)}}}}catch(error){console.error("Error reading directory ".concat(dirPath,": ").concat(error.message))}return tsFiles}function findFunctionCalls(filePaths){var foundCalls=[];var _loop_1=function(filePath){try{var sourceText=fs.readFileSync(filePath,"utf8");var sourceFile_1=ts.createSourceFile(path.basename(filePath),sourceText,ts.ScriptTarget.ESNext,true,ts.ScriptKind.Unknown);var visit_1=function(node){if(ts.isCallExpression(node)){var functionName=null;var expression=node.expression;if(ts.isIdentifier(expression)){functionName=expression.text}if(functionName&&targetFunctionNames.has(functionName)){var _a=ts.getLineAndCharacterOfPosition(sourceFile_1,node.getStart()),line=_a.line,character=_a.character;var argsText_1=[];var errorMessage_1;var assertionId_1;if(node.arguments&&node.arguments.length>0){node.arguments.forEach((function(arg){argsText_1.push(arg.getText(sourceFile_1));if(ts.isStringLiteral(arg)){errorMessage_1=arg.getText(sourceFile_1)}else if(ts.isNumericLiteral(arg)){assertionId_1=parseInt(arg.getText(sourceFile_1),10)}}))}foundCalls.push({fileName:filePath,functionName:functionName,line:line+1,character:character+1,argumentsText:argsText_1,errorMessage:errorMessage_1,assertionId:assertionId_1!==null&&assertionId_1!==void 0?assertionId_1:-1})}}ts.forEachChild(node,visit_1)};visit_1(sourceFile_1)}catch(error){console.error("Error processing file ".concat(filePath,": ").concat(error.message))}};for(var _i=0,filePaths_1=filePaths;_i<filePaths_1.length;_i++){var filePath=filePaths_1[_i];_loop_1(filePath)}return foundCalls}function handleList(occurrences){if(occurrences.length===0){log("No assertion ids found.");return}occurrences.sort((function(a,b){return a.assertionId-b.assertionId})).forEach((function(call){console.log("ID: ".concat(call.assertionId,"; MESSAGE: ").concat(call.errorMessage,"; SOURCE: '").concat(call.functionName,"' call at ").concat(path.relative(process.cwd(),call.fileName),":").concat(call.line,":").concat(call.character))}))}function handleFind(occurrences,targetId){var target=typeof targetId==="number"?targetId:targetId.toString();var foundLocations=occurrences.filter((function(o){return String(o.assertionId)===String(target)}));if(foundLocations.length===0){log('Assertion id "'.concat(targetId,'" not found.'));process.exit(1)}handleList(foundLocations)}function handleCheck(occurrences){if(occurrences.length===0){log("No assertion ids found to check for duplicates.");return}var idCounts={};occurrences.forEach((function(occ){var codeStr=String(occ.assertionId);if(!idCounts[codeStr]){idCounts[codeStr]=[]}idCounts[codeStr].push(occ)}));var duplicatesFound=false;log("Checking for duplicate assertion id usage:");Object.entries(idCounts).forEach((function(_a){var code=_a[0],locations=_a[1];if(locations.length>1){duplicatesFound=true;console.error('\nDuplicate assertion id "'.concat(code,'" found at ').concat(locations.length," locations:"));locations.forEach((function(loc){var relativePath=path.relative(process.cwd(),loc.fileName);console.error("- ".concat(relativePath,":").concat(loc.line,":").concat(loc.character))}))}}));if(!duplicatesFound){log("No duplicate assertion ids found.")}else{process.exit(1)}}function handleNew(occurrences){var maxCode=0;occurrences.forEach((function(occ){if(occ.assertionId>maxCode){maxCode=occ.assertionId}}));if(occurrences.length===0){log("0");return}var newCode=maxCode+1;console.log(newCode)}function main(){return __awaiter(this,void 0,void 0,(function(){var argv,targetDirectory,stats,filesToScan,allOccurrences;return __generator(this,(function(_a){argv=(0,yargs_1.default)((0,helpers_1.hideBin)(process.argv)).usage("Usage: $0 [options]").option("dir",{alias:"D",describe:"Directory to scan recursively for TS files",type:"string",demandOption:true}).option("verbose",{alias:"V",describe:"verbose",type:"boolean"}).option("find",{alias:"F",describe:"Find locations of a specific {assertionId}",type:"string",nargs:1}).option("list",{alias:"L",describe:"List all unique assertion ids found (default action)",type:"boolean"}).option("new",{alias:"N",describe:"Suggest a new assertion id based on existing ones",type:"boolean"}).option("check",{alias:"C",describe:"Check for duplicate usage of assertion ids",type:"boolean"}).check((function(argv){var options=[argv.F,argv.L,argv.N,argv.C].filter(Boolean).length;if(options>1){throw new Error("Options -F, -L, -N, -C are mutually exclusive.")}return true})).help().alias("help","h").strict().parse();targetDirectory=path.resolve(argv["dir"]);isVerbose=!!argv["verbose"];try{stats=fs.statSync(targetDirectory);if(!stats.isDirectory()){console.error("Error: Provided path is not a directory: ".concat(targetDirectory));process.exit(1)}}catch(error){console.error("Error accessing directory ".concat(targetDirectory,": ").concat(error.message));process.exit(1)}log("Scanning directory: ".concat(targetDirectory));filesToScan=getTsFilesRecursive(targetDirectory);if(filesToScan.length===0){log("No relevant .ts or .tsx files found.");process.exit(0)}log("Found ".concat(filesToScan.length," files. Analyzing for assertion ids..."));allOccurrences=findFunctionCalls(filesToScan);log("Scan complete. Found ".concat(allOccurrences.length," potential assertion id occurrences."));if(argv["find"]){handleFind(allOccurrences,argv["find"])}else if(argv["new"]){handleNew(allOccurrences)}else if(argv["check"]){handleCheck(allOccurrences)}else{handleList(allOccurrences)}return[2]}))}))}main().catch((function(error){console.error("\nAn unexpected error occurred:");console.error(error);process.exit(1)}));