1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2026-03-14 02:16:35 +00:00

Deploying to gh-pages from @ sehugg/8bitworkshop@3954099ea3 🚀

This commit is contained in:
sehugg
2026-03-03 18:30:42 +00:00
parent e88f416093
commit b6ddfe5518
9 changed files with 518 additions and 17 deletions

View File

@@ -46,8 +46,8 @@ function usage() {
command: 'help',
data: {
commands: {
'compile': 'compile --tool <tool> --platform <platform> [--output <file>] <source>',
'check': 'check --tool <tool> --platform <platform> <source>',
'compile': 'compile --platform <platform> [--tool <tool>] [--output <file>] <source>',
'check': 'check --platform <platform> [--tool <tool>] <source>',
'run': 'run --platform <platform> [--frames N] <rom>',
'list-tools': 'list-tools',
'list-platforms': 'list-platforms',
@@ -82,14 +82,18 @@ async function doCompile(args, positional, checkOnly) {
var platform = args['platform'];
var outputFile = args['output'];
var sourceFile = positional[0];
if (!tool || !platform || !sourceFile) {
if (!platform || !sourceFile) {
outputJSON({
success: false,
command: checkOnly ? 'check' : 'compile',
error: 'Required: --tool <tool> --platform <platform> <source>'
error: 'Required: --platform <platform> <source> [--tool <tool>]'
});
process.exit(1);
}
// Auto-detect tool from filename if not specified
if (!tool) {
tool = (0, testlib_1.getToolForFilename)(sourceFile, platform);
}
if (!testlib_1.TOOLS[tool]) {
outputJSON({
success: false,

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,7 @@
"use strict";
// testlib - Clean async API for compiling and testing 8bitworkshop projects
// Wraps the worker build system for use in tests and CLI tools
// FOR TESTING ONLY
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -40,12 +41,16 @@ exports.initialize = initialize;
exports.preload = preload;
exports.compile = compile;
exports.compileFile = compileFile;
exports.getToolForFilename = getToolForFilename;
exports.compileSourceFile = compileSourceFile;
exports.listTools = listTools;
exports.listPlatforms = listPlatforms;
exports.ab2str = ab2str;
exports.createMockLocalStorage = createMockLocalStorage;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const util_1 = require("../common/util");
const baseplatform_1 = require("../common/baseplatform");
const workerlib_1 = require("../worker/workerlib");
Object.defineProperty(exports, "store", { enumerable: true, get: function () { return workerlib_1.store; } });
Object.defineProperty(exports, "TOOL_PRELOADFS", { enumerable: true, get: function () { return workerlib_1.TOOL_PRELOADFS; } });
@@ -119,18 +124,244 @@ async function compileFile(tool, platform, presetPath) {
path: presetPath,
});
}
/**
* Parse include and link dependencies from source text.
* Extracted from CodeProject.parseIncludeDependencies / parseLinkDependencies.
* TODO: project.ts should be refactored so we don't have to duplicate the logic
*/
function parseIncludeDependencies(text, platformId, mainPath) {
let files = [];
let m;
var dir = (0, util_1.getFolderForPath)(mainPath);
function pushFile(fn) {
files.push(fn);
if (dir.length > 0 && dir != 'local')
files.push(dir + '/' + fn);
}
if (platformId.startsWith('verilog')) {
let re1 = /^\s*(`include|[.]include)\s+"(.+?)"/gmi;
while (m = re1.exec(text)) {
pushFile(m[2]);
}
let re1a = /^\s*\$(include|\$dofile|\$write_image_in_table)\('(.+?)'/gmi;
while (m = re1a.exec(text)) {
pushFile(m[2]);
}
let re2 = /^\s*([.]arch)\s+(\w+)/gmi;
while (m = re2.exec(text)) {
pushFile(m[2] + ".json");
}
let re3 = /\$readmem[bh]\("(.+?)"/gmi;
while (m = re3.exec(text)) {
pushFile(m[1]);
}
}
else {
let re2 = /^\s*[.#%]?(include|incbin|embed)\s+"(.+?)"/gmi;
while (m = re2.exec(text)) {
pushFile(m[2]);
}
let re3 = /^\s*([;']|[/][/])#(resource)\s+"(.+?)"/gm;
while (m = re3.exec(text)) {
pushFile(m[3]);
}
let re4 = /^\s+(USE|ASM)\s+(\S+[.]\S+)/gm;
while (m = re4.exec(text)) {
pushFile(m[2]);
}
let re5 = /^\s*(import|embed)\s*"(.+?)";/gmi;
while (m = re5.exec(text)) {
if (m[1] == 'import')
pushFile(m[2] + ".wiz");
else
pushFile(m[2]);
}
let re6 = /^\s*(import)\s*"(.+?)"/gmi;
while (m = re6.exec(text)) {
pushFile(m[2]);
}
let re7 = /^[!]src\s+"(.+?)"/gmi;
while (m = re7.exec(text)) {
pushFile(m[1]);
}
}
return files;
}
function parseLinkDependencies(text, platformId, mainPath) {
let files = [];
let m;
var dir = (0, util_1.getFolderForPath)(mainPath);
function pushFile(fn) {
files.push(fn);
if (dir.length > 0 && dir != 'local')
files.push(dir + '/' + fn);
}
if (!platformId.startsWith('verilog')) {
let re = /^\s*([;]|[/][/])#link\s+"(.+?)"/gm;
while (m = re.exec(text)) {
pushFile(m[2]);
}
}
return files;
}
/**
* Try to resolve a file path by searching the source directory,
* the presets directory for the platform, and the current working directory.
*/
function resolveFileData(filePath, sourceDir, platform) {
var searchPaths = [];
// Try relative to source file directory
if (sourceDir) {
searchPaths.push(path.resolve(sourceDir, filePath));
}
// Try presets directory
var basePlatform = (0, util_1.getBasePlatform)(platform);
searchPaths.push(path.resolve('presets', basePlatform, filePath));
// Try current working directory
searchPaths.push(path.resolve(filePath));
for (var p of searchPaths) {
try {
if (fs.existsSync(p)) {
if ((0, util_1.isProbablyBinary)(filePath)) {
return new Uint8Array(fs.readFileSync(p));
}
else {
return fs.readFileSync(p, 'utf-8');
}
}
}
catch (e) {
// continue searching
}
}
return null;
}
/**
* Strips the main file's folder prefix from a path (matching CodeProject.stripLocalPath).
*/
function stripLocalPath(filePath, mainPath) {
var folder = (0, util_1.getFolderForPath)(mainPath);
if (folder != '' && filePath.startsWith(folder + '/')) {
filePath = filePath.substring(folder.length + 1);
}
return filePath;
}
/**
* Recursively resolve all file dependencies for a source file.
*/
function resolveAllDependencies(mainText, mainPath, platform, sourceDir) {
var resolved = [];
var seen = new Set();
function resolve(text, currentPath) {
var includes = parseIncludeDependencies(text, platform, currentPath);
var links = parseLinkDependencies(text, platform, currentPath);
var allPaths = includes.concat(links);
var linkSet = new Set(links);
for (var depPath of allPaths) {
var filename = stripLocalPath(depPath, mainPath);
if (seen.has(filename))
continue;
seen.add(filename);
var data = resolveFileData(depPath, sourceDir, platform);
if (data != null) {
resolved.push({
path: depPath,
filename: filename,
data: data,
link: linkSet.has(depPath),
});
// Recursively parse text files for their own dependencies
if (typeof data === 'string') {
resolve(data, depPath);
}
}
}
}
resolve(mainText, mainPath);
return resolved;
}
// TODO: refactor dependency parsing and tool selection into a common library
// shared between CodeProject (src/ide/project.ts) and testlib
/**
* Select the appropriate tool for a filename based on platform architecture.
*/
function getToolForFilename(fn, platform) {
var params = platforms_1.PLATFORM_PARAMS[(0, util_1.getBasePlatform)(platform)];
var arch = params && params.arch;
switch (arch) {
case 'z80':
case 'gbz80':
return (0, baseplatform_1.getToolForFilename_z80)(fn);
case '6502':
return (0, baseplatform_1.getToolForFilename_6502)(fn);
case '6809':
return (0, baseplatform_1.getToolForFilename_6809)(fn);
default:
return (0, baseplatform_1.getToolForFilename_z80)(fn); // fallback
}
}
/**
* Compile an arbitrary source file path.
* Parses include/link/resource directives and loads dependent files.
*/
async function compileSourceFile(tool, platform, filePath) {
await initialize();
var code = fs.readFileSync(filePath, 'utf-8');
var basename = filePath.split('/').pop();
var sourceDir = path.dirname(path.resolve(filePath));
// Auto-detect tool from filename if not specified
if (!tool) {
tool = getToolForFilename(basename, platform);
}
// Parse and resolve all dependencies
var deps = resolveAllDependencies(code, basename, platform, sourceDir);
if (deps.length === 0) {
// No dependencies found, use simple single-file path
return compile({
tool: tool,
platform: platform,
code: code,
path: basename,
});
}
// Build multi-file message with updates and buildsteps
var files = [];
var depFilenames = [];
// Main file first
files.push({ path: basename, data: code });
// Include files (non-link dependencies)
for (var dep of deps) {
if (!dep.link) {
files.push({ path: dep.filename, data: dep.data });
depFilenames.push(dep.filename);
}
}
// Build steps: main file first
var buildsteps = [];
buildsteps.push({
path: basename,
files: [basename].concat(depFilenames),
platform: platform,
tool: tool,
mainfile: true,
});
// Link dependencies get their own build steps, with tool selected by extension
for (var dep of deps) {
if (dep.link && dep.data) {
files.push({ path: dep.filename, data: dep.data });
buildsteps.push({
path: dep.filename,
files: [dep.filename].concat(depFilenames),
platform: platform,
tool: getToolForFilename(dep.filename, platform),
});
}
}
return compile({
tool: tool,
platform: platform,
code: code,
path: basename,
files: files,
buildsteps: buildsteps,
});
}
function workerResultToCompileResult(result) {

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,7 @@
"use strict";
// workerlib.ts - Node.js-friendly entry point for the worker build system
// Re-exports core worker functionality without Web Worker onmessage/postMessage wiring
// FOR TESTING ONLY
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -79,6 +80,14 @@ class Blob {
*/
function setupNodeEnvironment() {
// Basic globals expected by various parts of the worker system
// Some Emscripten-generated WASM modules check for __filename/__dirname
if (typeof globalThis.__filename === 'undefined') {
globalThis.__filename = __filename;
}
if (typeof globalThis.__dirname === 'undefined') {
globalThis.__dirname = __dirname;
// TODO: support require('path').dirname
}
wasmutils_1.emglobal.window = wasmutils_1.emglobal;
wasmutils_1.emglobal.exports = {};
wasmutils_1.emglobal.self = wasmutils_1.emglobal;

View File

@@ -1 +1 @@
{"version":3,"file":"workerlib.js","sourceRoot":"","sources":["../../src/worker/workerlib.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"workerlib.js","sourceRoot":"","sources":["../../src/worker/workerlib.ts"],"names":[],"mappings":"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"}

View File

@@ -3,7 +3,7 @@
// 8bws - 8bitworkshop CLI tool for compilation, ROM execution, and platform info
import * as fs from 'fs';
import { initialize, compile, compileSourceFile, preload, listTools, listPlatforms, PLATFORM_PARAMS, TOOLS, TOOL_PRELOADFS } from './testlib';
import { initialize, compile, compileSourceFile, preload, listTools, listPlatforms, getToolForFilename, PLATFORM_PARAMS, TOOLS, TOOL_PRELOADFS } from './testlib';
interface CLIResult {
success: boolean;
@@ -22,8 +22,8 @@ function usage(): void {
command: 'help',
data: {
commands: {
'compile': 'compile --tool <tool> --platform <platform> [--output <file>] <source>',
'check': 'check --tool <tool> --platform <platform> <source>',
'compile': 'compile --platform <platform> [--tool <tool>] [--output <file>] <source>',
'check': 'check --platform <platform> [--tool <tool>] <source>',
'run': 'run --platform <platform> [--frames N] <rom>',
'list-tools': 'list-tools',
'list-platforms': 'list-platforms',
@@ -61,15 +61,20 @@ async function doCompile(args: { [key: string]: string }, positional: string[],
var outputFile = args['output'];
var sourceFile = positional[0];
if (!tool || !platform || !sourceFile) {
if (!platform || !sourceFile) {
outputJSON({
success: false,
command: checkOnly ? 'check' : 'compile',
error: 'Required: --tool <tool> --platform <platform> <source>'
error: 'Required: --platform <platform> <source> [--tool <tool>]'
});
process.exit(1);
}
// Auto-detect tool from filename if not specified
if (!tool) {
tool = getToolForFilename(sourceFile, platform);
}
if (!TOOLS[tool]) {
outputJSON({
success: false,

View File

@@ -1,9 +1,13 @@
// testlib - Clean async API for compiling and testing 8bitworkshop projects
// Wraps the worker build system for use in tests and CLI tools
// FOR TESTING ONLY
import * as fs from 'fs';
import type { WorkerResult, WorkerMessage, WorkerErrorResult, WorkerOutputResult } from "../common/workertypes";
import * as path from 'path';
import type { WorkerResult, WorkerMessage, WorkerErrorResult, WorkerOutputResult, Dependency } from "../common/workertypes";
import { getFolderForPath, isProbablyBinary, getBasePlatform } from "../common/util";
import { getToolForFilename_z80, getToolForFilename_6502, getToolForFilename_6809 } from "../common/baseplatform";
import { setupNodeEnvironment, handleMessage, store, TOOL_PRELOADFS } from "../worker/workerlib";
import { PLATFORM_PARAMS } from "../worker/platforms";
import { TOOLS } from "../worker/workertools";
@@ -103,19 +107,258 @@ export async function compileFile(tool: string, platform: string, presetPath: st
});
}
/**
* Parse include and link dependencies from source text.
* Extracted from CodeProject.parseIncludeDependencies / parseLinkDependencies.
* TODO: project.ts should be refactored so we don't have to duplicate the logic
*/
function parseIncludeDependencies(text: string, platformId: string, mainPath: string): string[] {
let files: string[] = [];
let m;
var dir = getFolderForPath(mainPath);
function pushFile(fn: string) {
files.push(fn);
if (dir.length > 0 && dir != 'local')
files.push(dir + '/' + fn);
}
if (platformId.startsWith('verilog')) {
let re1 = /^\s*(`include|[.]include)\s+"(.+?)"/gmi;
while (m = re1.exec(text)) { pushFile(m[2]); }
let re1a = /^\s*\$(include|\$dofile|\$write_image_in_table)\('(.+?)'/gmi;
while (m = re1a.exec(text)) { pushFile(m[2]); }
let re2 = /^\s*([.]arch)\s+(\w+)/gmi;
while (m = re2.exec(text)) { pushFile(m[2] + ".json"); }
let re3 = /\$readmem[bh]\("(.+?)"/gmi;
while (m = re3.exec(text)) { pushFile(m[1]); }
} else {
let re2 = /^\s*[.#%]?(include|incbin|embed)\s+"(.+?)"/gmi;
while (m = re2.exec(text)) { pushFile(m[2]); }
let re3 = /^\s*([;']|[/][/])#(resource)\s+"(.+?)"/gm;
while (m = re3.exec(text)) { pushFile(m[3]); }
let re4 = /^\s+(USE|ASM)\s+(\S+[.]\S+)/gm;
while (m = re4.exec(text)) { pushFile(m[2]); }
let re5 = /^\s*(import|embed)\s*"(.+?)";/gmi;
while (m = re5.exec(text)) {
if (m[1] == 'import') pushFile(m[2] + ".wiz");
else pushFile(m[2]);
}
let re6 = /^\s*(import)\s*"(.+?)"/gmi;
while (m = re6.exec(text)) { pushFile(m[2]); }
let re7 = /^[!]src\s+"(.+?)"/gmi;
while (m = re7.exec(text)) { pushFile(m[1]); }
}
return files;
}
function parseLinkDependencies(text: string, platformId: string, mainPath: string): string[] {
let files: string[] = [];
let m;
var dir = getFolderForPath(mainPath);
function pushFile(fn: string) {
files.push(fn);
if (dir.length > 0 && dir != 'local')
files.push(dir + '/' + fn);
}
if (!platformId.startsWith('verilog')) {
let re = /^\s*([;]|[/][/])#link\s+"(.+?)"/gm;
while (m = re.exec(text)) { pushFile(m[2]); }
}
return files;
}
type FileData = string | Uint8Array;
interface ResolvedFile {
path: string; // path as referenced (may include folder prefix)
filename: string; // stripped filename for the worker
data: FileData;
link: boolean;
}
/**
* Try to resolve a file path by searching the source directory,
* the presets directory for the platform, and the current working directory.
*/
function resolveFileData(filePath: string, sourceDir: string, platform: string): FileData | null {
var searchPaths = [];
// Try relative to source file directory
if (sourceDir) {
searchPaths.push(path.resolve(sourceDir, filePath));
}
// Try presets directory
var basePlatform = getBasePlatform(platform);
searchPaths.push(path.resolve('presets', basePlatform, filePath));
// Try current working directory
searchPaths.push(path.resolve(filePath));
for (var p of searchPaths) {
try {
if (fs.existsSync(p)) {
if (isProbablyBinary(filePath)) {
return new Uint8Array(fs.readFileSync(p));
} else {
return fs.readFileSync(p, 'utf-8');
}
}
} catch (e) {
// continue searching
}
}
return null;
}
/**
* Strips the main file's folder prefix from a path (matching CodeProject.stripLocalPath).
*/
function stripLocalPath(filePath: string, mainPath: string): string {
var folder = getFolderForPath(mainPath);
if (folder != '' && filePath.startsWith(folder + '/')) {
filePath = filePath.substring(folder.length + 1);
}
return filePath;
}
/**
* Recursively resolve all file dependencies for a source file.
*/
function resolveAllDependencies(
mainText: string, mainPath: string, platform: string, sourceDir: string
): ResolvedFile[] {
var resolved: ResolvedFile[] = [];
var seen = new Set<string>();
function resolve(text: string, currentPath: string) {
var includes = parseIncludeDependencies(text, platform, currentPath);
var links = parseLinkDependencies(text, platform, currentPath);
var allPaths = includes.concat(links);
var linkSet = new Set(links);
for (var depPath of allPaths) {
var filename = stripLocalPath(depPath, mainPath);
if (seen.has(filename)) continue;
seen.add(filename);
var data = resolveFileData(depPath, sourceDir, platform);
if (data != null) {
resolved.push({
path: depPath,
filename: filename,
data: data,
link: linkSet.has(depPath),
});
// Recursively parse text files for their own dependencies
if (typeof data === 'string') {
resolve(data, depPath);
}
}
}
}
resolve(mainText, mainPath);
return resolved;
}
// TODO: refactor dependency parsing and tool selection into a common library
// shared between CodeProject (src/ide/project.ts) and testlib
/**
* Select the appropriate tool for a filename based on platform architecture.
*/
export function getToolForFilename(fn: string, platform: string): string {
var params = PLATFORM_PARAMS[getBasePlatform(platform)];
var arch = params && params.arch;
switch (arch) {
case 'z80':
case 'gbz80':
return getToolForFilename_z80(fn);
case '6502':
return getToolForFilename_6502(fn);
case '6809':
return getToolForFilename_6809(fn);
default:
return getToolForFilename_z80(fn); // fallback
}
}
/**
* Compile an arbitrary source file path.
* Parses include/link/resource directives and loads dependent files.
*/
export async function compileSourceFile(tool: string, platform: string, filePath: string): Promise<CompileResult> {
await initialize();
var code = fs.readFileSync(filePath, 'utf-8');
var basename = filePath.split('/').pop();
var sourceDir = path.dirname(path.resolve(filePath));
// Auto-detect tool from filename if not specified
if (!tool) {
tool = getToolForFilename(basename, platform);
}
// Parse and resolve all dependencies
var deps = resolveAllDependencies(code, basename, platform, sourceDir);
if (deps.length === 0) {
// No dependencies found, use simple single-file path
return compile({
tool: tool,
platform: platform,
code: code,
path: basename,
});
}
// Build multi-file message with updates and buildsteps
var files: { path: string; data: string | Uint8Array }[] = [];
var depFilenames: string[] = [];
// Main file first
files.push({ path: basename, data: code });
// Include files (non-link dependencies)
for (var dep of deps) {
if (!dep.link) {
files.push({ path: dep.filename, data: dep.data });
depFilenames.push(dep.filename);
}
}
// Build steps: main file first
var buildsteps: any[] = [];
buildsteps.push({
path: basename,
files: [basename].concat(depFilenames),
platform: platform,
tool: tool,
mainfile: true,
});
// Link dependencies get their own build steps, with tool selected by extension
for (var dep of deps) {
if (dep.link && dep.data) {
files.push({ path: dep.filename, data: dep.data });
buildsteps.push({
path: dep.filename,
files: [dep.filename].concat(depFilenames),
platform: platform,
tool: getToolForFilename(dep.filename, platform),
});
}
}
return compile({
tool: tool,
platform: platform,
code: code,
path: basename,
files: files,
buildsteps: buildsteps,
});
}

View File

@@ -1,6 +1,7 @@
// workerlib.ts - Node.js-friendly entry point for the worker build system
// Re-exports core worker functionality without Web Worker onmessage/postMessage wiring
// FOR TESTING ONLY
import * as fs from 'fs';
import * as path from 'path';
@@ -46,6 +47,14 @@ class Blob {
*/
export function setupNodeEnvironment() {
// Basic globals expected by various parts of the worker system
// Some Emscripten-generated WASM modules check for __filename/__dirname
if (typeof globalThis.__filename === 'undefined') {
(globalThis as any).__filename = __filename;
}
if (typeof globalThis.__dirname === 'undefined') {
(globalThis as any).__dirname = __dirname;
// TODO: support require('path').dirname
}
emglobal.window = emglobal;
emglobal.exports = {};
emglobal.self = emglobal;