From 76be2cbbb0edcc085b776ab1c5551d9f748cb1e7 Mon Sep 17 00:00:00 2001 From: Hyper_ <40342021+NotHyper-474@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:18:52 -0300 Subject: [PATCH 1/4] ci: Build Actions for Sample Projects --- .github/workflows/build-samples.yml | 91 ++++++++++++++++++++++++ include.xml | 3 + samples/.gitignore | 2 + samples/flixel/hmm.json | 4 +- samples/flixel_zip/hmm.json | 21 +++++- samples/heaps/hmm.json | 26 ++++++- samples/nme/hmm.json | 25 ++++++- samples/openfl/hmm.json | 25 ++++++- samples/openfl_firetongue/hmm.json | 23 +++++- samples/openfl_hscript/hmm.json | 24 +++++-- samples/openfl_hscript/project.xml | 1 - samples/openfl_hscript_class/hmm.json | 24 +++++-- samples/openfl_hscript_class/project.xml | 1 - samples/run.hxml | 3 + samples/scripts/SamplesHMMBuilder.hx | 83 +++++++++++++++++++++ 15 files changed, 331 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/build-samples.yml create mode 100644 samples/.gitignore create mode 100644 samples/run.hxml create mode 100644 samples/scripts/SamplesHMMBuilder.hx diff --git a/.github/workflows/build-samples.yml b/.github/workflows/build-samples.yml new file mode 100644 index 00000000..dd5c80e7 --- /dev/null +++ b/.github/workflows/build-samples.yml @@ -0,0 +1,91 @@ +# Builds the sample projects on multiple targets to check for compiler errors. + +name: Build Samples + +on: + #push: + pull_request: + workflow_dispatch: + +jobs: + build: + strategy: + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + target: [cpp, html5, hl] + fail-fast: false + + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout + uses: actions/checkout@v6.0.2 + + - name: Setup Haxe + uses: FunkinCrew/ci-haxe@v3 + with: + haxe-version: 4.3.7 + + - name: Setup hmm.json for Samples + working-directory: ./samples + run: haxe run.hxml + + - name: Cache Haxelibs + uses: actions/cache@v6 + with: + path: ./samples/.haxelib + key: haxelib-${{ hashFiles('samples/hmm.json') }} + enableCrossOsArchive: true + restore-keys: | + haxelib- + + - name: Setup HMM + run: | + haxelib --global --quiet --never update haxelib + haxelib --global fixrepo + haxelib --global --quiet install hmm + haxelib --global run hmm setup + + - name: Install sample dependencies + working-directory: ./samples + run: | + hmm install --quiet + haxelib fixrepo + + - name: Build Flixel Sample + working-directory: ./samples/flixel + run: haxelib run lime build ${{ matrix.target }} --no-output + + - name: Build ZIP Flixel Sample + working-directory: ./samples/flixel_zip + run: haxelib run lime build ${{ matrix.target }} --no-output + + - name: Build Heaps Sample + if: matrix.target == 'hl' + working-directory: ./samples/heaps + run: haxe hl.hxml + + # The NME target seems to be in a pretty unusable state, so we will ignore errors for now. + - name: Build NME Sample + continue-on-error: true + if: matrix.target != 'hl' && matrix.target != 'html5' + working-directory: ./samples/nme + run: echo y | haxelib run nme build ${{ matrix.target }} --no-output + + - name: Build OpenFL Sample + working-directory: ./samples/openfl + run: haxelib run openfl build ${{ matrix.target }} --no-output + + - name: Build OpenFL (Firetongue) Sample + working-directory: ./samples/openfl_firetongue + run: haxelib run openfl build ${{ matrix.target }} --no-output + + - name: Build OpenFL (HScript) Sample + working-directory: ./samples/openfl_hscript + run: haxelib run openfl build ${{ matrix.target }} --no-output + + - name: Build OpenFL (HScript with Classes) Sample + working-directory: ./samples/openfl_hscript_class + run: haxelib run openfl build ${{ matrix.target }} --no-output + + diff --git a/include.xml b/include.xml index 9a6efc6d..c7e46176 100644 --- a/include.xml +++ b/include.xml @@ -1,6 +1,9 @@ + + + diff --git a/samples/openfl_hscript_class/hmm.json b/samples/openfl_hscript_class/hmm.json index 0bfaa61d..e1ee973c 100644 --- a/samples/openfl_hscript_class/hmm.json +++ b/samples/openfl_hscript_class/hmm.json @@ -1,17 +1,22 @@ { "dependencies": [ { - "name": "hscript", + "name": "hxcpp", "type": "haxelib", "version": null }, { - "name": "hxcpp", + "name": "hxcpp-debug-server", "type": "haxelib", "version": null }, { - "name": "hxcpp-debug-server", + "name": "jsonpatch", + "type": "haxelib", + "version": null + }, + { + "name": "jsonpath", "type": "haxelib", "version": null }, @@ -30,10 +35,19 @@ "path": "../..", "type": "dev" }, + { + "name": "thx.core", + "type": "git", + "dir": null, + "ref": "master", + "url": "https://github.com/fponticelli/thx.core" + }, { "name": "thx.semver", - "type": "haxelib", - "version": null + "type": "git", + "dir": null, + "ref": "master", + "url": "https://github.com/fponticelli/thx.semver" } ] } diff --git a/samples/openfl_hscript_class/project.xml b/samples/openfl_hscript_class/project.xml index 9dc38ff2..6979e8c6 100644 --- a/samples/openfl_hscript_class/project.xml +++ b/samples/openfl_hscript_class/project.xml @@ -11,7 +11,6 @@ - diff --git a/samples/run.hxml b/samples/run.hxml new file mode 100644 index 00000000..8a04b532 --- /dev/null +++ b/samples/run.hxml @@ -0,0 +1,3 @@ +--class-path scripts +--main SamplesHMMBuilder +--interp diff --git a/samples/scripts/SamplesHMMBuilder.hx b/samples/scripts/SamplesHMMBuilder.hx new file mode 100644 index 00000000..274b5446 --- /dev/null +++ b/samples/scripts/SamplesHMMBuilder.hx @@ -0,0 +1,83 @@ +package ; + +import haxe.format.JsonPrinter; +import haxe.format.JsonParser; +import haxe.Json; +import sys.io.File; +import haxe.io.Path; +import sys.FileSystem; + +typedef HMMDependency = +{ + name:String, + type:String, + ?version: String, + ?path:String, + ?dir:String, + ?url:String, + ?ref:String, +} + +/** + * A simple tool to build a `hmm.json` file for the samples directory, + * by scanning for `hmm.json` files in each sample subdirectory and merging + * their dependencies into a single `hmm.json` file. + */ +class SamplesHMMBuilder +{ + /** + * A list of sample directories to ignore when scanning for `hmm.json` files. + * This is useful if certain samples do not work well with the system. + */ + static final IGNORE_LIST:Array = []; + + public static function main() + { + var scriptsPath:String = Path.directory(Sys.programPath()); + var workPath:String = Path.normalize('$scriptsPath/..'); + + var searchPaths:Array = FileSystem.readDirectory(workPath); + var dependencies:Map = []; + + for (path in searchPaths) + { + if (IGNORE_LIST.contains(path)) continue; + if (!FileSystem.isDirectory(path)) continue; + + var hmmPath:String = Path.join([path, 'hmm.json']); + if (!FileSystem.exists(hmmPath)) continue; + + var hmmContent:String = File.getContent(hmmPath); + try + { + var json:{ dependencies:Array } = Json.parse(hmmContent); + if (json.dependencies == null) continue; + + for (dependency in json.dependencies) + { + if (dependencies.exists(dependency.name)) + { + continue; + } + + dependencies.set(dependency.name, dependency); + } + } + catch (_) {} + } + + var result = { dependencies: [] }; + for (dependency in dependencies) + { + if (dependency.name == 'polymod' && dependency.type == 'dev') + { + // Force correct relative path + dependency.path = '..'; + } + + result.dependencies.push(dependency); + } + + File.saveContent(Path.join([workPath, 'hmm.json']), Json.stringify(result, ' ')); + } +} From e3bd0a2ac50427419ad9b1497b0b270284985c7b Mon Sep 17 00:00:00 2001 From: Hyper_ <40342021+NotHyper-474@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:56:34 -0300 Subject: [PATCH 2/4] General cleanup to fix issues with building samples --- polymod/Polymod.hx | 31 +++- polymod/fs/BaseFileSystem.hx | 31 ++-- polymod/fs/StubFileSystem.hx | 14 +- polymod/hscript/HScriptable.hx | 133 ----------------- polymod/hscript/ScriptRunner.hx | 139 ++++++++++++++++++ polymod/hscript/_internal/HScriptableMacro.hx | 13 +- polymod/hscript/_internal/Interp.hx | 10 +- 7 files changed, 201 insertions(+), 170 deletions(-) create mode 100644 polymod/hscript/ScriptRunner.hx diff --git a/polymod/Polymod.hx b/polymod/Polymod.hx index 0c45bf7e..58f31e5a 100644 --- a/polymod/Polymod.hx +++ b/polymod/Polymod.hx @@ -279,7 +279,6 @@ class Polymod params.dirs ??= []; params.ignoredFiles ??= []; - var shouldLoadMods:Bool = params.modIds.length == 0 && params.dirs.length == 0; if (params.fileSystemParams == null) params.fileSystemParams = {modRoot: modRoot}; if (params.fileSystemParams.modRoot == null) params.fileSystemParams.modRoot = modRoot; if (params.apiVersionRule == null) params.apiVersionRule = VersionUtil.DEFAULT_VERSION_RULE; @@ -411,7 +410,8 @@ class Polymod return sortedModsToLoad; } - static function cleanupAssetLibrary():Void { + static function cleanupAssetLibrary():Void + { if (assetLibrary == null) return; var fileSystem = assetLibrary.fileSystem; @@ -891,7 +891,7 @@ class Polymod #if hscript_typer polymod.hscript._internal.PolymodTyperEx.clearAllModules(); #end - polymod.hscript.HScriptable.ScriptRunner.clearScripts(); + polymod.hscript.ScriptRunner.clearScripts(); } static function prepareRegisterScriptedClasses():Void @@ -970,9 +970,9 @@ class Polymod #end } + #if (POLYMOD_CPPIA && lime) static function registerAllCppiaClassesAsync():Array> { - #if POLYMOD_CPPIA @:privateAccess { var libraryIds:Array = Polymod.assetLibrary.listLibraries(); var allBytes:Array = Polymod.assetLibrary.list(BYTES); @@ -1047,10 +1047,17 @@ class Polymod } return futures; } - #else - return []; + } + #else + static function registerAllCppiaClassesAsync() + { + // Only error if we're not using Lime + #if POLYMOD_CPPIA + Polymod.error(SCRIPT_PARSE_FAILED, 'Asynchronous script loading with CPPIA is not supported on this platform!'); #end + return []; } + #end /** * Loads all script classes (`.hxc` files) and registers any classes they provide. @@ -1082,7 +1089,8 @@ class Polymod break; } } - if (!Polymod.assetLibrary.exists(path)) { + if (!Polymod.assetLibrary.exists(path)) + { Polymod.error(SCRIPT_NOT_FOUND, 'Could not find file "$textPath"'); results.set(path, false); } @@ -1150,7 +1158,8 @@ class Polymod } } - return lime.app.Promise.allSettled(futures).then((results) -> { + return lime.app.Promise.allSettled(futures).then((results) -> + { #if POLYMOD_CPPIA polymod.hscript._internal.PolymodCppiaClassReference.unloadInactiveModules(); #end @@ -1163,6 +1172,12 @@ class Polymod return lime.app.Future.withValue(results); }); } + #else + public static function registerAllScriptClassesAsync():Array + { + Polymod.error(SCRIPT_PARSE_FAILED, 'Asynchronous script loading is not supported on this platform!'); + return []; + } #end /** diff --git a/polymod/fs/BaseFileSystem.hx b/polymod/fs/BaseFileSystem.hx index 9a06953d..6736d5aa 100644 --- a/polymod/fs/BaseFileSystem.hx +++ b/polymod/fs/BaseFileSystem.hx @@ -104,40 +104,38 @@ abstract class BaseFileSystem implements IFileSystem return new Future(performWork, true); } - #end /** - * Get the byte data for a file from a specific mod. + * Load the byte data for a file from a specific mod, asynchronously. * * @param path The path to retrieve byte data from, relative to the asset root. * @param modId A specific mod ID to retrieve an asset from. - * @return The file bytes, or `null` if it couldn't be fetched. + * @return A future which returns the file bytes. */ - public function getFileBytesByModId(path:String, modId:String):Null + public function loadFileBytesByModId(path:String, modId:String):Future { - var modDir:String = scanModDirectoriesForId(modId) ?? return null; - var relativeDir:String = Util.pathJoin(modRoot, modDir); + var modDir:Null = scanModDirectoriesForId(modId); + if (modDir == null) return null; + var relativeDir = Util.pathJoin(modRoot, modDir); - return getFileBytes(Util.pathJoin(relativeDir, path)); + return loadFileBytes(Util.pathJoin(relativeDir, path)); } + #end - #if lime /** - * Load the byte data for a file from a specific mod, asynchronously. + * Get the byte data for a file from a specific mod. * * @param path The path to retrieve byte data from, relative to the asset root. * @param modId A specific mod ID to retrieve an asset from. - * @return A future which returns the file bytes. + * @return The file bytes, or `null` if it couldn't be fetched. */ - public function loadFileBytesByModId(path:String, modId:String):Future + public function getFileBytesByModId(path:String, modId:String):Null { - var modDir:Null = scanModDirectoriesForId(modId); - if (modDir == null) return null; - var relativeDir = Util.pathJoin(modRoot, modDir); + var modDir:String = scanModDirectoriesForId(modId) ?? return null; + var relativeDir:String = Util.pathJoin(modRoot, modDir); - return loadFileBytes(Util.pathJoin(relativeDir, path)); + return getFileBytes(Util.pathJoin(relativeDir, path)); } - #end /** * Provide a list of valid mods for this file system to load. @@ -295,7 +293,6 @@ abstract class BaseFileSystem implements IFileSystem function getModIconPath(modPath:String, ?origin:PolymodErrorOrigin):Null { - var foundIcon = false; for (iconBasePath in PolymodConfig.modIconFile) { var iconFile = Util.pathJoin(modPath, iconBasePath); diff --git a/polymod/fs/StubFileSystem.hx b/polymod/fs/StubFileSystem.hx index e9646b1e..5e6696c8 100644 --- a/polymod/fs/StubFileSystem.hx +++ b/polymod/fs/StubFileSystem.hx @@ -16,7 +16,7 @@ import polymod.fs.PolymodFileSystem.PolymodFileSystemParams; @SuppressWarnings('checkstyle:FieldDocComment') class StubFileSystem implements IFileSystem { - public final modRoot:String; + public final modRoot:String = ''; public function new(params:PolymodFileSystemParams) {} public inline function exists(path:String):Bool @@ -58,6 +58,18 @@ class StubFileSystem implements IFileSystem return null; } + #if lime + public inline function loadFileBytes(path:String):lime.app.Future + { + return cast lime.app.Future.withError('Cannot load file bytes from stub file system'); + } + + public inline function loadFileBytesByModId(path:String, modId:String):lime.app.Future + { + return cast lime.app.Future.withError('Cannot load file bytes from stub file system'); + } + #end + public inline function readDirectoryRecursive(path:String):Array { return []; diff --git a/polymod/hscript/HScriptable.hx b/polymod/hscript/HScriptable.hx index 18e9cb78..0c8f2e06 100644 --- a/polymod/hscript/HScriptable.hx +++ b/polymod/hscript/HScriptable.hx @@ -1,9 +1,6 @@ package polymod.hscript; import haxe.Json; -import polymod.hscript._internal.Expr; -import polymod.Polymod; -import polymod.util.Util; /** * This interface triggers the execution of a macro on any elements which use the `@:hscript` annotation. @@ -171,133 +168,3 @@ class HScriptParams return Json.stringify(this); } } - -typedef ScriptOutput = -{ - /** - * The output of the script. Can be any value type. - */ - var script_result:Dynamic; - - /** - * The functions and variables created within the scope of the script. - */ - var script_variables:Map; -} - -class ScriptRunner -{ - /** - * No reason not to make this static! Load a script once instead of 50 times. - */ - private static var scripts:Map = new Map(); - - public function new() {} - - public static function clearScripts():Void - { - scripts.clear(); - } - - public function load(name:String, assetHandler:Dynamic):Null