| 1 | import * as NodeFsPromises from "node:fs/promises"; |
| 2 | import * as NodePath from "node:path"; |
| 3 | import { describe, expect, it } from "vitest"; |
| 4 | |
| 5 | const GENERIC_MODULES = ["Vocs.ts", "Target.ts", "index.ts"]; |
| 6 | const FORBIDDEN = [ |
| 7 | /^@alchemy\.run\/cloudflare-runtime/, |
| 8 | /^@cloudflare\//, |
| 9 | /cloudflare:/, |
| 10 | /(^|\/)cloudflare(\.ts|\.js)?$/, |
| 11 | /\.\.\/waku\/cloudflare\.ts$/, |
| 12 | ]; |
| 13 | |
| 14 | const importSpecifiers = (source: string): Array<string> => { |
| 15 | const specifiers: Array<string> = []; |
| 16 | for (const pattern of [ |
| 17 | /(?:^|\n)\s*(?:import|export)\s[^;]*?from\s*["']([^"']+)["']/g, |
| 18 | /(?:^|\n)\s*import\s*["']([^"']+)["']/g, |
| 19 | /import\s*\(\s*["']([^"']+)["']\s*\)/g, |
| 20 | ]) { |
| 21 | for (const match of source.matchAll(pattern)) specifiers.push(match[1]!); |
| 22 | } |
| 23 | return specifiers; |
| 24 | }; |
| 25 | |
| 26 | describe("Vocs target decoupling", () => { |
| 27 | for (const module of GENERIC_MODULES) { |
| 28 | it(`${module} imports nothing Cloudflare-specific`, async () => { |
| 29 | const source = await NodeFsPromises.readFile( |
| 30 | NodePath.resolve(import.meta.dirname, "..", module), |
| 31 | "utf8", |
| 32 | ); |
| 33 | const offending = importSpecifiers(source).filter((specifier) => |
| 34 | FORBIDDEN.some((pattern) => pattern.test(specifier)), |
| 35 | ); |
| 36 | expect(offending).toEqual([]); |
| 37 | }); |
| 38 | } |
| 39 | |
| 40 | it("cloudflare.ts owns the Waku Cloudflare target composition", async () => { |
| 41 | const source = await NodeFsPromises.readFile( |
| 42 | NodePath.resolve(import.meta.dirname, "../cloudflare.ts"), |
| 43 | "utf8", |
| 44 | ); |
| 45 | expect(importSpecifiers(source)).toContain("../waku/cloudflare.ts"); |
| 46 | }); |
| 47 | }); |