Releasing 0.25.77 (#968)

Squash commits
This commit is contained in:
vorotamoroz
2026-06-19 17:45:37 +09:00
committed by GitHub
parent c6c4044f3c
commit 62f44e38c0
453 changed files with 29917 additions and 727 deletions
+1 -5
View File
@@ -26,11 +26,7 @@ for (const sourceFile of project.getSourceFiles()) {
const posixFilePath = toPosixPath(filePath);
if (!posixFilePath.startsWith(posixSrc)) continue;
if (
posixFilePath.includes("/_test/") ||
posixFilePath.endsWith(".spec.ts") ||
posixFilePath.endsWith(".test.ts")
) {
if (posixFilePath.includes("/_test/") || posixFilePath.endsWith(".spec.ts") || posixFilePath.endsWith(".test.ts")) {
continue;
}
+12 -6
View File
@@ -40,6 +40,7 @@ function toPosixPath(filePath: string): string {
const posixProjectRoot = toPosixPath(projectRoot);
const posixSrc = `${posixProjectRoot}/src`;
const posixLibSrc = `${posixProjectRoot}/src/lib/src`;
const posixSubrepo = `${posixProjectRoot}/src/lib`;
console.log(`Project Root: ${posixProjectRoot}`);
console.log(`Source Directory: ${posixSrc}`);
@@ -93,12 +94,6 @@ for (const sourceFile of project.getSourceFiles()) {
continue;
}
// Keep relative sibling/child imports unchanged (e.g. ./utils) unless --all-alias is set.
const isSibling = isRelative && !moduleSpecifier.startsWith("..");
if (isSibling && !allAlias) {
continue;
}
// Resolve path to an absolute POSIX path.
let resolvedPath = "";
if (moduleSpecifier.startsWith("@lib/")) {
@@ -112,6 +107,17 @@ for (const sourceFile of project.getSourceFiles()) {
resolvedPath = toPosixPath(path.normalize(resolvedPath));
// Keep relative sibling/child imports unchanged (e.g. ./utils) unless:
// 1. --all-alias is set, OR
// 2. the import crosses the subrepository boundary (src/lib/)
const isSibling = isRelative && !moduleSpecifier.startsWith("..");
const importerInsideSubrepo = posixFilePath.startsWith(posixSubrepo + "/");
const targetInsideSubrepo = resolvedPath.startsWith(posixSubrepo + "/");
const crossesSubrepo = importerInsideSubrepo !== targetInsideSubrepo;
if (isSibling && !allAlias && !crossesSubrepo) {
continue;
}
// Determine correct normalised specifier.
let newSpecifier = "";
const hasExtension =
+2 -1
View File
@@ -37,7 +37,8 @@ for (const sourceFile of project.getSourceFiles()) {
const posixFilePath = toPosixPath(filePath);
if (!posixFilePath.startsWith(posixSrc)) continue;
if (posixFilePath.includes("/_test/") || posixFilePath.endsWith(".spec.ts") || posixFilePath.endsWith(".test.ts")) continue;
if (posixFilePath.includes("/_test/") || posixFilePath.endsWith(".spec.ts") || posixFilePath.endsWith(".test.ts"))
continue;
// Find AsExpression (expr as Type) and TypeAssertion (<Type>expr)
const asExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.AsExpression);
+3 -3
View File
@@ -69,7 +69,7 @@ for (const sourceFile of project.getSourceFiles()) {
for (const impDecl of importDeclarations) {
const specifier = impDecl.getModuleSpecifierValue();
// Check if it's a Node.js built-in module we want to redirect
let exportedName = "";
if (specifier === "fs/promises" || specifier === "node:fs/promises") {
@@ -92,11 +92,11 @@ for (const sourceFile of project.getSourceFiles()) {
if (targetImports.length > 0) {
console.log(`File: ${posixFilePath.slice(posixProjectRoot.length + 1)}`);
for (const { impDecl, exportedName, localName } of targetImports) {
const { line } = sourceFile.getLineAndColumnAtPos(impDecl.getStart());
console.log(` Line ${line}: Redirecting "${impDecl.getText()}"`);
if (exportedName === localName) {
namedImportsToAdd.push(exportedName);
} else {
+12 -9
View File
@@ -38,7 +38,8 @@ for (const sourceFile of project.getSourceFiles()) {
const posixFilePath = toPosixPath(filePath);
if (!posixFilePath.startsWith(posixSrc)) continue;
if (posixFilePath.includes("/_test/") || posixFilePath.endsWith(".spec.ts") || posixFilePath.endsWith(".test.ts")) continue;
if (posixFilePath.includes("/_test/") || posixFilePath.endsWith(".spec.ts") || posixFilePath.endsWith(".test.ts"))
continue;
let fileModified = false;
@@ -51,10 +52,11 @@ for (const sourceFile of project.getSourceFiles()) {
if (varDec) {
const varName = varDec.getName();
// Count references within the catch clause itself
const count = catchClause.getDescendantsOfKind(SyntaxKind.Identifier)
.filter((id) => id.getText() === varName)
.length;
if (count === 1) { // Only the declaration itself
const count = catchClause
.getDescendantsOfKind(SyntaxKind.Identifier)
.filter((id) => id.getText() === varName).length;
if (count === 1) {
// Only the declaration itself
catchVarsToRemove.push(varDec);
}
}
@@ -86,10 +88,11 @@ for (const sourceFile of project.getSourceFiles()) {
for (const namedImport of namedImports) {
const importName = namedImport.getAliasNode()?.getText() ?? namedImport.getName();
// Count references in the entire file
const count = sourceFile.getDescendantsOfKind(SyntaxKind.Identifier)
.filter((id) => id.getText() === importName)
.length;
if (count === 1) { // Only the import specifier itself
const count = sourceFile
.getDescendantsOfKind(SyntaxKind.Identifier)
.filter((id) => id.getText() === importName).length;
if (count === 1) {
// Only the import specifier itself
importsToRemove.push({ namedImport, impDecl });
}
}
+192 -27
View File
@@ -1,41 +1,194 @@
import { Project, SyntaxKind } from "npm:ts-morph";
function processFile(filePath: string) {
function processFile(filePath: string, origin: string, repoHash: string): string {
const project = new Project();
const sourceFile = project.addSourceFileAtPath(filePath);
let updated = false;
// 1. Collect all 'any' type nodes in the file
const anyTypeNodes = sourceFile.getDescendantsOfKind(SyntaxKind.AnyKeyword);
const sourceText = sourceFile.getFullText();
const lineBreak = sourceText.includes("\r\n") ? "\r\n" : "\n";
const lines = sourceText.split(/\r?\n/);
const targetLines = new Set<number>();
// 0. insert a commit hash comment at the top of the file
sourceFile.insertText(0, `// @ts-nocheck\n// REPO: ${origin} Commit hash: ${repoHash}\n`);
updated = true;
// 2. Collect the line numbers that contain 'any'
anyTypeNodes.forEach((anyNode: any) => {
const { line } = sourceFile.getLineAndColumnAtPos(anyNode.getStart());
targetLines.add(line - 1);
// 1. Replacements for Uint8Array<ArrayBuffer> and DataView<ArrayBuffer>
let sourceText = sourceFile.getFullText();
if (sourceText.includes("Uint8Array<ArrayBuffer>") || sourceText.includes("DataView<ArrayBuffer>")) {
sourceText = sourceText.replace(/Uint8Array<ArrayBuffer>/g, "Uint8Array");
sourceText = sourceText.replace(/DataView<ArrayBuffer>/g, "DataView");
sourceFile.replaceWithText(sourceText);
updated = true;
}
// 2. Remove EventEmitter import from "events" and declare class EventEmitter inline
const imports = sourceFile.getImportDeclarations();
imports.forEach((importDecl) => {
if (importDecl.getModuleSpecifierValue() === "events") {
const defaultImport = importDecl.getDefaultImport();
if (defaultImport && defaultImport.getText() === "EventEmitter") {
importDecl.remove();
sourceFile.addClass({
name: "EventEmitter",
isExported: false,
methods: [
{
name: "on",
parameters: [
{ name: "event", type: "string | symbol" },
{ name: "listener", type: "(...args: any[]) => void" },
],
returnType: "this",
},
{
name: "once",
parameters: [
{ name: "event", type: "string | symbol" },
{ name: "listener", type: "(...args: any[]) => void" },
],
returnType: "this",
},
{
name: "off",
parameters: [
{ name: "event", type: "string | symbol" },
{ name: "listener", type: "(...args: any[]) => void" },
],
returnType: "this",
},
{
name: "emit",
parameters: [
{ name: "event", type: "string | symbol" },
{ name: "args", isRestParameter: true, type: "any[]" },
],
returnType: "boolean",
},
{
name: "addListener",
parameters: [
{ name: "event", type: "string | symbol" },
{ name: "listener", type: "(...args: any[]) => void" },
],
returnType: "this",
},
{
name: "removeListener",
parameters: [
{ name: "event", type: "string | symbol" },
{ name: "listener", type: "(...args: any[]) => void" },
],
returnType: "this",
},
{
name: "removeAllListeners",
parameters: [{ name: "event", isOptional: true, type: "string | symbol" }],
returnType: "this",
},
],
});
updated = true;
}
}
});
// 3. Add an inline disable only to lines that contain 'any'
for (const lineIndex of targetLines) {
// 3. Collect targets for inline disable comments
const targetAnyLines = new Set<number>();
const targetEmptyObjectLines = new Set<number>();
const targetEmptyInterfaceLines = new Set<number>();
const targetDuplicateEnumLines = new Set<number>();
// 3.1. 'any' type nodes
const anyTypeNodes = sourceFile.getDescendantsOfKind(SyntaxKind.AnyKeyword);
anyTypeNodes.forEach((anyNode: any) => {
const { line } = sourceFile.getLineAndColumnAtPos(anyNode.getStart());
targetAnyLines.add(line - 1);
});
// 3.2. Empty object type literals {}
const typeLiterals = sourceFile.getDescendantsOfKind(SyntaxKind.TypeLiteral);
typeLiterals.forEach((node) => {
if (node.getMembers().length === 0) {
const { line } = sourceFile.getLineAndColumnAtPos(node.getStart());
targetEmptyObjectLines.add(line - 1);
}
});
// 3.3. Empty interfaces
const interfaces = sourceFile.getInterfaces();
interfaces.forEach((node) => {
if (node.getMembers().length === 0) {
const { line } = sourceFile.getLineAndColumnAtPos(node.getStart());
targetEmptyInterfaceLines.add(line - 1);
}
});
// 3.4. Duplicate enum member values
const enums = sourceFile.getEnums();
enums.forEach((enumDecl) => {
const values = new Set<string>();
enumDecl.getMembers().forEach((member) => {
const initValue = member.getInitializer()?.getText();
if (initValue) {
if (values.has(initValue)) {
const { line } = sourceFile.getLineAndColumnAtPos(member.getStart());
targetDuplicateEnumLines.add(line - 1);
} else {
values.add(initValue);
}
}
});
});
// 4. Inject ignore comments line by line
const finalSourceText = sourceFile.getFullText();
const lineBreak = finalSourceText.includes("\r\n") ? "\r\n" : "\n";
const lines = finalSourceText.split(/\r?\n/);
// 4.1. Add inline disable to lines that contain 'any'
for (const lineIndex of targetAnyLines) {
const line = lines[lineIndex];
if (!line) {
continue;
}
if (line.includes("eslint-disable-line @typescript-eslint/no-explicit-any")) {
continue;
}
lines[lineIndex] = `${line} // eslint-disable-line @typescript-eslint/no-explicit-any`;
if (!line) continue;
if (line.includes("eslint-disable-line @typescript-eslint/no-explicit-any")) continue;
lines[lineIndex] = `${line} // eslint-disable-line @typescript-eslint/no-explicit-any -- Only type declaration`;
updated = true;
}
// 4.2. Add inline disable to lines that contain empty object {}
for (const lineIndex of targetEmptyObjectLines) {
const line = lines[lineIndex];
if (!line) continue;
if (line.includes("eslint-disable-line") || line.includes("eslint-disable-next-line")) continue;
lines[lineIndex] =
`${line} // eslint-disable-line @typescript-eslint/no-empty-object-type, @typescript-eslint/ban-types -- Empty object type`;
updated = true;
}
// 4.3. Add inline disable to lines that contain empty interface
for (const lineIndex of targetEmptyInterfaceLines) {
const line = lines[lineIndex];
if (!line) continue;
if (line.includes("eslint-disable-line") || line.includes("eslint-disable-next-line")) continue;
lines[lineIndex] =
`${line} // eslint-disable-line @typescript-eslint/no-empty-object-type, @typescript-eslint/no-empty-interface -- Empty interface`;
updated = true;
}
// 4.4. Add inline disable to lines with duplicate enums
for (const lineIndex of targetDuplicateEnumLines) {
const line = lines[lineIndex];
if (!line) continue;
if (line.includes("eslint-disable-line") || line.includes("eslint-disable-next-line")) continue;
lines[lineIndex] =
`${line} // eslint-disable-line @typescript-eslint/no-duplicate-enum-values -- Duplicate enum value`;
updated = true;
}
const updatedSourceText = lines.join(lineBreak);
// Output the result
if (updated) {
console.log(`Processed file: ${filePath}`);
}
return updatedSourceText;
}
const targetDir = `./_types/`;
const targetDir = `./_types`;
async function processDir(dirPath: string) {
for await (const entry of Deno.readDir(dirPath)) {
@@ -45,14 +198,26 @@ async function processDir(dirPath: string) {
if (entry.isFile && entry.name.endsWith(".d.ts")) {
const filePath = `${dirPath}/${entry.name}`;
console.log(`Processing: ${filePath}`);
const updatedContent = processFile(filePath);
const updatedContent = processFile(filePath, repoRemoteOriginStr, gitCommitHashStr);
// Write the file. To revert, regenerate it with npm run lib:build:types.
await Deno.writeTextFile(filePath, updatedContent);
// console.log(`Updated content for ${filePath}:\n${updatedContent}\n`);
console.log(`Processed: ${filePath}`);
}
}
}
const subDir = "./src/lib/";
const repoRemoteOrigins = new Deno.Command("git", {
args: ["remote", "get-url", "origin"],
cwd: subDir,
stdout: "piped",
}).outputSync().stdout;
const repoRemoteOriginStr = new TextDecoder().decode(repoRemoteOrigins).trim();
console.log(`STAMP: Git remote origin: ${repoRemoteOriginStr}`);
const gitCommitHashSub = new Deno.Command("git", {
args: ["rev-parse", "--short", "HEAD"],
cwd: subDir,
stdout: "piped",
}).outputSync().stdout;
const gitCommitHashStr = new TextDecoder().decode(gitCommitHashSub).trim();
console.log(`STAMP: Git commit hash: ${gitCommitHashStr}`);
await processDir(targetDir);