PromucFlow_constructor/app/server/scripts/check-field-constants.mjs
Shrikant Sharat Kandula 41a66a1168
chore: Tiny NodeJS script as a linter for field name constants (#31766)
The point is to prevent unfortunate field name problems like this:
https://github.com/appsmithorg/appsmith/pull/31760/files.

This NodeJS script does a very rudimentary analysis on all Java files,
with a few regular expressions, and finds anomalies. As such, since it's
not very smart, it's quite strict. I intend to make it a little more
strict in the coming days, but it's a start.

It's not hooked into any processes/CI yet, but that will also come in
next. Since it's not very smart, it actually runs quite fast (.8s on
EE).

The script also doesn't exit with a non-zero exit code when it finds a
problem. Also will be solved as part of integrating it into CI.
2024-03-14 06:30:40 +05:30

66 lines
2.0 KiB
JavaScript

import {promises as fs} from "fs";
import path from "path";
async function findInnerClassDefinitions(directory) {
try {
const files = await fs.readdir(directory);
for (const file of files) {
const filePath = path.join(directory, file);
const stats = await fs.stat(filePath);
if (stats.isDirectory()) {
await findInnerClassDefinitions(filePath);
} else if (path.extname(filePath) === '.java') {
await processJavaFile(filePath);
}
}
} catch (err) {
console.error(err);
}
}
async function processJavaFile(filePath) {
try {
const contents = await fs.readFile(filePath, 'utf8');
const innerClassRegex = /^ {4}([\w ]+?)\s+class\s+Fields\s+(extends (\w+)\.Fields)?\s*{(.+?\n {4})?}$/gsm;
for (const innerClassMatch of contents.matchAll(innerClassRegex)) {
const classQualifiers = innerClassMatch[1]; // we don't care much about this
const expectedParentClass = innerClassMatch[3];
console.log(filePath, classQualifiers, expectedParentClass);
for (const match of innerClassMatch[0].matchAll(/\bpublic\s+static\s+final\s+String\s+(\w+)\s+=\s+(.+?);/gs)) {
const key = match[1]
const valMatcherParts = [`^dotted\\(`];
for (const [i, field] of key.split("_").entries()) {
if (i > 0) {
valMatcherParts.push(`\\s*,\\s+`);
}
valMatcherParts.push(`(\\w+\\.\\w+\\.)?${field}`);
}
valMatcherParts.push(`\\s*\\)$`);
const valMatcher = new RegExp(valMatcherParts.join(''));
if (!valMatcher.test(match[2])) {
console.log("key is", key);
console.log("val is", match[2]);
console.log("pattern", valMatcher);
console.error(`Field ${key} in ${filePath} is not looking right.`);
}
}
}
// if (finds.length > 1) {
// console.error(`Found multiple inner class definitions in file: ${filePath}`);
// return;
// }
} catch (err) {
console.error(err);
}
}
const directoryPath = '.';
findInnerClassDefinitions(directoryPath);