Skip to content

Commit

Permalink
feat(swc-plugin): Add version data of swc_core and `swc_plugin_runn…
Browse files Browse the repository at this point in the history
…er` (#53)
  • Loading branch information
kdy1 authored Aug 27, 2024
1 parent f16e38f commit 6c2b43c
Show file tree
Hide file tree
Showing 9 changed files with 332 additions and 42 deletions.
3 changes: 3 additions & 0 deletions apps/swc-plugins/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

# scripts
.cache/

This file was deleted.

2 changes: 1 addition & 1 deletion apps/swc-plugins/app/compat/core/[version]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default function Page({
}: {
params: { version: string };
}) {
const [compatRange] = apiClient.compatRange.byVersion.useSuspenseQuery({
const [compatRange] = apiClient.compatRange.byCoreVersion.useSuspenseQuery({
version,
});

Expand Down
2 changes: 1 addition & 1 deletion apps/swc-plugins/app/import/runtime/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export async function POST(req: NextRequest) {
const api = await createCaller();

for (const version of versions) {
const compatRange = await api.compatRange.byVersion({
const compatRange = await api.compatRange.byCoreVersion({
version: version.swcCoreVersion,
});
if (!compatRange) {
Expand Down
29 changes: 29 additions & 0 deletions apps/swc-plugins/app/import/swc_core/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { createCaller } from "@/lib/server";
import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";

const CoreVersionSchema = z.object({
version: z.string(),
pluginRunnerReq: z.string(),
});

const BodySchema = z.object({
coreVersions: z.array(CoreVersionSchema),
pluginRunnerVersions: z.array(z.string()),
});

export async function POST(req: NextRequest) {
const api = await createCaller();
const { coreVersions, pluginRunnerVersions } = BodySchema.parse(
await req.json()
);

await api.compatRange.addCacheForCrates({
coreVersions,
pluginRunnerVersions,
});

return NextResponse.json({
ok: true,
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { createCaller } from "@/lib/server";
import { redirect } from "next/navigation";

export default async function Page({
params: { version },
}: {
params: { version: string };
}) {
const api = await createCaller();
const compatRange = await api.compatRange.byPluginRunnerVersion({
version,
});

if (compatRange) {
return redirect(`/compat/range/${compatRange.id}`);
}

return <div>No compat range found for swc_plugin_runner@{version}</div>;
}
215 changes: 194 additions & 21 deletions apps/swc-plugins/lib/api/compatRange/router.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { publicProcedure, router } from "@/lib/base";
import { db } from "@/lib/prisma";
import { TRPCError } from "@trpc/server";
import semver from "semver";
import { z } from "zod";
import { VersionRange, VersionRangeSchema } from "./zod";

export const CompatRangeSchema = z.object({
id: z.bigint(),
from: z.string(),
to: z.string(),
});

export const compatRangeRouter = router({
list: publicProcedure
.input(z.void())
.output(
z.array(
z.object({
id: z.bigint(),
from: z.string(),
to: z.string(),
})
)
)
.output(z.array(CompatRangeSchema))
.query(async ({ ctx }) => {
const versions = await db.compatRange.findMany({
orderBy: {
Expand Down Expand Up @@ -97,31 +96,72 @@ export const compatRangeRouter = router({
};
}),

byVersion: publicProcedure
byPluginRunnerVersion: publicProcedure
.input(
z.object({
version: z.string(),
version: z.string().describe("The version of the swc_plugin_runner"),
})
)
.output(
z.nullable(
z.object({
id: z.bigint(),
from: z.string(),
to: z.string(),
})
)
.output(z.nullable(CompatRangeSchema))
.query(async ({ ctx, input: { version } }) => {
const v = await db.swcPluginRunnerVersion.findUnique({
where: {
version,
},
select: {
compatRange: {
select: {
id: true,
from: true,
to: true,
},
},
},
});

return v?.compatRange ?? null;
}),

byCoreVersion: publicProcedure
.input(
z.object({
version: z.string(),
})
)
.output(z.nullable(CompatRangeSchema))
.query(async ({ ctx, input: { version } }) => {
const versions = await db.compatRange.findMany({
// Try the cache first.
{
const v = await db.swcCoreVersion.findUnique({
where: {
version,
},
select: {
compatRange: {
select: {
id: true,
from: true,
to: true,
},
},
},
});

if (v) {
return v.compatRange;
}
}

console.warn("Fallback to full search");
const compatRanges = await db.compatRange.findMany({
select: {
id: true,
from: true,
to: true,
},
});

for (const range of versions) {
for (const range of compatRanges) {
if (
semver.gte(version, range.from) &&
(range.to === "*" || semver.lte(version, range.to))
Expand All @@ -132,6 +172,115 @@ export const compatRangeRouter = router({

return null;
}),

addCacheForCrates: publicProcedure
.input(
z.object({
pluginRunnerVersions: z.array(z.string()),
coreVersions: z.array(
z.object({
version: z.string().describe("The version of the swc_core"),
pluginRunnerReq: z.string(),
})
),
})
)
.output(z.void())
.mutation(
async ({ ctx, input: { coreVersions, pluginRunnerVersions } }) => {
if (process.env.NODE_ENV === "production") {
throw new TRPCError({
code: "FORBIDDEN",
});
}

const previousMaxCoreVersion = await maxSwcCoreVersion();
const previousMaxPluginRunnerVersion =
await maxSwcPluginRunnerVersion();

const compatRanges = await db.compatRange.findMany({
select: {
id: true,
from: true,
to: true,
},
});

const done = new Set<string>();

function byVersion(swcCoreVersion: string) {
for (const range of compatRanges) {
if (
semver.gte(swcCoreVersion, range.from) &&
(range.to === "*" || semver.lte(swcCoreVersion, range.to))
) {
return range;
}
}
}

for (const corePkg of coreVersions) {
corePkg.version = corePkg.version.replace("v", "");

if (semver.lt(corePkg.version, previousMaxCoreVersion)) {
console.log(
`Skipping swc_core@${corePkg.version} as it's less than previous max (${previousMaxCoreVersion})`
);
continue;
}

const compatRange = byVersion(corePkg.version);

if (!compatRange) {
console.error(`Compat range not found for ${corePkg.version}`);
continue;
}

for (let rv of pluginRunnerVersions) {
rv = rv.replace("v", "");

if (done.has(rv)) {
continue;
}
if (semver.lt(rv, previousMaxPluginRunnerVersion)) {
continue;
}

if (semver.satisfies(rv, corePkg.pluginRunnerReq)) {
await db.swcPluginRunnerVersion.upsert({
where: {
version: rv,
},
create: {
version: rv,
compatRangeId: compatRange.id,
},
update: {
compatRangeId: compatRange.id,
},
});
console.log(`Imported swc_plugin_runner@${rv}`);
done.add(rv);
}
}

await db.swcCoreVersion.upsert({
where: {
version: corePkg.version,
},
create: {
version: corePkg.version,
pluginRunnerReq: corePkg.pluginRunnerReq,
compatRangeId: compatRange.id,
},
update: {
pluginRunnerReq: corePkg.pluginRunnerReq,
},
});
console.log(`Imported swc_core@${corePkg.version}`);
}
}
),
});

function merge(ranges: { name: string; version: string }[]): VersionRange[] {
Expand Down Expand Up @@ -165,3 +314,27 @@ function mergeVersion(min: string, max: string, newValue: string) {

return { min: minVersion, max: maxVersion };
}

async function maxSwcCoreVersion() {
const coreVersions = await db.swcCoreVersion.findMany({
select: {
version: true,
},
});

return coreVersions.reduce((max, core) => {
return semver.gt(max, core.version) ? max : core.version;
}, "0.0.0");
}

async function maxSwcPluginRunnerVersion() {
const pluginRunnerVersions = await db.swcPluginRunnerVersion.findMany({
select: {
version: true,
},
});

return pluginRunnerVersions.reduce((max, pluginRunner) => {
return semver.gt(max, pluginRunner.version) ? max : pluginRunner.version;
}, "0.0.0");
}
38 changes: 31 additions & 7 deletions apps/swc-plugins/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,15 @@ model TeamInvitation {

/// The range of versions of the `swc_core` that a plugin is compatible with.
model CompatRange {
id BigInt @id @default(autoincrement())
from String
to String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
runtimes SwcRuntimeVersion[]
plugins SwcPluginVersion[]
id BigInt @id @default(autoincrement())
from String
to String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
runtimes SwcRuntimeVersion[]
plugins SwcPluginVersion[]
coreVersions SwcCoreVersion[]
SwcPluginRunnerVersion SwcPluginRunnerVersion[]
@@unique([from, to])
}
Expand Down Expand Up @@ -194,3 +196,25 @@ model SwcPluginVersion {
@@unique([pluginId, version])
}

model SwcCoreVersion {
id BigInt @id @default(autoincrement())
/// The version of the (exact) `swc_core` package.
version String @unique
/// Semver range of the `swc_plugin_runner` package that is compatible with this version of `swc_core`.
pluginRunnerReq String?
compatRange CompatRange @relation(fields: [compatRangeId], references: [id])
compatRangeId BigInt
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

model SwcPluginRunnerVersion {
id BigInt @id @default(autoincrement())
/// The version of the `swc_plugin_runner` package.
version String @unique
compatRange CompatRange @relation(fields: [compatRangeId], references: [id])
compatRangeId BigInt
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Loading

0 comments on commit 6c2b43c

Please sign in to comment.