Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS-599 Use a single method to find files #5165

Merged
merged 2 commits into from
Mar 5, 2025
Merged

JS-599 Use a single method to find files #5165

merged 2 commits into from
Mar 5, 2025

Conversation

vdiez
Copy link
Contributor

@vdiez vdiez commented Mar 4, 2025

JS-599

logic around dealing with tsconfig files and lookup moves into projectAnalyzer.ts instead of program.ts, as it's there where it is used. find-files.ts helper has been removed as it was too convoluted

Once we are able to blacklist rules per extension (like no-var for HTML), the ruling will not need to search for files at all and just hand everything over to projectAnalyzer. Right now we still need to do it because ruling will remove that rule from the linter before proceeding with HTML analysis

Added a configuration object in the project analysis to reflect what sonar properties we may need to be sent from the Java part. Not all of them are supported at the moment.

@vdiez vdiez requested a review from zglicz March 4, 2025 11:26
@hashicorp-vault-sonar-prod hashicorp-vault-sonar-prod bot changed the title Use a single method to find files JS-599 Use a single method to find files Mar 4, 2025
@vdiez vdiez force-pushed the single-find-files branch 5 times, most recently from 84d31a5 to 724ef5b Compare March 5, 2025 15:05
Copy link
Contributor

@zglicz zglicz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Big, big prs. In general makes sense :)


export async function findFiles(
dir: string,
onFile: (file: Dirent) => Promise<void>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why onFile and not return the files? If this using onFile, would a yield be good as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's just like an event watcher. I'm allowing the consumer of this function to pass any function with whatever they want to do with the file that was just found. i don't think a yield is applicable here, or I'm missing the point

Comment on lines +134 to +132
if (testPaths?.some(testPath => parent.startsWith(testPath))) {
fileType = 'TEST';
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should there be a isTestFile method with a good test suite? Or will it only be based on the provided paths?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not sure about this. We only enter here if we call analyze-project without sending the files, allowing node.js to search for them instead. In that case only the path matters, but as I say I may clean up this after the POC I want to do next week

for (const tsConfigPath of tsConfigPaths) {
const tsConfig = join(baseDir, tsConfigPath.trim());
try {
await access(tsConfig);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whats access?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, probably should change that name. access it a function that checks if the file passes all filters: size, minified or not, and bundled or not

Comment on lines 62 to 65
const maxFiles =
typeof maxFilesForTypeChecking === 'undefined'
? DEFAULT_MAX_FILES_FOR_TYPE_CHECKING
: maxFilesForTypeChecking;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null coalescing?

Suggested change
const maxFiles =
typeof maxFilesForTypeChecking === 'undefined'
? DEFAULT_MAX_FILES_FOR_TYPE_CHECKING
: maxFilesForTypeChecking;
const maxFiles = maxFilesForTypeChecking ?? DEFAULT_MAX_FILES_FOR_TYPE_CHECKING;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, but I changed that in latest commit, I want the default to be managed by the project-analyzer function, not here. now it's mandatory

*/
export async function writeTSConfigFile(tsConfig: TsConfigJson): Promise<{ filename: string }> {
const filename = await new Promise<string>((resolve, reject) => {
tmp.file({ template: 'tsconfig-XXXXXX.json' }, function _tempFileCreated(err, path) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will it be XXXXXX or it will be replaces?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

taken from tmp options:
https://www.npmjs.com/package/tmp#options

it was just a random filename, not even .json. I think it's better to have a more meaningful filename.

expect(getTSConfigsCount()).toEqual(3);
});

it('should write tsconfig file', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here you don't clearTSConfigs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't depend at all on what tsconfigs are known, this is 100% stateless

Comment on lines +95 to +126
const jsTsFiles = {},
htmlFiles = {},
yamlFiles = {};
await findFiles(
projectPath,
async file => {
const filePath = toUnixPath(join(file.parentPath, file.name));
const fileType = testPath && dirname(filePath).startsWith(testPath) ? 'TEST' : 'MAIN';
if (isHtmlFile(filePath)) {
htmlFiles[filePath] = { fileType, filePath };
} else if (isYamlFile(filePath)) {
yamlFiles[filePath] = { fileType, filePath };
} else if (isJsTsFile(filePath)) {
const fileContent = await fs.readFile(filePath, 'utf8');
if (accept(filePath, fileContent)) {
jsTsFiles[filePath] = { fileType, filePath, fileContent };
}
}
},
DEFAULT_EXCLUSIONS.concat((exclusions || '').split(',')),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't like helper methods?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to remove that very soon...

expect(await getAsyncIteratorValue(tsconfigs)).toEqual(undefined);
});

it('when no tsconfigs, in SonarQube should generate tsconfig with all files', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So will you rename to: AnalysisSonarQube and AnalysisSonarLint? I would like this to at least be consistent. The names we have currently are: AnalysisWithProgram and AnalysisWithoutProgram, so please use a common strategy

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can discuss this. not so long ago SQ was also using watch programs if there were Vue files present.

Comment on lines 273 to 305
it('when no tsconfigs, in SonarLint should generate tsconfig with wildcard', async () => {
clearTSConfigs();
const baseDir = toUnixPath(join(fixtures, 'module'));
const files = await loadFiles(baseDir, {});
const tsconfigs = getTSConfigsIterator(Object.keys(files), baseDir, true, 200);
const tsconfig = await getAsyncIteratorValue(tsconfigs);
expect(basename(tsconfig)).toMatch(/tsconfig-\w{6}\.json/);
expect(JSON.parse(await readFile(tsconfig, 'utf8'))).toMatchObject({
compilerOptions: {
allowJs: true,
noImplicitAny: true,
},
include: [`${baseDir}/**/*`],
});
expect(await getAsyncIteratorValue(tsconfigs)).toEqual(undefined);
});

it('when no tsconfigs, in SonarQube should generate tsconfig with all files', async () => {
clearTSConfigs();
const baseDir = toUnixPath(join(fixtures, 'module'));
const files = await loadFiles(baseDir, {});
const tsconfigs = getTSConfigsIterator(Object.keys(files), baseDir, false, 200);
const tsconfig = await getAsyncIteratorValue(tsconfigs);
expect(basename(tsconfig)).toMatch(/tsconfig-\w{6}\.json/);
expect(JSON.parse(await readFile(tsconfig, 'utf8'))).toMatchObject({
compilerOptions: {
allowJs: true,
noImplicitAny: true,
},
files: [`${baseDir}/file.ts`, `${baseDir}/string42.ts`],
});
expect(await getAsyncIteratorValue(tsconfigs)).toEqual(undefined);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same test with just a flag difference? Could you refactor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you prefer it.each?

export async function* getTSConfigsIterator(
files: string[],
baseDir: string,
sonarLint: boolean,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I like this boolean argument here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you propose?

@vdiez vdiez force-pushed the single-find-files branch from f4713f1 to 647781c Compare March 5, 2025 16:59
@vdiez vdiez merged commit ab64477 into master Mar 5, 2025
17 of 18 checks passed
@vdiez vdiez deleted the single-find-files branch March 5, 2025 17:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants