Initial Commit
This commit is contained in:
commit
cef6bd975a
6 changed files with 142 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
node_modules
|
3
README.md
Normal file
3
README.md
Normal 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
BIN
bun.lockb
Executable file
Binary file not shown.
5
package.json
Normal file
5
package.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.1.6"
|
||||
}
|
||||
}
|
106
src/index.ts
Normal file
106
src/index.ts
Normal 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
27
tsconfig.json
Normal 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
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue