Initial Commit

This commit is contained in:
yname 2024-08-16 15:24:15 -04:00
commit cef6bd975a
6 changed files with 142 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
node_modules

3
README.md Normal file
View file

@ -0,0 +1,3 @@
# SourcemapGenerator
This program watches multiple Rojo project directories for changes and builds a combined sourcemap.

BIN
bun.lockb Executable file

Binary file not shown.

5
package.json Normal file
View file

@ -0,0 +1,5 @@
{
"devDependencies": {
"@types/bun": "^1.1.6"
}
}

106
src/index.ts Normal file
View file

@ -0,0 +1,106 @@
import fs from 'fs'
import { spawn } from 'child_process'
// These are where I (yname) have my Rojo projects.
const SOURCE_ROOTS = ['Core', 'Secret']
type RojoSourcemap = {
name: string
className: string
filePaths?: string[]
children?: RojoSourcemap[]
}
const sourcemapCache = new Map<string, RojoSourcemap>()
function getSourcemap(root: string): Promise<RojoSourcemap> {
const cached = sourcemapCache.get(root)
if (cached) {
return Promise.resolve(cached)
}
return new Promise((resolve, reject) => {
let stdout = ''
let stderr = ''
const rojo = spawn('rojo', ['sourcemap', root])
rojo.stdout.on('data', (data) => {
stdout += data.toString()
})
rojo.stderr.on('data', (data) => {
stderr += data.toString()
})
rojo.on('close', (code) => {
if (code === 0) {
try {
const sourcemap = JSON.parse(stdout)
sourcemapCache.set(root, sourcemap)
resolve(sourcemap)
} catch {
reject(new Error(`Failed to parse sourcemap: ${stdout}`))
}
} else {
reject(stderr)
}
})
})
}
function prefixSourcemap(sourcemap: RojoSourcemap, prefix: string): RojoSourcemap {
return {
name: sourcemap.name,
className: sourcemap.className,
filePaths: sourcemap.filePaths?.map(path => `${prefix}/${path}`),
children: sourcemap.children?.map(child => prefixSourcemap(child, prefix)),
}
}
async function getPrefixedSourcemap(root: string): Promise<RojoSourcemap> {
const sourcemap = await getSourcemap(root)
const prefixed = prefixSourcemap(sourcemap, root)
return prefixed
}
function mergeSourcemaps(sourcemaps: RojoSourcemap[]): RojoSourcemap {
const merged: Required<RojoSourcemap> = {
name: '',
className: '',
filePaths: [],
children: []
};
for (const sourcemap of sourcemaps) {
merged.name = sourcemap.name;
merged.className = sourcemap.className;
if (sourcemap.filePaths) {
merged.filePaths = sourcemap.filePaths;
}
for (const child of sourcemap.children ?? []) {
const existingChild = merged.children.findIndex(oldChild => oldChild.name === child.name);
if (existingChild !== -1) {
merged.children[existingChild] = mergeSourcemaps([merged.children[existingChild], child]);
} else {
merged.children.push(child);
}
}
}
return merged;
}
async function rebuild() {
const sourcemaps = await Promise.all([
getPrefixedSourcemap('Secret'),
getPrefixedSourcemap('Core'),
])
const sourcemap = mergeSourcemaps(sourcemaps)
await fs.promises.writeFile('sourcemap.json', JSON.stringify(sourcemap, null, 2))
}
for (const root of SOURCE_ROOTS) {
fs.watch(root, {recursive:true}, () => {
sourcemapCache.delete(root)
rebuild()
})
}
rebuild()

27
tsconfig.json Normal file
View file

@ -0,0 +1,27 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Some stricter flags
"noUnusedLocals": true,
"noUnusedParameters": true,
"noPropertyAccessFromIndexSignature": true
}
}