Remove rnadom script
This commit is contained in:
parent
9256377c13
commit
20433bd9f0
5 changed files with 936 additions and 250 deletions
|
|
@ -30,10 +30,11 @@ jobs:
|
||||||
npx playwright install --with-deps chromium
|
npx playwright install --with-deps chromium
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: npm run lint
|
run: npm run lint:check
|
||||||
|
|
||||||
- name: Typecheck
|
- name: Typecheck
|
||||||
run: |
|
run: |
|
||||||
|
npm run unused:check
|
||||||
npm run typecheck
|
npm run typecheck
|
||||||
npm run typecheck:e2e
|
npm run typecheck:e2e
|
||||||
|
|
||||||
|
|
|
||||||
931
package-lock.json
generated
931
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -8,18 +8,17 @@
|
||||||
"dev": "vite --host 0.0.0.0",
|
"dev": "vite --host 0.0.0.0",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"lint": "npm run lint:check",
|
|
||||||
"lint:check": "eslint --rule \"prettier/prettier: off\" \"src/**/*.ts\" && npm run unused:check",
|
"lint:check": "eslint --rule \"prettier/prettier: off\" \"src/**/*.ts\" && npm run unused:check",
|
||||||
"lint:fix": "eslint --fix \"src/**/*.ts\"",
|
"lint:fix": "eslint --fix \"src/**/*.ts\"",
|
||||||
"format": "prettier --write \"index.html\" \"src/**/*.{ts,scss,json,html}\" \"scripts/**/*.mjs\" \"e2e/**/*.ts\" \".forgejo/workflows/*.yml\" \"*.{json,js,ts,md}\" \".prettierrc\"",
|
"format": "prettier --write \"index.html\" \"src/**/*.{ts,scss,json,html}\" \"e2e/**/*.ts\" \".forgejo/workflows/*.yml\" \"*.{json,js,ts,md}\" \".prettierrc\"",
|
||||||
"format:check": "prettier --check \"index.html\" \"src/**/*.{ts,scss,json,html}\" \"scripts/**/*.mjs\" \"e2e/**/*.ts\" \".forgejo/workflows/*.yml\" \"*.{json,js,ts,md}\" \".prettierrc\"",
|
"format:check": "prettier --check \"index.html\" \"src/**/*.{ts,scss,json,html}\" \"e2e/**/*.ts\" \".forgejo/workflows/*.yml\" \"*.{json,js,ts,md}\" \".prettierrc\"",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"typecheck:e2e": "tsc --noEmit --project tsconfig.playwright.json",
|
"typecheck:e2e": "tsc --noEmit --project tsconfig.playwright.json",
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"test:e2e": "npm run build && playwright test",
|
"test:e2e": "npm run build && playwright test",
|
||||||
"test:e2e:ui": "npm run build && playwright test --ui",
|
"test:e2e:ui": "npm run build && playwright test --ui",
|
||||||
"test:watch": "vitest",
|
"test:watch": "vitest",
|
||||||
"unused:check": "node scripts/check-unused-exports.mjs",
|
"unused:check": "knip --exports --include-entry-exports",
|
||||||
"generate-icons": "pwa-assets-generator",
|
"generate-icons": "pwa-assets-generator",
|
||||||
"update": "ncu"
|
"update": "ncu"
|
||||||
},
|
},
|
||||||
|
|
@ -57,6 +56,7 @@
|
||||||
"eslint-plugin-unused-imports": "^4.4.1",
|
"eslint-plugin-unused-imports": "^4.4.1",
|
||||||
"gl-matrix": "^3.4.4",
|
"gl-matrix": "^3.4.4",
|
||||||
"globals": "^17.6.0",
|
"globals": "^17.6.0",
|
||||||
|
"knip": "^6.14.1",
|
||||||
"lightningcss": "^1.32.0",
|
"lightningcss": "^1.32.0",
|
||||||
"npm-check-updates": "^22.1.0",
|
"npm-check-updates": "^22.1.0",
|
||||||
"prettier": "^3.8.3",
|
"prettier": "^3.8.3",
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
||||||
|
|
||||||
<title>Not found</title>
|
|
||||||
<meta name="theme-color" content="#b7455e" />
|
|
||||||
<meta name="viewport" content="initial-scale=1.0" />
|
|
||||||
<style>
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
background-color: #b7455e;
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1,
|
|
||||||
a {
|
|
||||||
font-family: 'Roboto', 'Helvetica Neue', sans-serif;
|
|
||||||
font-weight: 100;
|
|
||||||
font-size: 3rem;
|
|
||||||
color: white;
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div>
|
|
||||||
<h1>Page not found.</h1>
|
|
||||||
<a href="/">Go back</a>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,197 +0,0 @@
|
||||||
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
||||||
import path from 'node:path';
|
|
||||||
import ts from 'typescript';
|
|
||||||
|
|
||||||
const projectRoot = process.cwd();
|
|
||||||
const sourceRoot = path.join(projectRoot, 'src');
|
|
||||||
|
|
||||||
const toPosix = (value) => value.split(path.sep).join('/');
|
|
||||||
|
|
||||||
const listTypeScriptFiles = (directory) =>
|
|
||||||
readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
|
|
||||||
const entryPath = path.join(directory, entry.name);
|
|
||||||
if (entry.isDirectory()) {
|
|
||||||
return listTypeScriptFiles(entryPath);
|
|
||||||
}
|
|
||||||
return entry.isFile() && entry.name.endsWith('.ts') && !entry.name.endsWith('.d.ts')
|
|
||||||
? [entryPath]
|
|
||||||
: [];
|
|
||||||
});
|
|
||||||
|
|
||||||
const files = listTypeScriptFiles(sourceRoot);
|
|
||||||
const fileSet = new Set(files.map((file) => path.resolve(file)));
|
|
||||||
|
|
||||||
const resolveModule = (fromFile, specifier) => {
|
|
||||||
if (!specifier.startsWith('.')) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const base = path.resolve(path.dirname(fromFile), specifier);
|
|
||||||
const candidates = [
|
|
||||||
`${base}.ts`,
|
|
||||||
path.join(base, 'index.ts'),
|
|
||||||
base.endsWith('.ts') ? base : null,
|
|
||||||
].filter(Boolean);
|
|
||||||
|
|
||||||
return (
|
|
||||||
candidates.find((candidate) => existsSync(candidate) && fileSet.has(candidate)) ??
|
|
||||||
null
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const exportKey = (file, name) => `${path.resolve(file)}:${name}`;
|
|
||||||
const isExported = (node) =>
|
|
||||||
ts.canHaveModifiers(node) &&
|
|
||||||
(ts.getModifiers(node) ?? []).some(
|
|
||||||
(modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword
|
|
||||||
);
|
|
||||||
const isDefaultExported = (node) =>
|
|
||||||
ts.canHaveModifiers(node) &&
|
|
||||||
(ts.getModifiers(node) ?? []).some(
|
|
||||||
(modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword
|
|
||||||
);
|
|
||||||
|
|
||||||
const exportedDeclarations = new Map();
|
|
||||||
const usedExports = new Set();
|
|
||||||
const wildcardUsedFiles = new Set();
|
|
||||||
|
|
||||||
const markUsed = (fromFile, name) => {
|
|
||||||
usedExports.add(exportKey(fromFile, name));
|
|
||||||
};
|
|
||||||
|
|
||||||
const collectImportUsage = (file, sourceFile) => {
|
|
||||||
sourceFile.forEachChild((node) => {
|
|
||||||
if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
|
|
||||||
const resolved = resolveModule(file, node.moduleSpecifier.text);
|
|
||||||
if (!resolved || !node.importClause) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.importClause.name) {
|
|
||||||
markUsed(resolved, 'default');
|
|
||||||
}
|
|
||||||
|
|
||||||
const namedBindings = node.importClause.namedBindings;
|
|
||||||
if (namedBindings && ts.isNamedImports(namedBindings)) {
|
|
||||||
namedBindings.elements.forEach((element) => {
|
|
||||||
markUsed(resolved, (element.propertyName ?? element.name).text);
|
|
||||||
});
|
|
||||||
} else if (namedBindings && ts.isNamespaceImport(namedBindings)) {
|
|
||||||
wildcardUsedFiles.add(path.resolve(resolved));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
ts.isExportDeclaration(node) &&
|
|
||||||
node.moduleSpecifier &&
|
|
||||||
ts.isStringLiteral(node.moduleSpecifier)
|
|
||||||
) {
|
|
||||||
const resolved = resolveModule(file, node.moduleSpecifier.text);
|
|
||||||
if (!resolved) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!node.exportClause) {
|
|
||||||
wildcardUsedFiles.add(path.resolve(resolved));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ts.isNamedExports(node.exportClause)) {
|
|
||||||
node.exportClause.elements.forEach((element) => {
|
|
||||||
markUsed(resolved, (element.propertyName ?? element.name).text);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const collectExportedDeclarations = (file, sourceFile) => {
|
|
||||||
if (file.endsWith('.test.ts')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceFile.forEachChild((node) => {
|
|
||||||
if (ts.isVariableStatement(node) && isExported(node)) {
|
|
||||||
node.declarationList.declarations.forEach((declaration) => {
|
|
||||||
if (ts.isIdentifier(declaration.name)) {
|
|
||||||
exportedDeclarations.set(exportKey(file, declaration.name.text), {
|
|
||||||
file,
|
|
||||||
name: declaration.name.text,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(ts.isFunctionDeclaration(node) ||
|
|
||||||
ts.isClassDeclaration(node) ||
|
|
||||||
ts.isInterfaceDeclaration(node) ||
|
|
||||||
ts.isTypeAliasDeclaration(node) ||
|
|
||||||
ts.isEnumDeclaration(node)) &&
|
|
||||||
isExported(node)
|
|
||||||
) {
|
|
||||||
if (isDefaultExported(node)) {
|
|
||||||
exportedDeclarations.set(exportKey(file, 'default'), { file, name: 'default' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.name) {
|
|
||||||
exportedDeclarations.set(exportKey(file, node.name.text), {
|
|
||||||
file,
|
|
||||||
name: node.name.text,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
ts.isExportDeclaration(node) &&
|
|
||||||
!node.moduleSpecifier &&
|
|
||||||
node.exportClause &&
|
|
||||||
ts.isNamedExports(node.exportClause)
|
|
||||||
) {
|
|
||||||
node.exportClause.elements.forEach((element) => {
|
|
||||||
exportedDeclarations.set(exportKey(file, element.name.text), {
|
|
||||||
file,
|
|
||||||
name: element.name.text,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const parsedFiles = files.map((file) => ({
|
|
||||||
file,
|
|
||||||
sourceFile: ts.createSourceFile(
|
|
||||||
file,
|
|
||||||
readFileSync(file, 'utf8'),
|
|
||||||
ts.ScriptTarget.Latest,
|
|
||||||
true,
|
|
||||||
ts.ScriptKind.TS
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
parsedFiles.forEach(({ file, sourceFile }) => collectImportUsage(file, sourceFile));
|
|
||||||
parsedFiles.forEach(({ file, sourceFile }) =>
|
|
||||||
collectExportedDeclarations(file, sourceFile)
|
|
||||||
);
|
|
||||||
|
|
||||||
const unusedExports = Array.from(exportedDeclarations.entries())
|
|
||||||
.filter(
|
|
||||||
([key, declaration]) =>
|
|
||||||
!usedExports.has(key) && !wildcardUsedFiles.has(declaration.file)
|
|
||||||
)
|
|
||||||
.map(([, declaration]) => declaration)
|
|
||||||
.sort((left, right) =>
|
|
||||||
`${left.file}:${left.name}`.localeCompare(`${right.file}:${right.name}`)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (unusedExports.length > 0) {
|
|
||||||
console.error('Unused exported declarations found:');
|
|
||||||
unusedExports.forEach(({ file, name }) => {
|
|
||||||
console.error(`- ${toPosix(path.relative(projectRoot, file))}: ${name}`);
|
|
||||||
});
|
|
||||||
process.exitCode = 1;
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue