UNPKG

@sebastianwessel/quickjs

Version:

A typescript package to execute JavaScript and TypeScript code in a WebAssembly QuickJS sandbox

113 lines (112 loc) 4.32 kB
import { join } from 'node:path'; /** * Add support for handling typescript files and code. * Requires the optional dependency 'typescript'. */ export const getTypescriptSupport = async (enabled = false, typescriptImportFile, options) => { if (!enabled) { return { transpileFile: (value, _compilerOptions, _fileName, _diagnostics, _moduleName) => value, transpileNestedDirectoryJSON: (mountFsJson, _option) => mountFsJson, transpileVirtualFs: (fs, _options) => { return fs; }, }; } let ts; try { ts = await import(typescriptImportFile ?? 'typescript'); } catch (error) { throw new Error('Package "typescript" is missing'); } const compilerOptions = { module: 99, // ESNext target: 99, // ES2023 //lib: ['ESNext'], allowJs: true, // moduleResolution: 100, skipLibCheck: true, esModuleInterop: true, strict: false, allowSyntheticDefaultImports: true, ...options, }; /** * Transpile a single File * * @param params source typescript code * @returns javascript code */ const transpileFile = (input, cpOptions = compilerOptions, fileName, diagnostics, moduleName) => ts.transpile(input, cpOptions, fileName, diagnostics, moduleName); /** * Iterates through the given JSON - NestedDirectoryJSON for defining the virtual file system. * Replace every typescript file with the transpiled javascript version and renames the file to *.js * * @param mountFsJson * @param fileExtensions * @returns */ const transpileNestedDirectoryJSON = (mountFsJson, option) => { const opt = { fileExtensions: ['ts'], ...option, }; const transformJson = (obj, transformer) => { if (typeof obj === 'object' && obj !== null) { const newObj = Array.isArray(obj) ? [] : {}; for (const key in obj) { if (obj[key]) { const [newKey, newValue] = transformer(key, obj[key]); newObj[newKey] = transformJson(newValue, transformer); } } return newObj; } return obj; }; const transpileTypescript = (key, value) => { if (!opt.fileExtensions.includes(key)) { return [key, value]; } const newFileName = key.replace('.ts', '.js'); const tsSource = typeof value === 'string' ? value : value.toString(); const jsSource = transpileFile(tsSource, compilerOptions); return [newFileName, jsSource]; }; return transformJson(mountFsJson, transpileTypescript); }; const transpileVirtualFs = (fs, options) => { const opt = { startPath: '/src', ...options, }; const transformFileSystem = (startPath) => { if (!fs.existsSync(startPath)) { throw new Error(`Directory not found: ${startPath}`); } const files = fs.readdirSync(startPath); for (const file of files) { const filePath = join(startPath, file); const stat = fs.lstatSync(filePath); if (stat.isDirectory()) { // ignore node_modules if (file !== 'node_modules') { transformFileSystem(filePath); } } else if (stat.isFile()) { const newFilePath = join(startPath, file.replace('.ts', '.js')); const content = fs.readFileSync(filePath, 'utf8'); const tsSource = typeof content === 'string' ? content : content.toString(); const jsSource = transpileFile(tsSource, compilerOptions, newFilePath); fs.renameSync(filePath, newFilePath); fs.writeFileSync(newFilePath, jsSource); } } }; transformFileSystem(opt.startPath); return fs; }; return { transpileFile, transpileNestedDirectoryJSON, transpileVirtualFs }; };