From 6c8c329992790031734d3ea22a20496a3cc55ea6 Mon Sep 17 00:00:00 2001 From: TopchetoEU <36534413+TopchetoEU@users.noreply.github.com> Date: Sat, 28 Dec 2024 13:18:56 +0200 Subject: [PATCH] feat: improve transpiler infrastructure --- build.gradle | 2 +- package.json | 9 +++++- rollup.config.js | 10 +++++++ src/lib/transpiler/_entry.ts | 4 +++ src/lib/transpiler/babel.ts | 25 +++++++++++++++++ src/lib/transpiler/coffeescript.ts | 28 +++++++++++++++++++ src/lib/{ts => transpiler}/map.ts | 16 +++++++---- src/lib/transpiler/types.ts | 10 +++++++ .../_entry.ts => transpiler/typescript.ts} | 7 +++-- 9 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 src/lib/transpiler/_entry.ts create mode 100644 src/lib/transpiler/babel.ts create mode 100644 src/lib/transpiler/coffeescript.ts rename src/lib/{ts => transpiler}/map.ts (91%) create mode 100644 src/lib/transpiler/types.ts rename src/lib/{ts/_entry.ts => transpiler/typescript.ts} (96%) diff --git a/build.gradle b/build.gradle index 0a8b73c..5b3c0d4 100644 --- a/build.gradle +++ b/build.gradle @@ -31,7 +31,7 @@ task compileEnv(type: NpmTask) { } task compileTypescript(type: NpmTask) { inputs.files('rollup.config.js'); - inputs.dir('src/lib/ts'); + inputs.dir('src/lib/transpiler'); outputs.files("build/js/ts.js"); // nom nom tasty ram environment.put("NODE_OPTIONS", "--max-old-space-size=4096"); diff --git a/package.json b/package.json index e8c346d..1d1eca7 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,17 @@ { "scripts": { "build-env": "rollup -c --environment INPUT:src/lib/libs/_entry.ts,OUTPUT:build/js/index.js,POLYFILLS:src/lib/libs/polyfills", - "build-ts": "rollup -c --environment INPUT:src/lib/ts/_entry.ts,OUTPUT:build/js/ts.js" + "build-ts": "rollup -c --environment INPUT:src/lib/transpiler/_entry.ts,OUTPUT:build/js/ts.js" }, "dependencies": { + "@babel/core": "^7.26.0", "@babel/runtime": "^7.26.0", + "@babel/standalone": "^7.26.4", + "@rollup/plugin-json": "^6.1.0", + "@types/babel__preset-env": "^7.9.7", + "@types/babel__standalone": "^7.1.9", + "@types/coffeescript": "^2.5.7", + "coffeescript": "^2.7.0", "typescript": "^5.7.2" }, "devDependencies": { diff --git a/rollup.config.js b/rollup.config.js index 9a295fa..5ca2f0a 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -4,6 +4,7 @@ const typescript = require("@rollup/plugin-typescript"); const babel = require("@rollup/plugin-babel"); const commonjs = require("@rollup/plugin-commonjs"); const nodeResolve = require("@rollup/plugin-node-resolve"); +const json = require("@rollup/plugin-json"); const { resolve } = require("path"); const shouldMinify = () => false; @@ -21,6 +22,7 @@ const construct = (input, output) => defineConfig({ }, commonjs(), nodeResolve(), + json(), babel({ extensions: [], exclude: ["node_modules/**"], @@ -107,6 +109,14 @@ const construct = (input, output) => defineConfig({ path: "null", os: "null", inspector: "null", + tty: "null", + util: "null", + assert: "null", + url: "null", + "@babel/preset-typescript/package.json": "null", + module: "null", + process: "null", + v8: "null", }, // plugins: [babel.getBabelOutputPlugin({ // allowAllFormats: true, diff --git a/src/lib/transpiler/_entry.ts b/src/lib/transpiler/_entry.ts new file mode 100644 index 0000000..f5aac7e --- /dev/null +++ b/src/lib/transpiler/_entry.ts @@ -0,0 +1,4 @@ +import coffeescript from "./coffeescript.ts"; +import babel from "./babel.ts"; + +register(v => coffeescript(babel(v))); diff --git a/src/lib/transpiler/babel.ts b/src/lib/transpiler/babel.ts new file mode 100644 index 0000000..119d4bb --- /dev/null +++ b/src/lib/transpiler/babel.ts @@ -0,0 +1,25 @@ +import { SourceMap } from "./map.ts"; +import { transform } from "@babel/standalone"; +// import presetEnv from "@babel/preset-env"; + +export default function babel(next: Compiler): Compiler { + print("Loaded babel!"); + + return (filename, code, prevMap) => { + const res = transform(code, { + filename, + sourceMaps: true, + }); + + const map = SourceMap.parse({ + file: "babel-internal://" + filename, + mappings: res.map!.mappings, + sources: [filename], + }); + + const compiled = next("babel-internal://" + filename, res.code!, SourceMap.chain(map, prevMap)); + registerSource(filename, code); + return compiled; + }; +} + diff --git a/src/lib/transpiler/coffeescript.ts b/src/lib/transpiler/coffeescript.ts new file mode 100644 index 0000000..255c856 --- /dev/null +++ b/src/lib/transpiler/coffeescript.ts @@ -0,0 +1,28 @@ +import { compile } from "coffeescript"; +import { SourceMap } from "./map.ts"; + +export default function coffee(next: Compiler): Compiler { + print("Loaded coffeescript!"); + + return (filename, code, prevMap) => { + const { + js: result, + v3SourceMap: rawMap, + } = compile(code, { + filename, + sourceMap: true, + bare: true, + }); + + const map = SourceMap.parse({ + file: "coffee-internal://" + filename, + mappings: JSON.parse(rawMap).mappings, + sources: [filename], + }); + + const compiled = next("coffee-internal://" + filename, result, SourceMap.chain(map, prevMap)); + registerSource(filename, code); + return compiled; + }; +} + diff --git a/src/lib/ts/map.ts b/src/lib/transpiler/map.ts similarity index 91% rename from src/lib/ts/map.ts rename to src/lib/transpiler/map.ts index 4e22f33..e30d39b 100644 --- a/src/lib/ts/map.ts +++ b/src/lib/transpiler/map.ts @@ -123,13 +123,16 @@ export class VLQSourceMap { public static parseVLQ(compiled: string, filenames: string[], raw: string): VLQSourceMap { const mapping = decodeVLQ(raw); - const res = new Map(); + const file: [start: number, dst: Location][][] = []; + const res = new Map([[compiled, file]]); let originalRow = 0; let originalCol = 0; let originalFile = 0; + const lastCols = new Set(); for (let compiledRow = 0; compiledRow < mapping.length; compiledRow++) { + const line = file[compiledRow] ??= []; let compiledCol = 0; for (const rawSeg of mapping[compiledRow]) { @@ -138,12 +141,13 @@ export class VLQSourceMap { originalRow += rawSeg.length > 2 ? rawSeg[2] : 0; originalCol += rawSeg.length > 3 ? rawSeg[3] : 0; - let file = res.get(compiled); - if (file == null) res.set(compiled, file = []); - - const line = file[compiledRow] ??= []; - line[line.length] = [compiledCol, [filenames[originalFile], originalRow, originalCol]]; + if (!lastCols.has(compiledCol)) { + line[line.length] = [compiledCol, [filenames[originalFile], originalRow, originalCol]]; + } + lastCols.add(compiledCol); } + + line.sort((a, b) => a[0] - b[0]); } return new VLQSourceMap(res); diff --git a/src/lib/transpiler/types.ts b/src/lib/transpiler/types.ts new file mode 100644 index 0000000..aadb44d --- /dev/null +++ b/src/lib/transpiler/types.ts @@ -0,0 +1,10 @@ +import { type SourceMap } from "./map.ts"; + +declare global { + type CompilerFactory = (next: Compiler) => Compiler; + type Compiler = (filename: string, src: string, mapper: SourceMap) => Function; + + function print(...args: any[]): void; + function register(factory: CompilerFactory): void; + function registerSource(filename: string, src: string): void; +} diff --git a/src/lib/ts/_entry.ts b/src/lib/transpiler/typescript.ts similarity index 96% rename from src/lib/ts/_entry.ts rename to src/lib/transpiler/typescript.ts index f04710e..d5d6b37 100644 --- a/src/lib/ts/_entry.ts +++ b/src/lib/transpiler/typescript.ts @@ -17,7 +17,7 @@ function resource(name: string) { else return resources[name] = getResource(name); } -register(next => { +export default function typescript(next: Compiler): Compiler { const files: Record = {}; const versions: Record = {}; let declI = 0; @@ -34,6 +34,7 @@ register(next => { forceConsistentCasingInFileNames: true, declaration: true, sourceMap: true, + downlevelIteration: true, }; let service: LanguageService; @@ -114,7 +115,7 @@ register(next => { const result = outputs["/src.js"]; const declaration = outputs["/src.d.ts"]; - const compiled = next("ts-internal://" + filename, result, SourceMap.chain(prevMap, map)); + const compiled = next("ts-internal://" + filename, result, SourceMap.chain(map, prevMap)); registerSource(filename, code); return function (this: any) { @@ -123,4 +124,4 @@ register(next => { return res; }; }; -}); +}