Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
92d081e
Add option for JSON output file
AlexanderKaran Mar 2, 2026
4a326c0
Moved back to JSON output
AlexanderKaran Mar 2, 2026
6d7fa88
Merge branch 'main' into json-output
AlexanderKaran Mar 7, 2026
ebcc668
Adding Core-JS detection to CLI
AlexanderKaran Mar 7, 2026
d0ea974
Update core-js.ts
AlexanderKaran Mar 7, 2026
41ad4bf
Merge branch 'main' into core-js
AlexanderKaran Mar 7, 2026
a294200
Fixed lint issues in test
AlexanderKaran Mar 7, 2026
6ee96de
Update src/analyze/core-js.ts
AlexanderKaran Mar 7, 2026
7dbceb9
Move to filesystem
AlexanderKaran Mar 7, 2026
c467923
Change target
AlexanderKaran Mar 7, 2026
cea0f8e
Added comment
AlexanderKaran Mar 7, 2026
7c65fcf
More detection
AlexanderKaran Mar 7, 2026
23c9933
Import
AlexanderKaran Mar 7, 2026
c12813c
Removed build check
AlexanderKaran Mar 17, 2026
43c3c03
Merge branch 'main' into core-js
AlexanderKaran Mar 17, 2026
c4865b9
Install
AlexanderKaran Mar 17, 2026
f61c510
Vitest Version Missmatch
AlexanderKaran Mar 17, 2026
6a67e80
Merge branch 'vitest' into core-js
AlexanderKaran Mar 17, 2026
496aa0b
Merged in vitest fix
AlexanderKaran Mar 17, 2026
e0b6e77
Removed lock
AlexanderKaran Mar 17, 2026
27e68df
Fixes
AlexanderKaran Mar 26, 2026
6bda1fb
Merge branch 'main' into core-js
AlexanderKaran Mar 26, 2026
5bcc793
Updated package
AlexanderKaran Mar 26, 2026
a4c11ea
Updated files filter
AlexanderKaran Apr 4, 2026
9ff9ae3
chore(deps): bump module-replacements (#199)
dependabot[bot] Mar 30, 2026
9f72f65
chore: move module-replacements URLs (#204)
43081j Apr 4, 2026
c2170a3
Add script to generate fixable syntax replacements
alieron Apr 6, 2026
e8f6095
Add simple syntax replacement plugin for analyze
alieron Apr 6, 2026
4990e4d
Remove code generation and add check to analyze command
alieron May 10, 2026
f6176b5
Merge branch 'main' into feat/syntax-replacement
alieron May 10, 2026
40c060b
Restore generate module replacements script in package.json
alieron May 10, 2026
7cba628
Merge branch 'main' into feat/syntax-replacement
43081j May 10, 2026
5e998f5
chore: revert sorting keys
43081j May 10, 2026
52f7d00
De-dupe source files glob
alieron May 10, 2026
bad8ed6
Import CodeMod interface from the codemods package
alieron May 10, 2026
a794a30
Add tests for web features codemods analysis
alieron May 10, 2026
4658645
Add additional testcases
alieron May 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 174 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@
"homepage": "https://github.com/e18e/cli#readme",
"dependencies": {
"@clack/prompts": "^1.3.0",
"@e18e/web-features-codemods": "^0.2.0",
"fast-wrap-ansi": "^0.2.0",
"@publint/pack": "^0.1.4",
"fast-wrap-ansi": "^0.2.0",
"fdir": "^6.5.0",
"gunshi": "^0.29.5",
"lockparse": "^0.5.0",
Expand Down
10 changes: 1 addition & 9 deletions src/analyze/core-js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {glob} from 'tinyglobby';
import {minVersion} from 'semver';
import {relative, join} from 'path';
import type {AnalysisContext, ReportPluginResult} from '../types.js';
import {SOURCE_GLOB, SOURCE_IGNORE} from '../utils/source-files.js';

import coreJsCompat from 'core-js-compat';

Expand All @@ -12,15 +13,6 @@ const BROAD_IMPORTS = new Set([
'core-js/full'
]);

const SOURCE_GLOB = ['**/*.{js,ts,mjs,cjs,jsx,tsx}'];
const SOURCE_IGNORE = [
'**/node_modules/**',
'**/dist/**',
'**/build/**',
'**/coverage/**',
'**/lib/**'
];

const IMPORT_RE =
/(?:import\s+(?:.*\s+from\s+)?|require\s*\()\s*['"]([^'"]+)['"]/g;

Expand Down
4 changes: 3 additions & 1 deletion src/analyze/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ import {getPackageJson, detectLockfile} from '../utils/package-json.js';
import {parse as parseLockfile} from 'lockparse';
import {runDuplicateDependencyAnalysis} from './duplicate-dependencies.js';
import {runCoreJsAnalysis} from './core-js.js';
import {runWebFeaturesCodemodsAnalysis} from './web-features-codemods.js';

const plugins: ReportPlugin[] = [
runPublint,
runReplacements,
runDependencyAnalysis,
runDuplicateDependencyAnalysis,
runCoreJsAnalysis
runCoreJsAnalysis,
runWebFeaturesCodemodsAnalysis
];

async function computeInfo(fileSystem: FileSystem) {
Expand Down
69 changes: 69 additions & 0 deletions src/analyze/web-features-codemods.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import {glob} from 'tinyglobby';
import {join, relative} from 'node:path';
import * as WebFeatureCodemodExports from '@e18e/web-features-codemods';
// TODO: change this once CodeMod is exported from @e18e/web-features-codemods
import type {CodeMod} from '@e18e/web-features-codemods/lib/shared.js';
import type {AnalysisContext, ReportPluginResult} from '../types.js';
import {SOURCE_GLOB, SOURCE_IGNORE} from '../utils/source-files.js';

function isWebFeatureCodemod(value: unknown): value is CodeMod {
return (
typeof value === 'object' &&
value !== null &&
'test' in value &&
typeof value.test === 'function' &&
'apply' in value &&
typeof value.apply === 'function'
);
}

const webFeatureCodemods = Object.entries(WebFeatureCodemodExports).filter(
(entry): entry is [string, CodeMod] => isWebFeatureCodemod(entry[1])
);

export async function runWebFeaturesCodemodsAnalysis(
context: AnalysisContext
): Promise<ReportPluginResult> {
const messages: ReportPluginResult['messages'] = [];

const srcGlobs = context.options?.src;
const patterns = srcGlobs && srcGlobs.length > 0 ? srcGlobs : SOURCE_GLOB;
const allFiles = await glob(patterns, {
cwd: context.root,
ignore: SOURCE_IGNORE
});
// filter out any paths that escaped context.root via ../
const files = allFiles.filter(
(f) => !relative(context.root, join(context.root, f)).startsWith('..')
);

for (const filePath of files) {
let source: string;
try {
source = await context.fs.readFile(filePath);
} catch {
continue;
}

const matches: string[] = [];
for (const [name, codemod] of webFeatureCodemods) {
try {
if (codemod.test({source})) {
matches.push(name);
}
} catch {
continue;
}
}

if (matches.length > 0) {
messages.push({
severity: 'suggestion',
score: 0,
message: `File "${filePath}" can use newer web features: ${matches.join(', ')}.`
});
}
}

return {messages};
}
45 changes: 45 additions & 0 deletions src/test/analyze/__snapshots__/web-features-codemods.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`runWebFeaturesCodemodsAnalysis > handles a file with multiple matches 1`] = `
[
{
"message": "File "index.js" can use newer web features: arrayAt, exponentiation.",
"score": 0,
"severity": "suggestion",
},
]
`;

exports[`runWebFeaturesCodemodsAnalysis > handles a file with no matches 1`] = `[]`;

exports[`runWebFeaturesCodemodsAnalysis > handles a file with one match 1`] = `
[
{
"message": "File "index.js" can use newer web features: arrayAt.",
"score": 0,
"severity": "suggestion",
},
]
`;

exports[`runWebFeaturesCodemodsAnalysis > handles multiple occurrences of the same match in one file 1`] = `
[
{
"message": "File "index.js" can use newer web features: arrayAt.",
"score": 0,
"severity": "suggestion",
},
]
`;

exports[`runWebFeaturesCodemodsAnalysis > ignores a file path outside of the root 1`] = `[]`;

exports[`runWebFeaturesCodemodsAnalysis > respects the src option 1`] = `
[
{
"message": "File "src/index.js" can use newer web features: arrayAt.",
"score": 0,
"severity": "suggestion",
},
]
`;
Loading
Loading