diff --git a/scripts/unmonorepo/feature-spec.mjs b/scripts/unmonorepo/feature-spec.mjs deleted file mode 100644 index c7d31571..00000000 --- a/scripts/unmonorepo/feature-spec.mjs +++ /dev/null @@ -1,168 +0,0 @@ -import fs from "node:fs"; -import path from "node:path"; - -export function namespaceToPublicModule(namespace) { - if (!namespace.startsWith("WebApi")) { - throw new Error(`Unsupported namespace: ${namespace}`); - } - - return namespace.slice("WebApi".length); -} - -export function publicModuleToInternalPrefix(publicModule) { - return publicModule.replace(/[A-Z]+(?=[A-Z][a-z]|$)|[A-Z][a-z]*/g, (part) => { - return part[0] + part.slice(1).toLowerCase(); - }); -} - -export function publicNameForLeafModule(leafName, internalPrefix) { - const preservedPrefixedModules = new Set(["PushEvent"]); - const duplicatedSuffixes = ["Types", "Global", "Event", "File", "HTMLMediaElement"]; - - if (preservedPrefixedModules.has(leafName)) { - return leafName; - } - - for (const suffix of duplicatedSuffixes) { - if (leafName === `${internalPrefix}${suffix}`) { - return suffix; - } - } - - return leafName; -} - -const simplifiedLegacyLeaves = new Map([ - ["Canvas", new Map([["Global", "Canvas"]])], - ["Fetch", new Map([["Global", "Fetch"]])], - [ - "ServiceWorker", - new Map([["ServiceWorkerGlobalScope", "ServiceWorkerScope"]]), - ], - [ - "WebWorkers", - new Map([ - ["SharedWorkerGlobalScope", "SharedWorkerScope"], - ["WorkerGlobalScope", "Worker"], - ]), - ], -]); - -const legacyLeavesByCurrentLeaf = new Map( - [...simplifiedLegacyLeaves.entries()].map(([publicModule, leafMap]) => [ - publicModule, - new Map([...leafMap.entries()].map(([legacyLeaf, currentLeaf]) => [currentLeaf, legacyLeaf])), - ]), -); - -function simplifiedLeafName(spec, leafName) { - return simplifiedLegacyLeaves.get(spec.publicModule)?.get(leafName); -} - -export function legacyPublicNamesForLeafModule(leafName, spec) { - const names = [publicNameForLeafModule(leafName, spec.internalPrefix)]; - const legacyLeaf = legacyLeavesByCurrentLeaf.get(spec.publicModule)?.get(leafName); - - if (legacyLeaf !== undefined && !names.includes(legacyLeaf)) { - names.push(legacyLeaf); - } - - return names; -} - -export const featureSpecs = [ - ["Base", "WebApiBase"], - ["CSSFontLoading", "WebApiCSSFontLoading"], - ["Canvas", "WebApiCanvas"], - ["ChannelMessaging", "WebApiChannelMessaging"], - ["Clipboard", "WebApiClipboard"], - ["CredentialManagement", "WebApiCredentialManagement"], - ["DOM", "WebApiDOM"], - ["EncryptedMediaExtensions", "WebApiEncryptedMediaExtensions"], - ["Event", "WebApiEvent"], - ["Fetch", "WebApiFetch"], - ["File", "WebApiFile"], - ["FileAndDirectoryEntries", "WebApiFileAndDirectoryEntries"], - ["Gamepad", "WebApiGamepad"], - ["Geolocation", "WebApiGeolocation"], - ["History", "WebApiHistory"], - ["IndexedDB", "WebApiIndexedDB"], - ["IntersectionObserver", "WebApiIntersectionObserver"], - ["MediaCapabilities", "WebApiMediaCapabilities"], - ["MediaCaptureAndStreams", "WebApiMediaCaptureAndStreams"], - ["MediaSession", "WebApiMediaSession"], - ["MutationObserver", "WebApiMutationObserver"], - ["Notification", "WebApiNotification"], - ["Performance", "WebApiPerformance"], - ["Permissions", "WebApiPermissions"], - ["PictureInPicture", "WebApiPictureInPicture"], - ["Push", "WebApiPush"], - ["RemotePlayback", "WebApiRemotePlayback"], - ["ResizeObserver", "WebApiResizeObserver"], - ["ScreenWakeLock", "WebApiScreenWakeLock"], - ["ServiceWorker", "WebApiServiceWorker"], - ["Storage", "WebApiStorage"], - ["UIEvents", "WebApiUIEvents"], - ["URL", "WebApiURL"], - ["ViewTransitions", "WebApiViewTransitions"], - ["VisualViewport", "WebApiVisualViewport"], - ["WebAudio", "WebApiWebAudio"], - ["WebCrypto", "WebApiWebCrypto"], - ["WebLocks", "WebApiWebLocks"], - ["WebMIDI", "WebApiWebMIDI"], - ["WebSockets", "WebApiWebSockets"], - ["WebSpeech", "WebApiWebSpeech"], - ["WebStorage", "WebApiWebStorage"], - ["WebVTT", "WebApiWebVTT"], - ["WebWorkers", "WebApiWebWorkers"], -].map(([dirName, legacyNamespace]) => { - const publicModule = namespaceToPublicModule(legacyNamespace); - - return { - dirName, - legacyNamespace, - publicModule, - featureName: `WebAPI.${publicModule}`, - internalPrefix: publicModuleToInternalPrefix(publicModule), - sourceDir: `src/${dirName}`, - }; -}); - -export function migratedLeafName({ spec, leafName, duplicateLeaves }) { - if (spec.dirName === "Base" && leafName === "DOM") { - return "DOM"; - } - - const simplifiedName = simplifiedLeafName(spec, leafName); - if (simplifiedName !== undefined) { - return simplifiedName; - } - - if (leafName === spec.publicModule) { - return leafName; - } - - if (duplicateLeaves.has(leafName)) { - return `${spec.internalPrefix}${leafName}`; - } - - return leafName; -} - -export function findDuplicateLeafModules(rootDir, specs = featureSpecs) { - const counts = new Map(); - - for (const spec of specs) { - const legacySourceDir = path.join(rootDir, "packages", spec.dirName, "src"); - if (!fs.existsSync(legacySourceDir)) continue; - - for (const entry of fs.readdirSync(legacySourceDir, { withFileTypes: true })) { - if (!entry.isFile() || !entry.name.endsWith(".res")) continue; - - const leafName = path.basename(entry.name, ".res"); - counts.set(leafName, (counts.get(leafName) ?? 0) + 1); - } - } - - return new Set([...counts.entries()].filter(([, count]) => count > 1).map(([leafName]) => leafName)); -} diff --git a/scripts/unmonorepo/migrate-layout.mjs b/scripts/unmonorepo/migrate-layout.mjs deleted file mode 100644 index 020a6583..00000000 --- a/scripts/unmonorepo/migrate-layout.mjs +++ /dev/null @@ -1,50 +0,0 @@ -import fs from "node:fs"; -import path from "node:path"; -import { featureSpecs, findDuplicateLeafModules, migratedLeafName } from "./feature-spec.mjs"; - -function moveFile(fromPath, toPath) { - fs.mkdirSync(path.dirname(toPath), { recursive: true }); - fs.renameSync(fromPath, toPath); -} - -export function migrateLayout(rootDir) { - const duplicateLeaves = findDuplicateLeafModules(rootDir, featureSpecs); - - for (const spec of featureSpecs) { - const legacySourceDir = path.join(rootDir, "packages", spec.dirName, "src"); - if (!fs.existsSync(legacySourceDir)) continue; - - const nextSourceDir = path.join(rootDir, "src", spec.dirName); - fs.mkdirSync(nextSourceDir, { recursive: true }); - - for (const entry of fs.readdirSync(legacySourceDir, { withFileTypes: true })) { - if (!entry.isFile() || !entry.name.endsWith(".res")) continue; - - const leafName = path.basename(entry.name, ".res"); - const nextLeafName = migratedLeafName({ spec, leafName, duplicateLeaves }); - - moveFile( - path.join(legacySourceDir, entry.name), - path.join(nextSourceDir, `${nextLeafName}.res`), - ); - } - - for (const removable of ["package.json", "rescript.json", "lib"]) { - fs.rmSync(path.join(rootDir, "packages", spec.dirName, removable), { - recursive: true, - force: true, - }); - } - - fs.rmSync(path.join(rootDir, "packages", spec.dirName), { - recursive: true, - force: true, - }); - } - - fs.rmSync(path.join(rootDir, "packages", "Prelude"), { recursive: true, force: true }); -} - -if (process.argv.includes("--write")) { - migrateLayout(process.cwd()); -} diff --git a/scripts/unmonorepo/rewrite-references.mjs b/scripts/unmonorepo/rewrite-references.mjs deleted file mode 100644 index cd21f4cb..00000000 --- a/scripts/unmonorepo/rewrite-references.mjs +++ /dev/null @@ -1,127 +0,0 @@ -import fs from "node:fs"; -import path from "node:path"; -import { featureSpecs, legacyPublicNamesForLeafModule } from "./feature-spec.mjs"; - -function escapeRegExp(value) { - return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); -} - -function rewriteBareModuleReference(source, publicLeaf, leaf) { - const pattern = new RegExp(`(^|[^A-Za-z0-9_])${escapeRegExp(publicLeaf)}\\.`, "g"); - return source.replace(pattern, (match, prefix, offset, input) => { - const moduleStart = offset + prefix.length; - - if (prefix === "." && input.slice(Math.max(0, moduleStart - 3), moduleStart) !== "...") { - return match; - } - - return `${prefix}${leaf}.`; - }); -} - -function rewriteNestedFeatureReferences(source, { specs, leavesByFeature }) { - let next = source; - - for (const spec of specs) { - const leaves = leavesByFeature.get(spec.publicModule) ?? []; - - for (const leaf of leaves) { - for (const publicLeaf of legacyPublicNamesForLeafModule(leaf, spec)) { - next = next.replaceAll(`${spec.legacyNamespace}.${publicLeaf}.`, `${leaf}.`); - next = next.replaceAll(`WebAPI.${spec.publicModule}.${publicLeaf}.`, `${leaf}.`); - next = next.replaceAll(`WebApi.${spec.publicModule}.${publicLeaf}.`, `${leaf}.`); - next = next.replaceAll(`${spec.publicModule}.${publicLeaf}.`, `${leaf}.`); - } - } - } - - return next; -} - -export function rewriteSourceText( - source, - { currentFeature, specs, localLeaves, leavesByFeature = new Map([[currentFeature, localLeaves]]) }, -) { - const currentSpec = specs.find((spec) => spec.publicModule === currentFeature); - let next = rewriteNestedFeatureReferences(source, { specs, leavesByFeature }); - - for (const leaf of localLeaves) { - for (const publicLeaf of legacyPublicNamesForLeafModule(leaf, currentSpec)) { - next = next.replaceAll(`${currentSpec.legacyNamespace}.${publicLeaf}.`, `${leaf}.`); - next = next.replaceAll(`WebAPI.${currentSpec.publicModule}.${publicLeaf}.`, `${leaf}.`); - next = next.replaceAll(`WebApi.${currentSpec.publicModule}.${publicLeaf}.`, `${leaf}.`); - next = next.replaceAll(`${currentSpec.publicModule}.${publicLeaf}.`, `${leaf}.`); - - if (leaf !== publicLeaf) { - next = rewriteBareModuleReference(next, publicLeaf, leaf); - } - } - } - - return next; -} - -export function rewriteTestText(source, specs = featureSpecs, leavesByFeature = new Map()) { - return rewriteNestedFeatureReferences(source, { specs, leavesByFeature }); -} - -function rewriteTestFilesInDirectory(directoryPath, leavesByFeature) { - for (const entry of fs.readdirSync(directoryPath, { withFileTypes: true })) { - const entryPath = path.join(directoryPath, entry.name); - - if (entry.isDirectory()) { - rewriteTestFilesInDirectory(entryPath, leavesByFeature); - continue; - } - - if (!entry.isFile() || !entry.name.endsWith(".res")) continue; - fs.writeFileSync(entryPath, rewriteTestText(fs.readFileSync(entryPath, "utf8"), featureSpecs, leavesByFeature)); - } -} - -export function rewriteRepoReferences(rootDir) { - const leavesByFeature = new Map(); - - for (const spec of featureSpecs) { - const featureDir = path.join(rootDir, "src", spec.dirName); - if (!fs.existsSync(featureDir)) continue; - - const localLeaves = fs - .readdirSync(featureDir) - .filter((name) => name.endsWith(".res")) - .map((name) => path.basename(name, ".res")); - leavesByFeature.set(spec.publicModule, localLeaves); - } - - for (const spec of featureSpecs) { - const featureDir = path.join(rootDir, "src", spec.dirName); - if (!fs.existsSync(featureDir)) continue; - - const localLeaves = leavesByFeature.get(spec.publicModule); - - for (const fileName of fs.readdirSync(featureDir)) { - if (!fileName.endsWith(".res")) continue; - - const filePath = path.join(featureDir, fileName); - const source = fs.readFileSync(filePath, "utf8"); - fs.writeFileSync( - filePath, - rewriteSourceText(source, { - currentFeature: spec.publicModule, - specs: featureSpecs, - localLeaves, - leavesByFeature, - }), - ); - } - } - - const testsDir = path.join(rootDir, "tests"); - if (fs.existsSync(testsDir)) { - rewriteTestFilesInDirectory(testsDir, leavesByFeature); - } -} - -if (process.argv.includes("--write")) { - rewriteRepoReferences(process.cwd()); -} diff --git a/scripts/unmonorepo/write-root-config.mjs b/scripts/unmonorepo/write-root-config.mjs deleted file mode 100644 index 6f8572b4..00000000 --- a/scripts/unmonorepo/write-root-config.mjs +++ /dev/null @@ -1,87 +0,0 @@ -import fs from "node:fs"; -import path from "node:path"; -import { featureSpecs } from "./feature-spec.mjs"; - -export function isPublicModuleName(spec, moduleName) { - if (moduleName.endsWith("Types")) return false; - if (spec.dirName === "DOM" && moduleName === "DomGlobal") return false; - - return true; -} - -export function publicModulesForSourceDir(sourceDir, spec) { - if (!fs.existsSync(sourceDir)) return []; - - const publicModules = new Set(); - - for (const entry of fs.readdirSync(sourceDir, { withFileTypes: true })) { - if (!entry.isFile()) continue; - - const extension = path.extname(entry.name); - if (extension !== ".res" && extension !== ".resi") continue; - - const moduleName = path.basename(entry.name, extension); - if (!isPublicModuleName(spec, moduleName)) continue; - - publicModules.add(moduleName); - } - - return [...publicModules].sort(); -} - -export function buildRootRescriptJson(specs) { - return { - name: "@rescript/webapi", - sources: [ - ...specs.map((spec) => ({ - dir: `src/${spec.dirName}`, - subdirs: true, - feature: spec.featureName, - public: (spec.publicModules ?? []).filter((moduleName) => isPublicModuleName(spec, moduleName)), - })), - { - dir: "tests", - subdirs: true, - type: "dev", - }, - ], - "package-specs": { - module: "esmodule", - "in-source": true, - }, - suffix: ".js", - dependencies: [], - }; -} - -export function buildRootPackageJson(currentPackage) { - const nextPackage = structuredClone(currentPackage); - nextPackage.name = "@rescript/webapi"; - - delete nextPackage.private; - delete nextPackage.workspaces; - delete nextPackage.scripts["build:packages"]; - delete nextPackage.scripts["create:npm-packages"]; - - nextPackage.files = ["rescript.json", "src/**/*.res", "src/**/*.resi", "README.md"]; - - return nextPackage; -} - -export function writeRootConfig(rootDir) { - const packagePath = path.join(rootDir, "package.json"); - const rescriptPath = path.join(rootDir, "rescript.json"); - const currentPackage = JSON.parse(fs.readFileSync(packagePath, "utf8")); - const specsWithPublicModules = featureSpecs.map((spec) => ({ - ...spec, - publicModules: publicModulesForSourceDir(path.join(rootDir, spec.sourceDir), spec), - })); - - fs.writeFileSync(rescriptPath, `${JSON.stringify(buildRootRescriptJson(specsWithPublicModules), null, 2)}\n`); - fs.writeFileSync(packagePath, `${JSON.stringify(buildRootPackageJson(currentPackage), null, 2)}\n`); - fs.rmSync(path.join(rootDir, "scripts", "create-npm-packages.js"), { force: true }); -} - -if (process.argv.includes("--write")) { - writeRootConfig(process.cwd()); -} diff --git a/tests/unmonorepo/feature-spec.test.mjs b/tests/unmonorepo/feature-spec.test.mjs deleted file mode 100644 index 19dd33b1..00000000 --- a/tests/unmonorepo/feature-spec.test.mjs +++ /dev/null @@ -1,119 +0,0 @@ -import test from "node:test"; -import assert from "node:assert/strict"; -import { - featureSpecs, - migratedLeafName, - publicModuleToInternalPrefix, - publicNameForLeafModule, -} from "../../scripts/unmonorepo/feature-spec.mjs"; - -test("defines all legacy feature mappings used by the unmonorepo migration", () => { - assert.deepEqual( - featureSpecs - .filter(({ dirName }) => dirName === "Base" || dirName === "DOM") - .map(({ dirName, legacyNamespace, publicModule, featureName, internalPrefix }) => ({ - dirName, - legacyNamespace, - publicModule, - featureName, - internalPrefix, - })), - [ - { - dirName: "Base", - legacyNamespace: "WebApiBase", - publicModule: "Base", - featureName: "WebAPI.Base", - internalPrefix: "Base", - }, - { - dirName: "DOM", - legacyNamespace: "WebApiDOM", - publicModule: "DOM", - featureName: "WebAPI.DOM", - internalPrefix: "Dom", - }, - ], - ); - - assert.equal(featureSpecs.length, 44); -}); - -test("normalizes internal prefixes and public duplicate names", () => { - assert.equal(publicModuleToInternalPrefix("DOM"), "Dom"); - assert.equal(publicModuleToInternalPrefix("URL"), "Url"); - assert.equal(publicNameForLeafModule("DomTypes", "Dom"), "Types"); - assert.equal(publicNameForLeafModule("Document", "Dom"), "Document"); - assert.equal(publicNameForLeafModule("DOM", "Base"), "DOM"); - assert.equal(publicNameForLeafModule("PushEvent", "Push"), "PushEvent"); - assert.equal(publicNameForLeafModule("Storage", "WebStorage"), "Storage"); -}); - -test("preserves direct public leaf modules while renaming duplicated internals", () => { - const duplicateLeaves = new Set(["Types", "Global", "File", "Event"]); - - assert.equal( - migratedLeafName({ - spec: { dirName: "Base", publicModule: "Base", internalPrefix: "Base" }, - leafName: "DOM", - duplicateLeaves, - }), - "DOM", - ); - assert.equal( - migratedLeafName({ - spec: { dirName: "File", publicModule: "File", internalPrefix: "File" }, - leafName: "File", - duplicateLeaves, - }), - "File", - ); - assert.equal( - migratedLeafName({ - spec: { dirName: "File", publicModule: "File", internalPrefix: "File" }, - leafName: "Types", - duplicateLeaves, - }), - "FileTypes", - ); - assert.equal( - migratedLeafName({ - spec: { dirName: "Fetch", publicModule: "Fetch", internalPrefix: "Fetch" }, - leafName: "Global", - duplicateLeaves, - }), - "Fetch", - ); - assert.equal( - migratedLeafName({ - spec: { dirName: "Canvas", publicModule: "Canvas", internalPrefix: "Canvas" }, - leafName: "Global", - duplicateLeaves, - }), - "Canvas", - ); - assert.equal( - migratedLeafName({ - spec: { dirName: "WebWorkers", publicModule: "WebWorkers", internalPrefix: "WebWorkers" }, - leafName: "WorkerGlobalScope", - duplicateLeaves, - }), - "Worker", - ); - assert.equal( - migratedLeafName({ - spec: { dirName: "WebWorkers", publicModule: "WebWorkers", internalPrefix: "WebWorkers" }, - leafName: "SharedWorkerGlobalScope", - duplicateLeaves, - }), - "SharedWorkerScope", - ); - assert.equal( - migratedLeafName({ - spec: { dirName: "ServiceWorker", publicModule: "ServiceWorker", internalPrefix: "ServiceWorker" }, - leafName: "ServiceWorkerGlobalScope", - duplicateLeaves, - }), - "ServiceWorkerScope", - ); -}); diff --git a/tests/unmonorepo/migrate-layout.test.mjs b/tests/unmonorepo/migrate-layout.test.mjs deleted file mode 100644 index 14ceca0a..00000000 --- a/tests/unmonorepo/migrate-layout.test.mjs +++ /dev/null @@ -1,105 +0,0 @@ -import test from "node:test"; -import assert from "node:assert/strict"; -import { mkdtempSync, mkdirSync, readFileSync, writeFileSync, existsSync } from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import { migrateLayout } from "../../scripts/unmonorepo/migrate-layout.mjs"; - -function writePackage(root, dir, namespace, files) { - const packageDir = path.join(root, "packages", dir); - mkdirSync(path.join(packageDir, "src"), { recursive: true }); - writeFileSync(path.join(packageDir, "rescript.json"), JSON.stringify({ namespace })); - writeFileSync(path.join(packageDir, "package.json"), JSON.stringify({ name: dir })); - - for (const [name, contents] of Object.entries(files)) { - writeFileSync(path.join(packageDir, "src", name), contents); - } -} - -test("moves legacy sources into src/, renames duplicate leaves, and removes workspace metadata", () => { - const root = mkdtempSync(path.join(tmpdir(), "webapi-layout-")); - - writePackage(root, "DOM", "WebApiDOM", { - "Document.res": "let current = WebApiDOM.Global.document", - "Types.res": "type element", - "Global.res": "let document = 1", - }); - - writePackage(root, "Base", "WebApiBase", { - "DOM.res": "type dom = unit", - }); - - writePackage(root, "Fetch", "WebApiFetch", { - "Global.res": "let fetch = 1", - "Types.res": "type request", - "Headers.res": "type t", - }); - - writePackage(root, "Canvas", "WebApiCanvas", { - "Global.res": "let createImageBitmap = 1", - }); - - writePackage(root, "WebWorkers", "WebApiWebWorkers", { - "WorkerGlobalScope.res": "type worker", - "SharedWorkerGlobalScope.res": "type sharedWorker", - }); - - writePackage(root, "ServiceWorker", "WebApiServiceWorker", { - "ServiceWorkerGlobalScope.res": "type serviceWorker", - }); - - writePackage(root, "URL", "WebApiURL", { - "URL.res": "external make: unit => unit = \"URL\"", - "URLSearchParams.res": "type t", - }); - - mkdirSync(path.join(root, "packages", "Prelude", "lib"), { recursive: true }); - - migrateLayout(root); - - assert.equal( - readFileSync(path.join(root, "src", "DOM", "Document.res"), "utf8"), - "let current = WebApiDOM.Global.document", - ); - assert.equal(readFileSync(path.join(root, "src", "DOM", "DomTypes.res"), "utf8"), "type element"); - assert.equal( - readFileSync(path.join(root, "src", "DOM", "DomGlobal.res"), "utf8"), - "let document = 1", - ); - assert.equal( - readFileSync(path.join(root, "src", "Fetch", "Fetch.res"), "utf8"), - "let fetch = 1", - ); - assert.equal( - readFileSync(path.join(root, "src", "Canvas", "Canvas.res"), "utf8"), - "let createImageBitmap = 1", - ); - assert.equal( - readFileSync(path.join(root, "src", "WebWorkers", "Worker.res"), "utf8"), - "type worker", - ); - assert.equal( - readFileSync(path.join(root, "src", "WebWorkers", "SharedWorkerScope.res"), "utf8"), - "type sharedWorker", - ); - assert.equal( - readFileSync(path.join(root, "src", "ServiceWorker", "ServiceWorkerScope.res"), "utf8"), - "type serviceWorker", - ); - assert.equal( - readFileSync(path.join(root, "src", "Fetch", "FetchTypes.res"), "utf8"), - "type request", - ); - assert.equal( - readFileSync(path.join(root, "src", "URL", "URL.res"), "utf8"), - "external make: unit => unit = \"URL\"", - ); - assert.equal(readFileSync(path.join(root, "src", "URL", "URLSearchParams.res"), "utf8"), "type t"); - assert.ok(!existsSync(path.join(root, "src", "DOM", "DOM.res"))); - assert.ok(!existsSync(path.join(root, "src", "Base", "Base.res"))); - assert.equal(readFileSync(path.join(root, "src", "Base", "DOM.res"), "utf8"), "type dom = unit"); - assert.ok(!existsSync(path.join(root, "packages", "DOM", "rescript.json"))); - assert.ok(!existsSync(path.join(root, "packages", "DOM", "package.json"))); - assert.ok(!existsSync(path.join(root, "packages", "DOM"))); - assert.ok(!existsSync(path.join(root, "packages", "Prelude"))); -}); diff --git a/tests/unmonorepo/release-files.test.mjs b/tests/unmonorepo/release-files.test.mjs deleted file mode 100644 index 8ae4e839..00000000 --- a/tests/unmonorepo/release-files.test.mjs +++ /dev/null @@ -1,76 +0,0 @@ -import test from "node:test"; -import assert from "node:assert/strict"; -import fs from "node:fs"; - -test("docs and CI point at the unified package layout", () => { - const readme = fs.readFileSync("README.md", "utf8"); - const docsIndex = fs.readFileSync("docs/content/docs/index.mdx", "utf8"); - const docsPhilosophy = fs.readFileSync("docs/content/docs/philosophy.mdx", "utf8"); - const docsContributing = fs.readFileSync("docs/content/docs/contributing/api-modelling.mdx", "utf8"); - const docsLlm = fs.readFileSync("docs/llm.js", "utf8"); - const docsUtils = fs.readFileSync("docs/utils.js", "utf8"); - const designSpec = fs.readFileSync( - "docs/superpowers/specs/2026-04-22-unmonorepo-webapi-design.md", - "utf8", - ); - const workflow = fs.readFileSync(".github/workflows/ci.yml", "utf8"); - - assert.match(readme, /npm i @rescript\/webapi@experimental/); - assert.match(readme, /WebAPI\.Window\.current/); - assert.doesNotMatch(readme, /WebAPI\.Global/); - assert.match(docsIndex, /ReScript WebAPI/); - assert.match(docsIndex, /WebAPI\.Window\.current/); - assert.doesNotMatch(docsIndex, /WebAPI\.Global/); - assert.match(docsIndex, /location->WebAPI\.Location\.reload/); - assert.match(docsPhilosophy, /open WebAPI\.DOM/); - assert.doesNotMatch(docsPhilosophy, /WebAPI\.DomGlobal/); - assert.match(docsPhilosophy, /let myElement: WebAPI\.Element\.t = document->WebAPI\.Document\.createElement/); - assert.match(docsPhilosophy, /let node: WebAPI\.Node\.t = element->WebAPI\.Element\.asNode/); - assert.match(docsContributing, /open WebAPI/); - assert.doesNotMatch(docsContributing, /open WebAPI\.DOM/); - assert.match(designSpec, /original flat public API module shape/); - assert.match(designSpec, /Use `WebAPI\.\*` spelling, not `WebApi\.\*`\./); - assert.match(docsLlm, /rescript\.json/); - assert.match(docsLlm, /source\.public/); - assert.match(docsLlm, /isPublicFile\(filePath\)/); - assert.match(docsUtils, /path\.resolve\(process\.cwd\(\), "src"\)/); - assert.match(docsUtils, /rescript\.json/); - assert.match(docsUtils, /source\.public/); - assert.match(docsUtils, /publicModules\.has/); - assert.doesNotMatch(docsUtils, /path\.resolve\(process\.cwd\(\), "packages"\)/); - assert.match(workflow, /npm pack\b/); - assert.match(workflow, /npm publish --access public --tag experimental/); - assert.doesNotMatch(workflow, /--workspaces|publish --workspace|packages\/\*/); -}); - -test("root rescript.json keeps generated type modules internal", () => { - const config = JSON.parse(fs.readFileSync("rescript.json", "utf8")); - const sourceEntries = config.sources.filter((source) => source.dir?.startsWith("src/")); - - assert.ok(sourceEntries.length > 0); - - for (const source of sourceEntries) { - assert.ok(Array.isArray(source.public), `${source.dir} should explicitly list public modules`); - assert.deepEqual( - source.public.filter((moduleName) => moduleName.endsWith("Types")), - [], - `${source.dir} should not expose *Types modules`, - ); - assert.deepEqual( - source.public.filter((moduleName) => moduleName.includes("Global")), - [], - `${source.dir} should not expose Global or GlobalScope modules`, - ); - } - - const domSource = sourceEntries.find((source) => source.dir === "src/DOM"); - assert.ok(domSource, "src/DOM source entry should exist"); - assert.ok(!domSource.public.includes("DomGlobal"), "src/DOM should keep DomGlobal internal"); - - const visualViewportSource = sourceEntries.find((source) => source.dir === "src/VisualViewport"); - assert.ok(visualViewportSource, "src/VisualViewport source entry should exist"); - assert.ok( - visualViewportSource.public.includes("VisualViewport"), - "src/VisualViewport should expose a public VisualViewport module", - ); -}); diff --git a/tests/unmonorepo/rewrite-references.test.mjs b/tests/unmonorepo/rewrite-references.test.mjs deleted file mode 100644 index 966e2cdd..00000000 --- a/tests/unmonorepo/rewrite-references.test.mjs +++ /dev/null @@ -1,113 +0,0 @@ -import test from "node:test"; -import assert from "node:assert/strict"; -import { - rewriteSourceText, - rewriteTestText, -} from "../../scripts/unmonorepo/rewrite-references.mjs"; - -test("rewrites same-feature references to local modules and external namespaces to dotted names", () => { - const specs = [ - { publicModule: "DOM", legacyNamespace: "WebApiDOM", internalPrefix: "Dom" }, - { publicModule: "Event", legacyNamespace: "WebApiEvent", internalPrefix: "Event" }, - { publicModule: "URL", legacyNamespace: "WebApiURL", internalPrefix: "Url" }, - ]; - const leavesByFeature = new Map([ - ["DOM", ["Document", "DomGlobal", "DomTypes"]], - ["Event", ["Event", "EventTarget", "EventTypes"]], - ["URL", ["URL", "URLSearchParams", "UrlTypes"]], - ]); - - assert.equal( - rewriteSourceText( - "let target: Types.element = Global.document->WebApiEvent.EventTarget.asEventTarget", - { currentFeature: "DOM", specs, localLeaves: ["Document", "DomGlobal", "DomTypes"], leavesByFeature }, - ), - "let target: DomTypes.element = DomGlobal.document->EventTarget.asEventTarget", - ); - - assert.equal( - rewriteSourceText( - "let target: WebAPI.DOM.Types.element = WebAPI.DOM.Global.document->WebAPI.Event.EventTarget.asEventTarget", - { currentFeature: "DOM", specs, localLeaves: ["Document", "DomGlobal", "DomTypes"], leavesByFeature }, - ), - "let target: DomTypes.element = DomGlobal.document->EventTarget.asEventTarget", - ); - - assert.equal( - rewriteSourceText( - "type t = UrlTypes.urlSearchParams = private {...Types.urlSearchParams}", - { - currentFeature: "URL", - specs, - localLeaves: ["URLSearchParams", "UrlTypes"], - leavesByFeature, - }, - ), - "type t = UrlTypes.urlSearchParams = private {...UrlTypes.urlSearchParams}", - ); - - assert.equal( - rewriteTestText("let x = WebApiDOM.Global.document", specs, leavesByFeature), - "let x = DomGlobal.document", - ); -}); - -test("rewrites legacy global module references to simplified public modules", () => { - const specs = [ - { publicModule: "Fetch", legacyNamespace: "WebApiFetch", internalPrefix: "Fetch" }, - { publicModule: "Canvas", legacyNamespace: "WebApiCanvas", internalPrefix: "Canvas" }, - { publicModule: "WebWorkers", legacyNamespace: "WebApiWebWorkers", internalPrefix: "WebWorkers" }, - { - publicModule: "ServiceWorker", - legacyNamespace: "WebApiServiceWorker", - internalPrefix: "ServiceWorker", - }, - ]; - const leavesByFeature = new Map([ - ["Fetch", ["Fetch", "FetchTypes"]], - ["Canvas", ["Canvas", "CanvasTypes"]], - ["WebWorkers", ["Worker", "SharedWorkerScope", "SharedWorker", "WebWorkersTypes"]], - ["ServiceWorker", ["ServiceWorker", "ServiceWorkerScope", "ServiceWorkerTypes"]], - ]); - - assert.equal( - rewriteTestText( - "let response = WebApiFetch.Global.fetch(url)", - specs, - leavesByFeature, - ), - "let response = Fetch.fetch(url)", - ); - assert.equal( - rewriteTestText( - "let bitmap = WebAPI.Canvas.Global.createImageBitmap(image)", - specs, - leavesByFeature, - ), - "let bitmap = Canvas.createImageBitmap(image)", - ); - assert.equal( - rewriteTestText( - "let self = WebAPI.WebWorkers.WorkerGlobalScope.current", - specs, - leavesByFeature, - ), - "let self = Worker.current", - ); - assert.equal( - rewriteTestText( - "let self = WebAPI.WebWorkers.SharedWorkerGlobalScope.current", - specs, - leavesByFeature, - ), - "let self = SharedWorkerScope.current", - ); - assert.equal( - rewriteTestText( - "let self = WebAPI.ServiceWorker.ServiceWorkerGlobalScope.current", - specs, - leavesByFeature, - ), - "let self = ServiceWorkerScope.current", - ); -}); diff --git a/tests/unmonorepo/write-root-config.test.mjs b/tests/unmonorepo/write-root-config.test.mjs deleted file mode 100644 index 02c3fb02..00000000 --- a/tests/unmonorepo/write-root-config.test.mjs +++ /dev/null @@ -1,43 +0,0 @@ -import test from "node:test"; -import assert from "node:assert/strict"; -import { - buildRootPackageJson, - buildRootRescriptJson, -} from "../../scripts/unmonorepo/write-root-config.mjs"; - -test("builds the unified root rescript.json and package.json", () => { - const specs = [ - { dirName: "Base", publicModule: "Base", featureName: "WebAPI.Base", publicModules: ["DOM"] }, - { - dirName: "DOM", - publicModule: "DOM", - featureName: "WebAPI.DOM", - publicModules: ["Document", "DomGlobal", "DomTypes", "Element"], - }, - ]; - - assert.deepEqual(buildRootRescriptJson(specs).sources, [ - { dir: "src/Base", subdirs: true, feature: "WebAPI.Base", public: ["DOM"] }, - { dir: "src/DOM", subdirs: true, feature: "WebAPI.DOM", public: ["Document", "Element"] }, - { dir: "tests", subdirs: true, type: "dev" }, - ]); - - const nextPackage = buildRootPackageJson({ - name: "experimental-rescript-webapi", - version: "0.1.0", - private: true, - workspaces: ["packages/*"], - scripts: { - build: "rescript", - "build:packages": "npm run build --workspaces --if-present", - "create:npm-packages": "node scripts/create-npm-packages.js", - }, - }); - - assert.equal(nextPackage.name, "@rescript/webapi"); - assert.ok(!("private" in nextPackage)); - assert.ok(!("workspaces" in nextPackage)); - assert.ok(!("build:packages" in nextPackage.scripts)); - assert.ok(!("create:npm-packages" in nextPackage.scripts)); - assert.deepEqual(nextPackage.files, ["rescript.json", "src/**/*.res", "src/**/*.resi", "README.md"]); -});