-
-
Notifications
You must be signed in to change notification settings - Fork 195
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
552 additions
and
407 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,76 @@ | ||
import path from 'node:path' | ||
import { glob } from 'glob' | ||
import { build } from 'tsup' | ||
import { ensureCacheDirExists } from '../ensureCacheDirExists' | ||
import { FIXES_BANNER } from './compilationFixes' | ||
import path from "node:path"; | ||
import { glob } from "glob"; | ||
import { build } from "tsup"; | ||
import { ensureCacheDirExists } from "../ensureCacheDirExists"; | ||
import { FIXES_BANNER } from "./compilationFixes"; | ||
import buildWalletSetupFunction from "../utils/buildWalletSetupFunction"; | ||
|
||
const OUT_DIR_NAME = 'wallet-setup-dist' | ||
const OUT_DIR_NAME = "wallet-setup-dist"; | ||
|
||
const createGlobPattern = (walletSetupDir: string) => path.join(walletSetupDir, '**', '*.setup.{ts,js,mjs}') | ||
const createGlobPattern = (walletSetupDir: string) => | ||
path.join(walletSetupDir, "**", "*.setup.{ts,js,mjs}"); | ||
|
||
export async function compileWalletSetupFunctions(walletSetupDir: string, debug: boolean) { | ||
const outDir = path.join(ensureCacheDirExists(), OUT_DIR_NAME) | ||
export async function compileWalletSetupFunctions( | ||
walletSetupDir: string, | ||
debug: boolean | ||
) { | ||
const outDir = path.join(ensureCacheDirExists(), OUT_DIR_NAME); | ||
|
||
const globPattern = createGlobPattern(walletSetupDir) | ||
const fileList = await glob(globPattern) | ||
const globPattern = createGlobPattern(walletSetupDir); | ||
const fileList = await glob(globPattern); | ||
|
||
if (debug) { | ||
console.log('[DEBUG] Found the following wallet setup files:') | ||
console.log(fileList, '\n') | ||
console.log("[DEBUG] Found the following wallet setup files:"); | ||
console.log(fileList, "\n"); | ||
} | ||
|
||
// TODO: This error message is copied over from another function. Refactor this. | ||
if (!fileList.length) { | ||
throw new Error( | ||
[ | ||
`No wallet setup files found at ${walletSetupDir}`, | ||
'Remember that all wallet setup files must end with `.setup.{ts,js,mjs}` extension!' | ||
].join('\n') | ||
) | ||
"Remember that all wallet setup files must end with `.setup.{ts,js,mjs}` extension!", | ||
].join("\n") | ||
); | ||
} | ||
|
||
await build({ | ||
name: 'cli-build', | ||
name: "cli-build", | ||
silent: true, | ||
entry: fileList, | ||
clean: true, | ||
outDir, | ||
format: 'esm', | ||
format: "esm", | ||
splitting: true, | ||
sourcemap: false, | ||
config: false, | ||
// TODO: Make this list configurable. | ||
external: ['@synthetixio/synpress', '@playwright/test', 'playwright-core', 'esbuild', 'tsup'], | ||
external: [ | ||
"@synthetixio/synpress", | ||
"@playwright/test", | ||
"playwright-core", | ||
"esbuild", | ||
"tsup", | ||
], | ||
banner: { | ||
js: FIXES_BANNER | ||
js: FIXES_BANNER, | ||
}, | ||
esbuildOptions(options) { | ||
// TODO: In this step, if the debug file is present, we should modify `console.log` so it prints from which file the log is coming from. | ||
// We're dropping `console.log` and `debugger` statements because they do not play nicely with the Playwright Test Runner. | ||
options.drop = debug ? [] : ['console', 'debugger'] | ||
} | ||
}) | ||
options.drop = debug ? [] : ["console", "debugger"]; | ||
}, | ||
}); | ||
|
||
const functionStrings = await Promise.all( | ||
fileList.map(async (fileName) => { | ||
const walletSetupFunction = await import(fileName); | ||
|
||
return buildWalletSetupFunction(walletSetupFunction.toString()); | ||
}) | ||
); | ||
|
||
console.log({functionStrings}) | ||
Check notice Code scanning / CodeQL Semicolon insertion Note
Avoid automated semicolon insertion (90% of all statements in
the enclosing function Error loading related location Loading |
||
|
||
return outDir | ||
return { outDir, functionStrings: functionStrings }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,30 @@ | ||
import { getUniqueWalletSetupFunctions } from './utils/getUniqueWalletSetupFunctions' | ||
import { triggerCacheCreation } from './utils/triggerCacheCreation' | ||
import { getUniqueWalletSetupFunctions } from "./utils/getUniqueWalletSetupFunctions"; | ||
import { triggerCacheCreation } from "./utils/triggerCacheCreation"; | ||
|
||
export async function createCache(walletSetupDirPath: string, downloadExtension: () => Promise<string>, force = false) { | ||
const setupFunctions = await getUniqueWalletSetupFunctions(walletSetupDirPath) | ||
export async function createCache( | ||
walletSetupDirPath: string, | ||
functionStrings: string[], | ||
downloadExtension: () => Promise<string>, | ||
force = false | ||
) { | ||
const setupFunctions = await getUniqueWalletSetupFunctions( | ||
walletSetupDirPath | ||
); | ||
|
||
const cacheCreationPromises = await triggerCacheCreation(setupFunctions, downloadExtension, force) | ||
const cacheCreationPromises = await triggerCacheCreation( | ||
setupFunctions, | ||
functionStrings, | ||
downloadExtension, | ||
force | ||
); | ||
|
||
if (cacheCreationPromises.length === 0) { | ||
console.log('No new setup functions to cache. Exiting...') | ||
return | ||
console.log("No new setup functions to cache. Exiting..."); | ||
return; | ||
} | ||
|
||
// TODO: This line has no unit test. Not sure how to do it. Look into it later. | ||
await Promise.all(cacheCreationPromises) | ||
await Promise.all(cacheCreationPromises); | ||
|
||
console.log('All wallet setup functions are now cached!') | ||
console.log("All wallet setup functions are now cached!"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { transformSync } from "esbuild"; | ||
import { FIXES_BANNER } from "../cli/compilationFixes"; | ||
|
||
export default function buildWalletSetupFunction( | ||
walletSetupFunctionString: string | ||
) { | ||
const { code } = transformSync(walletSetupFunctionString, { | ||
format: "esm", | ||
minifyWhitespace: true, | ||
target: "es2022", | ||
drop: ["console", "debugger"], | ||
loader: "ts", | ||
logLevel: "silent", | ||
platform: "node", | ||
banner: FIXES_BANNER, | ||
}); | ||
|
||
return code; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,13 @@ | ||
import { createHash } from 'node:crypto' | ||
import esbuild from 'esbuild' | ||
import { createHash } from "node:crypto"; | ||
|
||
// Same length as the file part (first part before the `-`) of a Playwright Test ID. | ||
export const WALLET_SETUP_FUNC_HASH_LENGTH = 10 | ||
export const WALLET_SETUP_FUNC_HASH_LENGTH = 10; | ||
|
||
// biome-ignore lint/suspicious/noExplicitAny: any type here is intentional | ||
type AnyFunction = (...args: any) => Promise<any> | ||
export function getWalletSetupFuncHash(walletSetupString: string) { | ||
const hash = createHash("shake256", { | ||
outputLength: WALLET_SETUP_FUNC_HASH_LENGTH, | ||
}); | ||
|
||
export function getWalletSetupFuncHash(walletSetupFunc: AnyFunction) { | ||
// This transformation is necessary because a user could end up using a different execution engine than Playwright. | ||
// Different execution engines -> different codes -> different hashes. | ||
const { code } = esbuild.transformSync(walletSetupFunc.toString(), { | ||
format: 'esm', | ||
minifyWhitespace: true, | ||
target: 'ES2022', | ||
drop: ['console', 'debugger'], | ||
loader: 'ts', | ||
logLevel: 'silent', | ||
platform: 'node', | ||
treeShaking: true | ||
}) | ||
|
||
const hash = createHash('shake256', { | ||
outputLength: WALLET_SETUP_FUNC_HASH_LENGTH | ||
}) | ||
|
||
return hash.update(code).digest('hex') | ||
return hash.update(walletSetupString).digest("hex"); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,63 @@ | ||
import path from 'node:path' | ||
import fs from 'fs-extra' | ||
import { ensureCacheDirExists } from '../ensureCacheDirExists' | ||
import { createCacheForWalletSetupFunction } from './createCacheForWalletSetupFunction' | ||
import { getUniqueWalletSetupFunctions } from './getUniqueWalletSetupFunctions' | ||
import { isDirEmpty } from './isDirEmpty' | ||
import path from "node:path"; | ||
import fs from "fs-extra"; | ||
import { ensureCacheDirExists } from "../ensureCacheDirExists"; | ||
import { createCacheForWalletSetupFunction } from "./createCacheForWalletSetupFunction"; | ||
import { isDirEmpty } from "./isDirEmpty"; | ||
import { getWalletSetupFuncHash } from "./getWalletSetupFuncHash"; | ||
import type { WalletSetupFunction } from "../defineWalletSetup"; | ||
|
||
export async function triggerCacheCreation( | ||
setupFunctions: Awaited<ReturnType<typeof getUniqueWalletSetupFunctions>>, | ||
setupFunctions: Map< | ||
string, | ||
{ fileName: string; setupFunction: WalletSetupFunction } | ||
>, | ||
functionStrings: string[], | ||
downloadExtension: () => Promise<string>, | ||
force: boolean | ||
) { | ||
const cacheDirPath = ensureCacheDirExists() | ||
const extensionPath = await downloadExtension() | ||
|
||
const cacheCreationPromises = [] | ||
|
||
for (const [funcHash, { fileName, setupFunction }] of setupFunctions) { | ||
const cachePath = path.join(cacheDirPath, funcHash) | ||
const doesCacheDirExist = await fs.exists(cachePath) | ||
const isCacheDirEmpty = await isDirEmpty(cachePath) | ||
|
||
if (doesCacheDirExist) { | ||
if (isCacheDirEmpty) { | ||
// In case of incorrect Playwright setup, the cache dir will be empty. For now, we're just deleting it. | ||
await fs.remove(cachePath) | ||
} else { | ||
if (!force) { | ||
console.log(`Cache already exists for ${funcHash}. Skipping...`) | ||
continue | ||
const cacheDirPath = ensureCacheDirExists(); | ||
const extensionPath = await downloadExtension(); | ||
|
||
return Array.from(setupFunctions).map( | ||
async ([_, { fileName, setupFunction }], index) => { | ||
// @ts-ignore | ||
const funcHash = getWalletSetupFuncHash(functionStrings[index]); | ||
|
||
const cachePath = path.join(cacheDirPath, funcHash); | ||
const doesCacheDirExist = await fs.exists(cachePath); | ||
const isCacheDirEmpty = await isDirEmpty(cachePath); | ||
|
||
if (doesCacheDirExist) { | ||
if (isCacheDirEmpty) { | ||
// In case of incorrect Playwright setup, the cache dir will be empty. For now, we're just deleting it. | ||
await fs.remove(cachePath); | ||
} else { | ||
if (!force) { | ||
console.log(`Cache already exists for ${funcHash}. Skipping...`); | ||
return; | ||
} | ||
|
||
console.log( | ||
`Cache already exists for ${funcHash} but force flag is set. Deleting cache...` | ||
); | ||
await fs.remove(cachePath); | ||
} | ||
|
||
console.log(`Cache already exists for ${funcHash} but force flag is set. Deleting cache...`) | ||
await fs.remove(cachePath) | ||
} | ||
} | ||
|
||
const fileNameWithCorrectExtension = fileName.replace(/\.(ts|js|mjs)$/, '.{ts,js,mjs}') | ||
console.log(`Triggering cache creation for: ${funcHash} (${fileNameWithCorrectExtension})`) | ||
|
||
// We're not inferring the return type here to make sure we don't accidentally await the function. | ||
const createCachePromise: Promise<void> = createCacheForWalletSetupFunction( | ||
extensionPath, | ||
cachePath, | ||
setupFunction, | ||
fileNameWithCorrectExtension | ||
) | ||
cacheCreationPromises.push(createCachePromise) | ||
} | ||
|
||
return cacheCreationPromises | ||
const fileNameWithCorrectExtension = fileName.replace( | ||
/\.(ts|js|mjs)$/, | ||
".{ts,js,mjs}" | ||
); | ||
console.log( | ||
`Triggering cache creation for: ${funcHash} (${fileNameWithCorrectExtension})` | ||
); | ||
// We're not inferring the return type here to make sure we don't accidentally await the function. | ||
return createCacheForWalletSetupFunction( | ||
extensionPath, | ||
cachePath, | ||
setupFunction, | ||
fileNameWithCorrectExtension | ||
); | ||
} | ||
); | ||
} |
Oops, something went wrong.