diff --git a/swc-plugins/.eslintignore b/swc-plugins/.eslintignore
index 318bf5e..7eaeda2 100644
--- a/swc-plugins/.eslintignore
+++ b/swc-plugins/.eslintignore
@@ -1,8 +1,3 @@
*.d.ts
/lib/generated
/components/ui
-
-
-# TODO: Fix eslint config
-app/
-lib/
\ No newline at end of file
diff --git a/swc-plugins/.eslintrc.json b/swc-plugins/.eslintrc.json
index 9ecac64..b1a0a62 100644
--- a/swc-plugins/.eslintrc.json
+++ b/swc-plugins/.eslintrc.json
@@ -1,6 +1,8 @@
{
"extends": "next/core-web-vitals",
"rules": {
- "@typescript-eslint/no-unused-vars": "off"
+ "@typescript-eslint/no-unused-vars": "off",
+ "@next/next/no-server-import-in-page": "off",
+ "@typescript-eslint/ban-types": "off"
}
}
diff --git a/swc-plugins/app/import/page.tsx b/swc-plugins/app/import/page.tsx
deleted file mode 100644
index 22c5214..0000000
--- a/swc-plugins/app/import/page.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import fs from "node:fs/promises";
-
-export default async function Page() {
- if (process.env.NODE_ENV === "production") {
- return
Not allowed
;
- }
-
- const plugins = JSON.parse(
- await fs.readFile("./data/.cache/plugins.json", "utf8")
- );
-}
-
-export const dynamic = "force-dynamic";
diff --git a/swc-plugins/app/import/runtime/route.ts b/swc-plugins/app/import/runtime/route.ts
new file mode 100644
index 0000000..74172a9
--- /dev/null
+++ b/swc-plugins/app/import/runtime/route.ts
@@ -0,0 +1,70 @@
+import { db } from "@/lib/prisma";
+import { createCaller } from "@/lib/server";
+import { NextRequest, NextResponse } from "next/server";
+import { z } from "zod";
+
+const VersionSchema = z.object({
+ version: z.string(),
+ swcCoreVersion: z.string(),
+});
+
+const BodySchema = z.object({
+ runtime: z.enum(["@swc/core", "next", "rspack"]),
+ versions: z.array(VersionSchema),
+});
+
+export async function POST(req: NextRequest) {
+ if (process.env.NODE_ENV === "production") {
+ return NextResponse.json(
+ {
+ error: "Not allowed",
+ },
+ {
+ status: 403,
+ }
+ );
+ }
+
+ const { runtime, versions } = BodySchema.parse(await req.json());
+
+ const rt = await db.swcRuntime.findUniqueOrThrow({
+ where: {
+ name: runtime,
+ },
+ });
+ const api = await createCaller();
+
+ const items: {
+ runtimeId: bigint;
+ version: string;
+ compatRangeId: bigint;
+ swcCoreVersion: string;
+ }[] = [];
+
+ for (const version of versions) {
+ const compatRange = await api.compatRange.byVersion({
+ version: version.swcCoreVersion,
+ });
+ if (!compatRange) {
+ console.log(`No compat range found for ${version.swcCoreVersion}`);
+ continue;
+ }
+
+ items.push({
+ runtimeId: rt.id,
+ // Just to ensure it's a valid semver
+ version: version.version.replace("v", ""),
+ compatRangeId: compatRange.id,
+ // Just to ensure it's a valid semver
+ swcCoreVersion: version.swcCoreVersion.replace("v", ""),
+ });
+ }
+
+ await db.swcRuntimeVersion.createMany({
+ data: items,
+ });
+
+ return NextResponse.json({
+ ok: true,
+ });
+}
diff --git a/swc-plugins/data/ranges.json b/swc-plugins/data/ranges.json
index 63db482..9780423 100644
--- a/swc-plugins/data/ranges.json
+++ b/swc-plugins/data/ranges.json
@@ -4,7 +4,7 @@
"max": "0.59.40"
},
{
- "min": "v0.61.0",
+ "min": "0.61.0",
"max": "0.64.10"
},
{
diff --git a/swc-plugins/lib/api/compatRange/router.ts b/swc-plugins/lib/api/compatRange/router.ts
index 8972132..1b110e2 100644
--- a/swc-plugins/lib/api/compatRange/router.ts
+++ b/swc-plugins/lib/api/compatRange/router.ts
@@ -122,11 +122,7 @@ export const compatRangeRouter = router({
});
for (const range of versions) {
- if (semver.lt(version, range.from)) {
- continue;
- }
-
- if (semver.gte(version, range.to)) {
+ if (semver.gt(version, range.from) && semver.lt(version, range.to)) {
return range;
}
}
@@ -160,7 +156,8 @@ function merge(ranges: { name: string; version: string }[]): VersionRange[] {
* @param newValue semver
*/
function mergeVersion(min: string, max: string, newValue: string) {
- const minVersion = semver.lt(min, newValue) ? min : newValue;
+ const minVersion =
+ min !== "0.0.0" && semver.lt(min, newValue) ? min : newValue;
const maxVersion = semver.gt(max, newValue) ? max : newValue;
return { min: minVersion, max: maxVersion };
diff --git a/swc-plugins/package.json b/swc-plugins/package.json
index 319fa46..e8d26f1 100644
--- a/swc-plugins/package.json
+++ b/swc-plugins/package.json
@@ -91,8 +91,10 @@
"postcss": "8.4.33",
"prisma": "^5.17.0",
"tailwindcss": "3.4.1",
+ "toml": "^3.0.0",
"tsconfig-replace-paths": "^0.0.14",
"typescript": "^5.5.4",
- "zod-prisma-types": "^3.1.6"
+ "zod-prisma-types": "^3.1.6",
+ "zx": "^8.1.4"
}
}
diff --git a/swc-plugins/prisma/schema.prisma b/swc-plugins/prisma/schema.prisma
index fccd69e..13f46d8 100644
--- a/swc-plugins/prisma/schema.prisma
+++ b/swc-plugins/prisma/schema.prisma
@@ -155,14 +155,16 @@ model SwcRuntime {
}
model SwcRuntimeVersion {
- id BigInt @id @default(autoincrement())
- runtime SwcRuntime @relation(fields: [runtimeId], references: [id], onDelete: Cascade)
- runtimeId BigInt
- version String
- compatRange CompatRange @relation(fields: [compatRangeId], references: [id])
- compatRangeId BigInt
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
+ id BigInt @id @default(autoincrement())
+ runtime SwcRuntime @relation(fields: [runtimeId], references: [id], onDelete: Cascade)
+ runtimeId BigInt
+ version String
+ /// The version of `swc_core` used by the plugin.
+ swcCoreVersion String
+ compatRange CompatRange @relation(fields: [compatRangeId], references: [id])
+ compatRangeId BigInt
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
@@unique([runtimeId, version])
}
@@ -176,14 +178,17 @@ model SwcPlugin {
}
model SwcPluginVersion {
- id BigInt @id @default(autoincrement())
- plugin SwcPlugin @relation(fields: [pluginId], references: [id], onDelete: Cascade)
- pluginId BigInt
- version String
- compatRange CompatRange @relation(fields: [compatRangeId], references: [id])
- compatRangeId BigInt
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
+ id BigInt @id @default(autoincrement())
+ plugin SwcPlugin @relation(fields: [pluginId], references: [id], onDelete: Cascade)
+ pluginId BigInt
+ /// The version of the plugin.
+ version String
+ /// The version of `swc_core` used by the plugin.
+ swcCoreVersion String?
+ compatRange CompatRange @relation(fields: [compatRangeId], references: [id])
+ compatRangeId BigInt
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
@@unique([pluginId, version])
}
diff --git a/swc-plugins/scripts/import-runtime.mjs b/swc-plugins/scripts/import-runtime.mjs
new file mode 100755
index 0000000..64f8963
--- /dev/null
+++ b/swc-plugins/scripts/import-runtime.mjs
@@ -0,0 +1,86 @@
+#!/usr/bin/env zx
+//
+// Run this script using an absolute path to the runtime directory.
+import path from "path";
+import semver from "semver";
+import toml from "toml";
+import { $ } from "zx";
+
+const runtimeName = process.argv[2];
+const runtimeDir = process.argv[3];
+
+if (!runtimeName || !runtimeDir) {
+ console.error("Runtime name and directory are required");
+ process.exit(1);
+}
+
+const $$ = $({ cwd: runtimeDir });
+
+const repositoryRoot = (await $$`git rev-parse --show-toplevel`.text()).trim();
+const cargoLockPath = path.resolve(`${runtimeDir}/Cargo.lock`);
+const relativePathToCargoLock = path.relative(repositoryRoot, cargoLockPath);
+
+console.log("Runtime name:", runtimeName);
+console.log("Runtime dir:", runtimeDir);
+console.log("Repository root:", repositoryRoot);
+console.log("Cargo.lock path:", cargoLockPath);
+console.log("Relative path to Cargo.lock:", relativePathToCargoLock);
+
+// Get all git tags
+const gitTags = (await $$`git tag`.text()).split("\n");
+
+const data = {
+ runtime: runtimeName,
+ versions: [],
+};
+
+// For each tag, get the content of `${runtimeDir}/Cargo.lock`.
+for (const tag of gitTags) {
+ let tagVersion = tag.replace("v", "");
+ if (!semver.valid(tagVersion)) {
+ console.log(`Skipping tag ${tag} because it is not a valid semver`);
+ continue;
+ }
+
+ try {
+ const cargoLock =
+ await $$`git show ${tag}:${relativePathToCargoLock}`.text();
+
+ const parsed = toml.parse(cargoLock);
+ const packages = parsed.package;
+
+ for (const pkg of packages) {
+ if (pkg.name === "swc_core") {
+ const swcCoreVersion = pkg.version;
+
+ data.versions.push({
+ version: tagVersion,
+ swcCoreVersion,
+ });
+ console.log(`Found swc_core version ${swcCoreVersion} for tag ${tag}`);
+ }
+ }
+
+ // Send the data to the server
+ if (data.versions.length >= 20) {
+ await fetch("http://localhost:50000/import/runtime", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(data),
+ });
+ data.versions = [];
+ }
+ } catch (e) {
+ console.error(`Failed to parse Cargo.lock for tag ${tag}: ${e}`);
+ }
+}
+
+await fetch("http://localhost:50000/import/runtime", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(data),
+});