Skip to content

Instantly share code, notes, and snippets.

@snuffyDev
Created August 8, 2023 08:16
Show Gist options
  • Save snuffyDev/3a5bf910266cb1093f7a96bbd39cb50d to your computer and use it in GitHub Desktop.
Save snuffyDev/3a5bf910266cb1093f7a96bbd39cb50d to your computer and use it in GitHub Desktop.
SLS modules
import { readFileSync, readdirSync, rmSync } from "fs";
import { readFile } from "fs/promises";
import { createRequire } from "module";
import path from "path";
import { nodeModulesPolyfillPlugin } from "esbuild-plugins-node-modules-polyfill";
import resolve from "esbuild-plugin-resolve";
import { defineConfig } from "tsup";
import { transform } from "esbuild";
const require = createRequire(import.meta.url);
const moduleShimmerName = "ModuleShimmer";
const __dirname = path.resolve(".");
const env = process.env.NODE_ENV || "development";
const SVELTELAB_DIR = path.resolve("./../../Documents/GitHub/SvelteLab/src/lib/lsp/svelte");
const DIST_DIR = path.resolve("./dist");
const OUT_DIR = env === 'production' ? DIST_DIR : env === 'testing' ? DIST_DIR : SVELTELAB_DIR;
const moduleShimmer = {
name: moduleShimmerName,
setup(build) {
function escapeRegex(string) {
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
}
build.onLoad({ filter: /chokidar\/lib\/constants\.js/ }, (args) => {
const contents = readFileSync(args.path, { encoding: "utf-8" }).replace(
"os.type()",
"null",
);
return {
contents,
loader: "ts",
resolveDir: path.resolve("/node_modules/chokidar/lib/constants.js"),
};
});
const moduleShims = Object.fromEntries(
readdirSync(path.resolve(__dirname, "module_shims")).map((filename) => [
filename.includes('@babel') ? '@babel/core' : filename.replace(".ts", ""),
readFileSync(
path.resolve(__dirname, "module_shims", filename.includes('@babel') ? filename + '/core.ts' : filename),
).toString(),
]),
);
build.onLoad({ filter: /prettier\/standalone/ }, async (args) => {
const contentsBuffer = await readFile(args.path);
const contents = contentsBuffer
.toString()
.replace(/require\(\"/g, 'rekuire("');
return { contents };
});
// w/o this webCustomData.js included twice - as umd and as esm
build.onResolve(
{ filter: /.*vscode-html-languageservice.*webCustomData/ },
() => {
return {
path: require.resolve(
"vscode-html-languageservice/lib/esm/languageFacts/data/webCustomData.js",
),
};
},
);
for (const mod of Object.keys(moduleShims)) {
build.onResolve(
{ filter: new RegExp("^" + escapeRegex(mod) + "$") },
() => ({
path: mod,
namespace: moduleShimmerName,
}),
);
}
build.onLoad(
{
filter: /\/svelte-preprocess\/dist\/autoPreprocess\.js/,
},
async () => {
const contents = await readFile(
path.resolve(
__dirname,
"node_modules/svelte-preprocess/dist/autoProcess.js",
),
).then((x) => x.toString());
// .replace("synchronizeHostData()", "if (false)");
return {
contents,
loader: "ts",
resolveDir: path.resolve(
__dirname,
"node_modules/svelte-preprocess/dist/",
),
};
},
);
build.onLoad({ filter: /.*/ }, (args) => {
const contents = moduleShims[args.path];
return { contents, loader: "ts", resolveDir: "node_modules" };
});
},
};
function createAliasPlugin(aliasConfig) {
return {
name: "alias-plugin",
setup(build) {
// Convert the input array into an array of regex and replacement pairs
const aliasPairs = aliasConfig.map(({ find, replacement }) => ({
find: new RegExp(find),
replacement,
}));
// Handle the transform step
build.onLoad({ filter: /.*/ }, async (args) => {
// Read the original file content
const source = await readFile(args.path, "utf8");
// Apply each alias in order
let transformedSource = source;
for (const { find, replacement } of aliasPairs) {
transformedSource = transformedSource.replace(find, replacement);
}
// Return the transformed file content
return {
contents: await transform(transformedSource, {
platform: "browser",
format: "esm",
keepNames: true,
treeShaking: true,
minify:true,
loader: "ts",
}).then((value) => value.code),
};
});
},
};
}
const aliases = [
{
find: /vscode.html.languageservice.lib.umd.*webCustomData/,
replacement:
"vscode-html-languageservice/lib/esm/languageFacts/data/webCustomData.js",
},
{
find: /events/,
replacement: "events/",
},
{
find: /^fs$/,
replacement: path.resolve("./module_shims/fs.ts"),
},
{
find: /graceful-fs/,
replacement: path.resolve("./module_shims/fs.ts"),
},
{
find: /^path$/,
replacement: path.resolve("./deps/path-deno.ts"),
},
{
find: /^@babel\/core$/,
replacement: path.resolve("./module_shims/@babel/core.ts"),
},
{
find: /^perf_hooks$/,
replacement: path.resolve("./module_shims/perf_hooks.ts"),
},
{
find: /^util$/,
replacement: path.resolve("./module_shims/util.ts"),
},
{
find: /^os$/,
replacement: path.resolve("./module_shims/os.ts"),
},
{
find: /^process$/,
replacement: path.resolve("./module_shims/process.ts"),
},
{
find: /^stylus$/,
replacement: path.resolve("./module_shims/stylus.ts"),
},
];
try {
// rmSync("./dist", { recursive: true });
rmSync(OUT_DIR, {
recursive: true,
});
} catch (_a) {}
export default defineConfig({
esbuildPlugins: [
nodeModulesPolyfillPlugin({
modules: { buffer: true,stream:true,tty:true,util:true, process: true, 'node:process': true, net: true },
globals: { process: true, Buffer: true },
}),
moduleShimmer,
createAliasPlugin(aliases),
{
name: "umd2esm",
setup(build) {
build.onResolve(
{ filter: /(vscode-.*|estree-walker|jsonc-parser)/ },
(args) => {
const pathUmdMay = require.resolve(args.path, {
paths: [args.resolveDir],
});
const pathEsm = pathUmdMay.replace("/umd/", "/esm/");
return { path: pathEsm };
},
);
},
},
resolve({
fs: path.resolve("./module_shims/"),
"graceful-fs": path.resolve("./module_shims"),
}),
],
esbuildOptions(options, context) {
options.define={
global: "globalThis",
__dirname: '""',
_self: "globalThis",
require: "require",
setImmediate: "queueMicrotask",
define: "null",
importScripts: "_importScripts",
importSvelte: "_importSvelte",
importSveltePreprocess: "_importSveltePreprocess",
importPrettier: "_importPrettier",
sorcery_1: "_sorceryShim",
__importStar: "__importStar",
__importDefault: "__importDefault",
}
},banner: {
js: `const __filename = new URL(import.meta.url).pathname;`
},
sourcemap: true,
platform: "browser",
external: ["@codemirror/state", "net"],
// outdir: DIST_DIR,
outDir: OUT_DIR,
noExternal:[/.*/],
format: "esm",
bundle: true,
tsconfig: "./tsconfig.build.json",
minifySyntax: true,
minifyIdentifiers: true,
metafile: true,
splitting: true,
minifyWhitespace: true,
minify: true,
treeshake: true,
entryPoints: [
// ...glob.sync("./module_shims/*.ts", { absolute: true }),
"./src/index.ts",
"./src/worker.ts",
],
});
import { Dirent, Stats, type WatchOptions } from "fs";
//@ts-ignore
import { resolve } from "../src/deps/path-deno";
import { VFS } from "../src/vfs";
import { basename, dirname, join, parse, posix } from "path";
interface ReadOptions {
encoding?: Encoding;
flag?: string;
}
interface WriteOptions {
encoding?: Encoding;
mode?: number;
flag?: string;
}
interface StatsOptions {
bigint?: boolean;
}
function readFile(
path: string | Buffer | URL,
options: ReadOptions | Encoding = "utf8",
): Promise<string | Buffer> {
return new Promise((resolve, reject) => {
const normalizedPath = normalizePath(path.toString());
const encoding =
typeof options === "string" ? options : options?.encoding || "utf8";
try {
const data = VFS.readFile(normalizedPath, encoding);
resolve(data as never);
} catch (error) {
reject(error);
}
});
}
function createReadStream(
path: string | Buffer | URL,
): import("fs").ReadStream {
throw new Error("createReadStream is not supported in the VFS");
}
function createWriteStream(
path: string | Buffer | URL,
): import("fs").WriteStream {
throw new Error("createWriteStream is not supported in the VFS");
}
function exists(path: string | Buffer | URL): Promise<boolean> {
return new Promise((resolve, reject) => {
const normalizedPath = normalizePath(path.toString());
try {
const fileExists = VFS.fileExists(normalizedPath);
resolve(fileExists);
} catch (error) {
reject(error);
}
});
}
function open(
path: string | Buffer | URL,
flags: string | number,
mode?: number,
): Promise<number> {
return new Promise((resolve, reject) => {
reject(new Error("open is not supported in the VFS"));
});
}
function symlink(
target: string | Buffer | URL,
path: string | Buffer | URL,
): Promise<void> {
return new Promise((resolve, reject) => {
reject(new Error("symlink is not supported in the VFS"));
});
}
function closeSync(fd: number): void {
throw new Error("closeSync is not supported in the VFS");
}
function close(fd: number, callback: () => void): Promise<void> {
return new Promise((resolve, reject) => {
resolve();
});
}
function fchmodSync(fd: number, mode: string | number): void {
throw new Error("fchmodSync is not supported in the VFS");
}
function fchownSync(fd: number, uid: number, gid: number): void {
throw new Error("fchownSync is not supported in the VFS");
}
function fsyncSync(fd: number): void {
throw new Error("fsyncSync is not supported in the VFS");
}
function ftruncateSync(fd: number, len?: number): void {
throw new Error("ftruncateSync is not supported in the VFS");
}
function futimesSync(
fd: number,
atime: number | Date,
mtime: number | Date,
): void {
throw new Error("futimesSync is not supported in the VFS");
}
function readSync(
fd: number,
buffer: Buffer,
offset: number,
length: number,
position?: number | null,
): number {
throw new Error("readSync is not supported in the VFS");
}
function writeFile(
path: string | Buffer | URL,
data: string | Buffer,
options: WriteOptions = {},
): Promise<void> {
return new Promise((resolve, reject) => {
const normalizedPath = normalizePath(path.toString());
const encoding = options.encoding || "utf8";
const writeByteOrderMark = options.flag === "w" && options.mode === 0xfeff;
try {
VFS.writeFile(
normalizedPath,
data.toString(encoding),
writeByteOrderMark,
);
resolve();
} catch (error) {
reject(error);
}
});
}
function existsSync(path: string | Buffer | URL): boolean {
const normalizedPath = normalizePath(path.toString());
return VFS.fileExists(normalizedPath);
}
function mkdirSync(path: string | Buffer | URL, mode?: number): void {
const normalizedPath = normalizePath(path.toString());
VFS.createDirectory(normalizedPath);
}
const { watchFile, watchDirectory, unwatchDirectory, unwatchFile } = VFS;
function statSync(
path: string | Buffer | URL,
options: StatsOptions = {},
): Stats {
const normalizedPath = normalizePath(path.toString());
const exists = VFS.fileExists(normalizedPath);
return {
isFile: () => exists,
isDirectory: () =>
normalizedPath ===
(parse(normalizedPath).ext === "" &&
join(
dirname(normalizedPath),
basename(normalizedPath) + parse(normalizedPath).ext,
)),
isBlockDevice: () => false,
isCharacterDevice: () => false,
isSymbolicLink: () => false,
isFIFO: () => false,
isSocket: () => false,
dev: 0,
ino: 0,
mode: 0,
nlink: 0,
uid: 0,
gid: 0,
rdev: 0,
size: 0,
blksize: 0,
blocks: 0,
atimeMs: 0,
mtimeMs: 0,
ctimeMs: 0,
birthtimeMs: 0,
atime: new Date(),
mtime: new Date(),
ctime: new Date(),
birthtime: new Date(),
...(options.bigint && {
atimeNs: BigInt(0),
mtimeNs: BigInt(0),
ctimeNs: BigInt(0),
birthtimeNs: BigInt(0),
}),
};
}
function readFileSync(
path: string | Buffer | URL,
options: Encoding = "utf8",
): string | Buffer | undefined {
const normalizedPath = normalizePath(path.toString());
const encoding = typeof options === "string" ? options : options || "utf8";
return VFS.readFile(normalizedPath, encoding) || Buffer.from([]);
}
function writeFileSync(
path: string | Buffer | URL,
data: string | Buffer,
options: WriteOptions = {},
): void {
const normalizedPath = normalizePath(path.toString());
const encoding = options.encoding || "utf8";
const writeByteOrderMark = options.flag === "w" && options.mode === 0xfeff;
VFS.writeFile(normalizedPath, data.toString(encoding), writeByteOrderMark);
}
function readdirSyncWithFileTypes(path: string | Buffer | URL): Dirent[] {
const normalizedPath = normalizePath(path.toString());
const files = VFS.readDirectory(normalizedPath);
return files.map(
(file) =>
({
name: file,
isFile: () => VFS.fileExists(file),
isDirectory: () => !VFS.fileExists(file),
} as Dirent),
);
}
type Encoding = BufferEncoding | null;
interface ReadOptions {
encoding?: Encoding;
flag?: string;
}
interface WriteOptions {
encoding?: Encoding;
mode?: number;
flag?: string;
}
interface StatsOptions {
bigint?: boolean;
}
function normalizePath(path: string): string {
return VFS.normalize(path);
}
function accessSync(path: string | Buffer | URL, mode?: number): void {
const normalizedPath = normalizePath(path.toString());
if (!VFS.fileExists(normalizedPath)) {
const err = new Error(`File does not exist: ${normalizedPath}`);
console.error(err);
throw err;
}
// Mode checking not supported in the vfs, but we can add checks for different modes if needed.
}
function chmodSync(path: string | Buffer | URL, mode: string | number): void {
const normalizedPath = normalizePath(path.toString());
// Not supported in the vfs, but can be implemented if needed.
}
function chownSync(
path: string | Buffer | URL,
uid: number,
gid: number,
): void {
const normalizedPath = normalizePath(path.toString());
// Not supported in the vfs, but can be implemented if needed.
}
function linkSync(
existingPath: string | Buffer | URL,
newPath: string | Buffer | URL,
): void {
const normalizedExistingPath = normalizePath(existingPath.toString());
const normalizedNewPath = normalizePath(newPath.toString());
// Not supported in the vfs, but can be implemented if needed.
}
function symlinkSync(
target: string | Buffer | URL,
path: string | Buffer | URL,
type?: string,
): void {
const normalizedTarget = normalizePath(target.toString());
const normalizedPath = normalizePath(path.toString());
// Not supported in the vfs, but can be implemented if needed.
}
function truncateSync(path: string | Buffer | URL, len?: number): void {
const normalizedPath = normalizePath(path.toString());
// Not supported in the vfs, but can be implemented if needed.
}
function unlinkSync(path: string | Buffer | URL): void {
const normalizedPath = normalizePath(path.toString());
// Not supported in the vfs, but can be implemented if needed.
}
function rmdirSync(path: string | Buffer | URL): void {
const normalizedPath = normalizePath(path.toString());
// Not supported in the vfs, but can be implemented if needed.
}
function lstatSync(path: string | Buffer | URL): Stats {
return statSync(path);
}
function fstatSync(fd: number): Stats {
// Not supported in the vfs, but can be implemented if needed.
throw new Error("fstatSync is not supported in the vfs");
}
function readlinkSync(path: string | Buffer | URL): string {
const normalizedPath = normalizePath(path.toString());
// Not supported in the vfs, but can be implemented if needed.
throw new Error("readlinkSync is not supported in the vfs");
}
type EventListener = (...args: any[]) => void;
function lstat(path: string | Buffer | URL): Promise<Stats> {
return new Promise((resolve, reject) => {
const normalizedPath = normalizePath(path.toString());
try {
const stats = lstatSync(normalizedPath);
resolve(stats);
} catch (error) {
reject(error);
}
});
}
function openSync(
path: string | Buffer | URL,
flags: string | number,
mode?: number,
): number {
// Not supported in the vfs, but can be implemented if needed.
throw new Error("openSync is not supported in the vfs");
}
function readdir(path: string | Buffer | URL): Promise<string[]> {
return new Promise((resolve, reject) => {
const normalizedPath = normalizePath(path.toString());
try {
const files = VFS.readDirectory(normalizedPath);
resolve(files);
} catch (error) {
reject(error);
}
});
}
function readdirSync(path: string | Buffer | URL): string[] {
const normalizedPath = normalizePath(path.toString());
return VFS.readDirectory(normalizedPath);
}
function realpathSync(path: string | Buffer | URL): string {
const _normalizedPath = normalizePath(path.toString());
return _normalizedPath;
}
function stat(
path: string | Buffer | URL,
callback: (err: Error | null, data: any) => void,
): void {
try {
const normalizedPath = normalizePath(path.toString());
const stats = statSync(normalizedPath);
callback(null, stats);
} catch (err) {
callback(err, null);
}
}
const S = Symbol.for("graceful-fs.queue");
const realpath = (path, options, callback) => {
if (!callback) options(null, resolve(path));
else if (callback) callback(null, resolve(path));
};
const rw = {
"___graceful-fs.queue": () => {},
[S]: () => {},
readFile,
readFileSync,
existsSync,
lstat,
openSync,
readdir,
readdirSync,
realpath,
realpathSync,
stat,
statSync,
accessSync,
chmodSync,
chownSync,
watchFile,
linkSync,
symlinkSync,
truncateSync,
unlinkSync,
rmdirSync,
lstatSync,
fstatSync,
readlinkSync,
watch: watchFile,
writeFile,
mkdirSync,
createReadStream,
createWriteStream,
exists,
close,
open,
symlink,
closeSync,
fchmodSync,
fchownSync,
fsyncSync,
ftruncateSync,
futimesSync,
readSync,
writeFileSync,
readdirSyncWithFileTypes,
};
// @ts-expect-error mocking node fs functionality
rw.realpath.native = (path, options, callback) => {
if (!callback) options(null, resolve(path));
else if (callback) callback(null, resolve(path));
};
// @ts-expect-error mocking node fs functionality
rw.realpathSync.native = (path, options) => {
return resolve(path);
};
const proxy = new Proxy(
{ [S]: () => {}, ...rw },
{
get(target, prop, _receiver) {
// console.warn(`FS GET`, { target, prop, _receiver });
if (!target[prop]) target[prop] = {};
return Reflect.get(target, prop);
},
preventExtensions(target) {
return false;
},
set(target, p, newValue, receiver) {
// console.warn(`FS SET`, { target, p, newValue, receiver });
return Reflect.set(target, p, newValue, receiver);
},
},
);
const {
readFile: _readFile,
readFileSync: _readFileSync,
existsSync: _existsSync,
lstat: _lstat,
openSync: _openSync,
watchFile: _watchFile,
readdir: _readdir,
realpath: _realpath,
readdirSync: _readdirSync,
realpathSync: _realpathSync,
stat: _stat,
statSync: _statSync,
close: _close,
accessSync: _accessSync,
chmodSync: _chmodSync,
chownSync: _chownSync,
linkSync: _linkSync,
symlinkSync: _symlinkSync,
truncateSync: _truncateSync,
createReadStream: _createReadStream,
createWriteStream: _createWriteStream,
exists: _exists,
open: _open,
symlink: _symlink,
closeSync: _closeSync,
fchmodSync: _fchmodSync,
fchownSync: _fchownSync,
fsyncSync: _fsyncSync,
ftruncateSync: _ftruncateSync,
futimesSync: _futimesSync,
readSync: _readSync,
unlinkSync: _unlinkSync,
rmdirSync: _rmdirSync,
lstatSync: _lstatSync,
fstatSync: _fstatSync,
readlinkSync: _readlinkSync,
watch: _watch,
writeFile: _writeFile,
mkdirSync: _mkdirSync,
writeFileSync: _writeFileSync,
readdirSyncWithFileTypes: _readdirSyncWithFileTypes,
} = proxy;
export {
_readFile as readFile,
_readFileSync as readFileSync,
_existsSync as existsSync,
_lstat as lstat,
_watchFile as watchFile,
_openSync as openSync,
_readdir as readdir,
_readdirSync as readdirSync,
_realpathSync as realpathSync,
_stat as stat,
_close as close,
_statSync as statSync,
_accessSync as accessSync,
_chmodSync as chmodSync,
_chownSync as chownSync,
_linkSync as linkSync,
_symlinkSync as symlinkSync,
_truncateSync as truncateSync,
_createReadStream as createReadStream,
_createWriteStream as createWriteStream,
_exists as exists,
_open as open,
_symlink as symlink,
_closeSync as closeSync,
_fchmodSync as fchmodSync,
_fchownSync as fchownSync,
_fsyncSync as fsyncSync,
_ftruncateSync as ftruncateSync,
_futimesSync as futimesSync,
_readSync as readSync,
_unlinkSync as unlinkSync,
_rmdirSync as rmdirSync,
_lstatSync as lstatSync,
_fstatSync as fstatSync,
_readlinkSync as readlinkSync,
_watch as watch,
_writeFile as writeFile,
_mkdirSync as mkdirSync,
_writeFileSync as writeFileSync,
_realpath as realpath,
};
export default proxy;
// In addition to being accessible through util.promisify.custom,
// this symbol is registered globally and can be accessed in any environment as
// Symbol.for('nodejs.util.promisify.custom').
const kCustomPromisifiedSymbol = Symbol.for("nodejs.util.promisify.custom");
// This is an internal Node symbol used by functions returning multiple
// arguments, e.g. ['bytesRead', 'buffer'] for fs.read().
const kCustomPromisifyArgsSymbol = Symbol.for(
"nodejs.util.promisify.customArgs",
);
export const customPromisifyArgs = kCustomPromisifyArgsSymbol;
function promisify(original) {
if (typeof original !== "function") return () => Promise.resolve(original);
if (original[kCustomPromisifiedSymbol]) {
const fn = original[kCustomPromisifiedSymbol];
return Object.defineProperty(fn, kCustomPromisifiedSymbol, {
value: fn,
enumerable: false,
writable: false,
configurable: true,
});
}
// Names to create an object from in case the callback receives multiple
// arguments, e.g. ['bytesRead', 'buffer'] for fs.read.
const argumentNames = original[kCustomPromisifyArgsSymbol];
function fn(...args) {
return new Promise((resolve, reject) => {
args.push((err, ...values) => {
if (err) {
return reject(err);
}
if (argumentNames !== undefined && values.length > 1) {
const obj = {};
for (let i = 0; i < argumentNames.length; i++) {
obj[argumentNames[i]] = values[i];
}
resolve(obj);
} else {
resolve(values[0]);
}
});
Reflect.apply(original, this, args);
});
}
Object.setPrototypeOf(fn, Object.getPrototypeOf(original));
Object.defineProperty(fn, kCustomPromisifiedSymbol, {
value: fn,
enumerable: false,
writable: false,
configurable: true,
});
return Object.defineProperties(
fn,
Object.getOwnPropertyDescriptors(original),
);
}
var _TextDecoder = TextDecoder;
export { _TextDecoder as TextDecoder, promisify };
// @ts-ignore
import typescript from "../node_modules/typescript/lib/typescript.js";
const { createLanguageService: createLanguageService2 } = typescript;
const sys = typescript.sys;
let ts = {
...typescript,
getDefaultLibFilePath() {
return "/node_modules/typescript/lib/lib.d.ts";
},
setSys(sys) {
},
sys, // ...langService,
} as Partial<typeof typescript>;
const proxy = new Proxy(ts, {
get(target, p, receiver) {
if (p === "default") return receiver;
if (!ts[p]) {
ts[p] = target[p];
}
return ts[p] ? ts[p] : target[p];
},
set(target, p, value) {
if (p === "sys") return true;
return Reflect.set(!ts[p] ? ts : target, p, value);
},
});
export default (() => proxy)();
// export all the typescript stuff from the proxy object
const {
createSourceFile,
createWatchProgram,
createEmitAndSemanticDiagnosticsBuilderProgram,
createAbstractBuilder,
// export everything else that exists on the proxy object and create a named export for them
} = proxy;
export {
createSourceFile,
createWatchProgram,
createEmitAndSemanticDiagnosticsBuilderProgram,
createSemanticDiagnosticsBuilderProgram,
createAbstractBuilder,
};
const {
sys: _sys,
// @ts-ignore
setSys: _setSys,
} = proxy;
export { _sys as sys, _setSys as setSys };
const { ScriptSnapshot, DisplayPartsSymbol } = proxy;
export { ScriptSnapshot, DisplayPartsSymbol };
const { ScriptTarget, ModuleKind, JsxEmit, ScriptKind } = proxy;
export { ScriptTarget, ModuleKind, JsxEmit, ScriptKind };
const { createPreEmitDiagnostics, flattenDiagnosticMessageText } = proxy;
export { createPreEmitDiagnostics, flattenDiagnosticMessageText };
const { createCompilerDiagnostic, createCompilerDiagnosticFromMessageChain } =
proxy;
export { createCompilerDiagnostic, createCompilerDiagnosticFromMessageChain };
const { DiagnosticCategory, ModuleResolutionKind, NewLineKind } = proxy;
export { DiagnosticCategory, ModuleResolutionKind, NewLineKind };
const { Extension, ExtensionKind, NodeFlags } = proxy;
export { Extension, ExtensionKind, NodeFlags };
const {
findConfigFile,
parseConfigFileTextToJson,
readConfigFile,
parseJsonConfigFileContent,
} = proxy;
export {
findConfigFile,
parseConfigFileTextToJson,
readConfigFile,
parseJsonConfigFileContent,
};
const {
getPreEmitDiagnostics,
getSemanticDiagnostics,
getSyntacticDiagnostics,
getDeclarationDiagnostics,
getGlobalDiagnostics,
getConfigFileParsingDiagnostics,
} = proxy;
export {
getPreEmitDiagnostics,
getSemanticDiagnostics,
getSyntacticDiagnostics,
getDeclarationDiagnostics,
getGlobalDiagnostics,
getConfigFileParsingDiagnostics,
};
const {
createCompilerHost,
createIncrementalCompilerHost,
createSourceMapWriter,
createWatchCompilerHost,
} = proxy;
export {
createCompilerHost,
createIncrementalCompilerHost,
createSourceMapWriter,
createWatchCompilerHost,
};
const { createIncrementalProgram, createProgram } = proxy;
export { createIncrementalProgram, createProgram };
const {
getSupportedExtensions,
resolveModuleName,
resolveTypeReferenceDirective,
} = proxy;
export {
getSupportedExtensions,
resolveModuleName,
resolveTypeReferenceDirective,
};
const {
createLanguageService,
createLanguageServiceSourceFile,
createLanguageServiceHost,
} = proxy;
export {
createLanguageService,
createLanguageServiceSourceFile,
createLanguageServiceHost,
};
const { createDocumentRegistry } = proxy;
export { createDocumentRegistry };
const { createSemanticDiagnosticsBuilderProgram } = proxy;
const obj = {
get sys() {
return _sys;
},
set sys(sys) {
_setSys(sys);
},
};
// import ts from "../module_shims/typescript";
const sys = new (class FSMap extends Map<string, string> {})();
import type { Encoding } from "crypto";
import EventEmitter from "events";
import {
WatchEventType,
statSync,
type WatchOptions,
type FSWatcher as _FSWatcher,
} from "fs";
import process from "process";
import { type FileWatcher, type FileWatcherCallback } from "typescript";
import _path from "./deps/path-deno";
import json from "./libs.json";
const directories = new Set<string>();
type EventListener = (
eventType: WatchEventType | "close" | "error",
filename: string | Buffer,
) => void;
class FSWatcherImpl extends EventEmitter.EventEmitter implements _FSWatcher {
private listener: EventListener;
private path: string;
private isFolder: boolean;
constructor(
path: string,
private options: WatchOptions | Encoding,
listener: EventListener,
) {
super();
this.path = VFSImpl.normalize(path);
this.listener = listener;
this.isFolder = statSync(this.path).isDirectory();
console.log({ isFolder: this.isFolder, options });
this.startWatching();
}
public close() {
this.listener = () => {}; // Clear the listener
this.removeAllListeners();
}
private startWatching() {
VFSImpl.on("change", (eventType, changedPath: string) => {
if (
(changedPath === this.path ||
(this.isFolder && changedPath.startsWith(this.path))) &&
this.listener
) {
console.log(eventType, changedPath);
const filename = changedPath;
this.listener(eventType, filename);
this.emit(eventType, filename);
VFS.emit("change", changedPath);
}
});
}
}
export const FSWatcher: new (
path: string,
options: WatchOptions | Encoding,
listener: EventListener,
) => _FSWatcher = FSWatcherImpl as any;
class VFSImpl {
public static readonly output: string[] = [];
public static emit = <T extends WatchEventType | "close" | "error">(
event: T,
name: string,
): boolean => {
const handlers = VFSImpl.handlers.get(event) ?? [];
for (const handler of handlers) {
handler(event, name);
}
return true;
};
public static handlers: Map<string, EventListener[]> = new Map();
public static eventNames = [...this.handlers.keys()];
public static getCurrentDirectory = () => {
return "/";
};
public static getExecutingFilePath = () => {
return process.execPath;
};
public static listenerCount = (event: string) => {
return VFSImpl.handlers.get(event)?.length ?? 0;
};
public static off = (event: string, callback: EventListener) => {
const handlers = VFSImpl.handlers.get(event) ?? [];
const index = handlers.indexOf(callback);
if (index > -1) {
handlers.splice(index, 1);
}
VFSImpl.handlers.set(event, handlers);
};
public static on = (event: string, callback: EventListener) => {
const handlers = VFSImpl.handlers.get(event) ?? [];
handlers.push(callback);
VFSImpl.handlers.set(event, handlers as unknown as EventListener[]);
};
public static createDirectory(path: string) {
this.emit("change", _path.posix.dirname(VFSImpl.normalize(path)));
console.log("createDirectory", path);
return directories.add(VFSImpl.normalize(path));
}
public static directoryExists(path: string) {
return directories.has(VFSImpl.normalize(path));
}
public static exit(exitCode?: number) {
return 1;
}
public static fileExists(path: string) {
return sys.has(VFSImpl.normalize(path));
}
public static getDirectories(path: string) {
console.log([...directories.keys()]);
return VFSImpl.readDirectory;
}
public static normalize(path: string) {
return _path.posix.fromFileUrl(
path.startsWith("file:///")
? path
: new URL(_path.posix.toFileUrl(_path.posix.resolve(path))),
);
}
public static readDirectory(
path: string,
extensions?: readonly string[],
exclude?: readonly string[],
include?: readonly string[],
depth?: number,
) {
console.log();
console.log({
result: [...sys.keys()]
.filter((v) => v.startsWith(VFS.normalize(path)))
.map((v) => VFS.normalize(v.slice(v.indexOf(path)))),
path,
extensions,
exclude,
include,
depth,
});
let files = [...sys.keys()];
if (include) {
files = files.filter((f) => include.some((i) => f.startsWith(i)));
}
if (exclude) {
files = files.filter((f) => !exclude.some((i) => f.startsWith(i)));
}
if (extensions) {
files = files.filter((f) => extensions.some((e) => f.endsWith(e)));
}
if (depth) {
files = files.filter(
(f) => f.split("/").length - 1 <= path.split("/").length - 1 + depth,
);
}
return [...sys.keys()]
.filter((v) => v.startsWith(VFS.normalize(path)))
.map((v) => VFS.normalize(v.slice(v.indexOf(path))));
}
public static readFile(path: string, encoding?: string) {
try {
const test =
sys.get(VFSImpl.normalize(path)) ||
sys.get(VFSImpl.normalize(path.replace("/", "/node_modules/lib/lib.")));
return encoding.startsWith("utf") ? test : Buffer.from(test);
} catch {
return undefined;
}
}
public static resolvePath(path: string) {
directories.add(_path.posix.dirname(VFSImpl.normalize(path)));
return VFSImpl.normalize(_path.posix.resolve("/", path));
}
public static write(s: string) {
return VFSImpl.output.push(s);
// return undefined;
}
public static writeFile(
path: string,
data: string,
writeByteOrderMark?: boolean,
) {
directories.add(_path.posix.dirname(VFSImpl.normalize(path)));
this.emit("change", _path.posix.dirname(VFSImpl.normalize(path)));
return sys.set(_path.posix.normalize(VFSImpl.normalize(path)), data);
}
}
/* Create an in-memory file tree (which is a class that implements the compiler host interface using a Map<string, string> to store files)
it will be used by the compiler host, and should support all the methods the compiler host expects
directory creation and reading for proper module resolution
The executing environment will be in the web browser, so we don't have access to the file system
*/
// write implmentation below
class VFSWithFileTreeAndDirectorySupport extends VFSImpl {
public static watchDirectory = (dir, options, callback) =>
VFSWithFileTreeAndDirectorySupport.watchFile(
dir,
{ __IS_FOLDER: true, ...options },
callback,
);
public static watchers: Map<string, _FSWatcher> = new Map();
public static unwatchDirectory(path: string, callback?: FileWatcherCallback) {
console.log();
const watcher = VFSWithFileTreeAndDirectorySupport.watchers.get(
VFSImpl.normalize(path),
);
if (watcher) {
watcher.close();
VFSWithFileTreeAndDirectorySupport.watchers.delete(
VFSImpl.normalize(path),
);
}
}
public static unwatchFile(path: string, callback?: FileWatcherCallback) {
const watcher = VFSWithFileTreeAndDirectorySupport.watchers.get(
VFSImpl.normalize(path),
);
if (watcher) {
watcher.close();
VFSWithFileTreeAndDirectorySupport.watchers.delete(
VFSImpl.normalize(path),
);
}
}
public static watchFile(
path: string,
options: WatchOptions | Encoding,
callback?: (
event: WatchEventType | "error" | "close",
fileName: string,
) => void,
): FileWatcher {
//@ts-ignore
const watcher = new FSWatcher(VFSImpl.normalize(path), options, callback);
VFSWithFileTreeAndDirectorySupport.watchers.set(
VFSImpl.normalize(path),
watcher,
);
return watcher;
}
}
export var VFS = VFSWithFileTreeAndDirectorySupport;
const fsMap = new Map(
Object.entries(json).map(([key, value]) => [
_path.posix.resolve(`/node_modules/typescript/lib/`, key),
value,
]),
);
VFSImpl.writeFile(
"file:///svelte.config.js",
`
import preprocess from 'svelte-preprocess';
export default {
// Consult https://svelte.dev/docs#compile-time-svelte-preprocess
// for more information about preprocessors
preprocess: preprocess(),
}
`,
);
// Create the tsConfig (should be done somewhere else!)
if (!VFSImpl.fileExists("/tsconfig.json"))
VFSImpl.writeFile(
"/tsconfig.json",
`{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020","ESNext", "DOM", "DOM.Iterable"],
/* Bundler mode */
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"strict": true,
"noUnusedLocals": true,
"skipLibCheck": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
}
}
`,
);
// SET SVELTE DEFINITIONS
const files = import.meta.glob("/node_modules/svelte/**/*.d.ts", {
eager: true,
as: "raw",
});
for (const file in files) {
VFSImpl.writeFile(file, files[file]);
}
// SET SVELTE2TSX DEFINITIONS
const filesS2TSX = import.meta.glob("/node_modules/svelte2tsx/**/*.d.ts", {
eager: true,
as: "raw",
});
for (const file in filesS2TSX) {
VFSImpl.writeFile(file, filesS2TSX[file]);
}
// SET PREPROCESS DEFINITIONS
const preprocess = import.meta.glob(
"/node_modules/svelte-preprocess/dist/**/*.d.ts",
{
eager: true,
as: "raw",
},
);
for (const file in preprocess) {
VFSImpl.writeFile(file, preprocess[file]);
}
fsMap.forEach((value, key) => {
console.log({ value, key });
VFSImpl.writeFile(`/node_modules/typescript/lib/${key}`, value);
});
console.log({ sys });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment