diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 985d9f8..bb97166 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,8 +54,8 @@ jobs: DevPackages key: tools-${{ hashFiles('rokit.toml') }} - - name: Lint StateMachine - run: ./scripts/lint.sh src/StateMachine + - name: Lint StateQ + run: ./scripts/lint.sh src/StateQ - name: Lint tests run: ./scripts/lint.sh src/TestService @@ -83,8 +83,8 @@ jobs: DevPackages key: tools-${{ hashFiles('rokit.toml') }} - - name: Enforce StateMachine code style with StyLua - run: ./scripts/formatCheck.sh src/StateMachine + - name: Enforce StateQ code style with StyLua + run: ./scripts/formatCheck.sh src/StateQ - name: Enforce tests code style with StyLua run: ./scripts/formatCheck.sh src/TestService @@ -112,10 +112,10 @@ jobs: DevPackages key: tools-${{ hashFiles('rokit.toml') }} - - name: Analyze StateMachine with luau-lsp + - name: Analyze StateQ with luau-lsp run: | - ./scripts/sourcemap.sh default.project.json stateMachineSourcemap.json - ./scripts/analyze.sh stateMachineSourcemap.json src/StateMachine + ./scripts/sourcemap.sh default.project.json stateQSourcemap.json + ./scripts/analyze.sh stateQSourcemap.json src/StateQ - name: Analyze tests with luau-lsp run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..243b5d9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,223 @@ +name: Release + +on: + release: + types: [published] + +jobs: + get-version: + name: Get version from release tag + runs-on: ubuntu-latest + + outputs: + tag-name: ${{ steps.output-version.outputs.tag_name }} + version-with-dots: ${{ steps.output-version.outputs.version_with_dots }} + version-with-dashes: ${{ steps.output-version.outputs.version_with_dashes }} + + steps: + - name: Checkout code + uses: actions/checkout@v4.1.7 + + - name: Output version and tag name + id: output-version + run: | + # Get the tag name (e.g., v0.1.0) + tag_name="${{ github.event.release.tag_name }}" + echo "tag_name=$tag_name" >> $GITHUB_OUTPUT + echo "tag_name=$tag_name" + + # Strip the leading 'v' to get the version (e.g., 0.1.0) + version_with_dots="${tag_name#v}" + echo "version_with_dots=$version_with_dots" >> $GITHUB_OUTPUT + echo "version_with_dots=$version_with_dots" + + # Replaces . with - for use in filenames (e.g., 0-1-0) + version_with_dashes="${version_with_dots//./-}" + echo "version_with_dashes=$version_with_dashes" >> $GITHUB_OUTPUT + echo "version_with_dashes=$version_with_dashes" + + install-tools: + name: Install tools and dependencies + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4.1.7 + + - name: Install Rokit + uses: CompeyDev/setup-rokit@v0.1.2 + + - name: Setup Lune + run: lune setup + + - name: Install dependencies with Wally + run: wally install + + - name: Cache installed items + uses: actions/cache@v4.0.2 + with: + path: | + ~/.rokit + ~/.lune + Packages + DevPackages + key: tools-${{ hashFiles('rokit.toml') }} + + preprocess-release: + name: Preprocess release (update versions, copyright years) + runs-on: ubuntu-latest + needs: [install-tools, get-version] + environment: Release Preprocessor + permissions: + contents: write + outputs: + commit-hash: ${{ steps.commit-and-push.outputs.commit_hash }} + + steps: + - uses: actions/create-github-app-token@v1.11.0 + id: release-preprocessor-bot-token + with: + app-id: ${{ vars.RELEASE_PREPROCESSOR_APP_ID }} + private-key: ${{ secrets.RELEASE_PREPROCESSOR_PRIVATE_KEY }} + + - name: Checkout code + uses: actions/checkout@v4.1.7 + with: + token: ${{ steps.release-preprocessor-bot-token.outputs.token }} + + - name: Restore installed items + uses: actions/cache@v4.0.2 + with: + path: | + ~/.rokit + ~/.lune + Packages + DevPackages + key: tools-${{ hashFiles('rokit.toml') }} + + - name: Add rokit tools to PATH + run: echo "$HOME/.rokit/bin" >> $GITHUB_PATH + + - name: Locally update version & copyright year in files + run: lune run preprocessRelease ${{ needs.get-version.outputs.version-with-dots }} + + - name: Commit version & copyright year updates + id: commit-and-push + uses: stefanzweifel/git-auto-commit-action@v5.0.1 + with: + commit_message: "Preprocess release for version ${{ needs.get-version.outputs.version-with-dots }}" + branch: main + file_pattern: "README.md wally.toml src/StateQ/init.luau LICENSE.md" + + create-release-artifacts: + name: Create release artifacts + runs-on: ubuntu-latest + needs: [install-tools, get-version, preprocess-release] + + steps: + - name: Checkout code + uses: actions/checkout@v4.1.7 + with: + ref: ${{ needs.preprocess-release.outputs.commit-hash }} + + - name: Restore installed items + uses: actions/cache@v4.0.2 + with: + path: | + ~/.rokit + ~/.lune + Packages + DevPackages + key: tools-${{ hashFiles('rokit.toml') }} + + - name: Add rokit tools to PATH + run: echo "$HOME/.rokit/bin" >> $GITHUB_PATH + + - name: Build release artifacts + run: lune run build ${{ needs.get-version.outputs.version-with-dashes }} + + - name: Cache artifacts + uses: actions/cache@v4.0.2 + with: + path: | + build + wally.toml + key: artifacts-${{ needs.get-version.outputs.tag-name }} + + publish-wally-artifact: + name: Publish release artifact to Wally + runs-on: ubuntu-latest + needs: + [install-tools, get-version, preprocess-release, create-release-artifacts] + + steps: + - name: Checkout code + uses: actions/checkout@v4.1.7 + with: + ref: ${{ needs.preprocess-release.outputs.commit-hash }} + + - name: Restore installed items + uses: actions/cache@v4.0.2 + with: + path: | + ~/.rokit + ~/.lune + Packages + DevPackages + key: tools-${{ hashFiles('rokit.toml') }} + + - name: Restore build artifacts + uses: actions/cache@v4.0.2 + with: + path: | + build + wally.toml + key: artifacts-${{ needs.get-version.outputs.tag-name }} + + - name: Add rokit tools to PATH + run: echo "$HOME/.rokit/bin" >> $GITHUB_PATH + + - name: Log in to Wally + run: wally login --token ${{ secrets.WALLY_ACCESS_TOKEN }} + + - name: Publish package to Wally + run: wally publish + + upload-github-artifacts: + name: Upload artifacts to the GitHub release + runs-on: ubuntu-latest + needs: [get-version, create-release-artifacts] + permissions: + contents: write + + steps: + - name: Restore build artifacts + uses: actions/cache@v4.0.2 + with: + path: | + build + wally.toml + key: artifacts-${{ needs.get-version.outputs.tag-name }} + + - name: Print files + run: ls -R + + - name: Upload zip artifact to the GitHub release + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: build/zip/StateQ-${{ needs.get-version.outputs.version-with-dashes}}.zip + asset_name: StateQ-${{ needs.get-version.outputs.version-with-dashes}}.zip + asset_content_type: application/zip + + - name: Upload rbxm artifact to the GitHub release + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: build/rbxm/StateQ-${{ needs.get-version.outputs.version-with-dashes }}.rbxm + asset_name: StateQ-${{ needs.get-version.outputs.version-with-dashes }}.rbxm + asset_content_type: application/octet-stream diff --git a/.gitignore b/.gitignore index ee14388..72c153b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,6 @@ globaltypes.d.luau Packages DevPackages *sourcemap.json -settings.json \ No newline at end of file +settings.json +build +.DS_Store \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1c63ece..424cd7a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -116,7 +116,7 @@ If you're running tests in studio yourself (not recommended) instead of using th | Method | Instructions | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -| CLI | `rojo build test.project.json -o StateMachine-Test.rbxl` | +| CLI | `rojo build test.project.json -o StateQ-Test.rbxl` | | VSC Extension | Click Rojo on the status bar at the bottom, mouse over `test.project.json` in the pop-up menu, and click the Build icon on the right of the list item. | @@ -174,10 +174,10 @@ You need to set the `FFlagEnableLoadModule` value to `true`. Be sure to restart ### Run tests -| Method | Instructions | -| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| CLI (recommended) | `lune run test` | -| Roblox Studio | Open the test place file `StateMachine-Test.rbxl` [built in the above step](#build-the-project) in Roblox Studio and run the place (server only). The output widget will show the test results. | +| Method | Instructions | +| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| CLI (recommended) | `lune run test` | +| Roblox Studio | Open the test place file `StateQ-Test.rbxl` [built in the above step](#build-the-project) in Roblox Studio and run the place (server only). The output widget will show the test results. | ### Continuous Integration (CI) @@ -211,3 +211,12 @@ Alternatively, you can run individual steps yourself: There is an additional script available to fix formatting with StyLua, that does not run on GitHub: > lune run formatFix + +## Releasing + +1. To make a release, use the GitHub web interface to [create a new release](https://github.com/BusyCityGuy/finite-state-machine-luau/releases/new). +1. Choose a tag with a version number like `v0.0.0`, beginning with `v` and using semantic versioning. No suffix like `-pre` is supported, only numbers as shown. +1. Create a release title, preferably something like "Version 0.0.0" to be consistent with the tag. +1. Describe the changes in the release +1. Publish release +1. A GitHub Actions workflow will automatically run and upload .zip and .rbxm artifacts to the release. It will also automatically publish the release to Wally, and update hardcoded numbers throughout the codebase like versions and copyright years. \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md index ebbf7d2..e12da40 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 BusyCityGuy +Copyright (c) 2024 BusyCityGuy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 55e812b..dcd873a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Finite State Machine (FSM) in Luau +# StateQ: A Finite State Machine (FSM) in Luau -A feature rich and fully typed implementation of a Finite State Machine in [Luau](https://luau-lang.org/), developed for use in Roblox experiences. +An intuitive fully-typed Finite State Machine in [Luau](https://luau-lang.org/) that supports async transitions by queueing events, developed for use in Roblox experiences. This project is licensed under the terms of the MIT license. See [LICENSE.md](https://github.com/busycityguy/finite-state-machine-luau/blob/main/LICENSE.md) for details. @@ -51,7 +51,7 @@ A simple state machine diagram for a light switch may look like this, where - States are represented as rectangles, and squares indicate the State can be Final - Events are represented as capsules -![Screen Shot 2023-12-14 at 18 04 33](https://github.com/BusyCityGuy/finite-state-machine-luau/assets/55513323/3d5b2118-91ea-4427-ac2d-688fb0094d1f) +![ExampleUsage](https://github.com/BusyCityGuy/finite-state-machine-luau/assets/55513323/3d5b2118-91ea-4427-ac2d-688fb0094d1f) ```luau local LightState = { @@ -64,7 +64,7 @@ local Event = { SwitchOff = "SwitchOff", } -local light = StateMachine.new(LightState.On, { +local light = StateQ.new(LightState.On, { [Event.SwitchOn] = { canBeFinal = true, from = { @@ -107,22 +107,22 @@ light:handle(Event.SwitchOn) -- warns "Illegal event `SwitchOn` called during st # Installation -If your project is set up to build with Rojo, you can add this repository as a submodule of your project by running the following command: +## Rojo users -`git submodule add https://github.com/BusyCityGuy/finite-state-machine-luau path/to/your/dependencies` +If your project is set up to build with Rojo, the preferred installation method is using [Wally](https://wally.run/). Add this to your `wally.toml` file: +> StateQ = "busycityguy/stateq@0.0.4" -
-These alternative installations are not implemented yet +If you're not using Wally, you can add this repository as a submodule of your project by running the following command: -In the future, an alternative installation method will be to download your desired release file from the [Releases](https://github.com/BusyCityGuy/latest) page. +> git submodule add https://github.com/BusyCityGuy/finite-state-machine-luau path/to/your/dependencies -Provided in the release will be a `.zip` file that can be extracted into your Rojo project, or you can download the `.rbxm` and drag it into Roblox Studio if you're not using Rojo. +If you want to avoid submodules too, you can download the `.zip` file from the [latest release](https://github.com/BusyCityGuy/finite-state-machine-luau/releases/latest) page. -Also in the future, this project will be published on [Wally](https://wally.run/), and could be installed into your project by adding `finite-state-machine = "busycityguy/finite-state-machine@0.0.0"` to your `wally.toml` file. +## Non-Rojo users -
+If you aren't using Rojo, you can download the `.rbxm` file from the [latest release](https://github.com/BusyCityGuy/finite-state-machine-luau/releases/latest) page and drag it into Roblox Studio. -# Help! +# Feedback If you have other questions, bugs, feature requests, or feedback, please [open an issue](https://github.com/BusyCityGuy/finite-state-machine-luau/issues)! diff --git a/default.project.json b/default.project.json index 642e265..b77509c 100644 --- a/default.project.json +++ b/default.project.json @@ -1,9 +1,9 @@ { - "name": "StateMachine", - "tree": { - "$path": "src/StateMachine", - "Dependencies": { - "$path": "Packages" - } - } -} \ No newline at end of file + "name": "StateQ", + "tree": { + "$path": "src/StateQ", + "Dependencies": { + "$path": "Packages" + } + } +} diff --git a/lune/analyze.luau b/lune/analyze.luau index 2371058..89b420d 100644 --- a/lune/analyze.luau +++ b/lune/analyze.luau @@ -17,9 +17,9 @@ local task = require("@lune/task") local ANALYZE_PATHS: { { path: string, project: string?, sourceMap: string? } } = { { - path = Path.join("src", "StateMachine"), + path = Path.join("src", "StateQ"), project = "default.project.json", - sourceMap = "stateMachineSourcemap.json", + sourceMap = "stateQSourcemap.json", }, { path = Path.join("src", "TestService"), diff --git a/lune/build.luau b/lune/build.luau new file mode 100644 index 0000000..3a79ef5 --- /dev/null +++ b/lune/build.luau @@ -0,0 +1,95 @@ +--!strict + +--[[ + Builds the release artifacts of the finite state machine. Used by CI to upload to various release targets. + + Since the parent folder is named `lune`, the `lune` cli will automatically look in this directory for scripts to run. + + Usage (from project directory): + lune run build 0-0-0 + + Where 0-0-0 is the version of the release. + This creates a build folder in the root directory with a subdirectory for each build target. For example, + - build + - rbxm + StateQ-0-0-0.rbxm + - wally + stateq-0-0-0 + - zip + StateQ-0-0-0.zip + + You can also build without appending the version number if you want to test locally without putting a dummy version number in. + lune run build + This produces a structure like the following + - build + - rbxm + StateQ.rbxm + - wally + stateq + - zip + StateQ.zip +--]] + +local Path = require("Utils/Path") +local fs = require("@lune/fs") +local process = require("@lune/process") + +local version = process.args[1] +assert(version == nil or version:match("^%d+%-%d+%-%d+$"), `Invalid version format. Expected "x-y-z", got "{version}"`) +local suffix = if version then `-{version}` else "" +local fileName = `StateQ{suffix}` +local buildFolder = "build" + +local function ensurePath(...: string) + local path = Path.join(...) + if not fs.isDir(path) then + print("Creating path", path) + fs.writeDir(path) + end + return path +end + +local build_targets = { + { + description = "rbxm", + command = "rojo", + args = { + "build", + "default.project.json", + "--output", + `{Path.join(ensurePath(buildFolder, "rbxm"), `{fileName}.rbxm`)}`, + }, + }, + { + description = "Wally package", + command = "wally", + args = { + "package", + "--output", + `{Path.join(ensurePath(buildFolder, "wally"), fileName:lower())}`, + }, + }, + { + description = "zip", + command = "zip", + args = { + "-r", + `{Path.join(ensurePath(buildFolder, "zip"), fileName)}.zip`, + "src/StateQ", + "default.project.json", + "Packages", + "README.md", + "LICENSE.md", + }, + }, +} + +for _, buildTarget in build_targets do + print(`\nBuilding {buildTarget.description} artifact...`) + print(buildTarget.command, table.concat(buildTarget.args, " ")) + local proc = process.spawn(buildTarget.command, buildTarget.args) + print(proc.stdout) + assert(proc.ok, proc.stderr) +end + +process.exit(0) diff --git a/lune/formatCheck.luau b/lune/formatCheck.luau index 5ada7ae..39c68d5 100644 --- a/lune/formatCheck.luau +++ b/lune/formatCheck.luau @@ -18,7 +18,7 @@ local stdio = require("@lune/stdio") local task = require("@lune/task") local FORMAT_PATHS = { - Path.join("src", "StateMachine"), + Path.join("src", "StateQ"), Path.join("src", "TestService"), "lune", } diff --git a/lune/formatFix.luau b/lune/formatFix.luau index 460d99e..daac01b 100644 --- a/lune/formatFix.luau +++ b/lune/formatFix.luau @@ -17,7 +17,7 @@ local stdio = require("@lune/stdio") local task = require("@lune/task") local FORMAT_PATHS = { - Path.join("src", "StateMachine"), + Path.join("src", "StateQ"), Path.join("src", "TestService"), "lune", } diff --git a/lune/lint.luau b/lune/lint.luau index 0d6a20f..62c1861 100644 --- a/lune/lint.luau +++ b/lune/lint.luau @@ -16,7 +16,7 @@ local stdio = require("@lune/stdio") local task = require("@lune/task") local LINT_PATHS = { - Path.join("src", "StateMachine"), + Path.join("src", "StateQ"), Path.join("src", "TestService"), "lune", } diff --git a/lune/preprocessRelease.luau b/lune/preprocessRelease.luau new file mode 100644 index 0000000..24871b7 --- /dev/null +++ b/lune/preprocessRelease.luau @@ -0,0 +1,68 @@ +--!strict + +--[[ + Updates hardcoded versions in the project files to the version specified in the first argument. + Also updates hardcoded copyright years to the current year. + Meant to be used by the release workflow to update the codebase when a release is made. + + Since the parent folder is named `lune`, the `lune` cli will automatically look in this directory for scripts to run. + + Usage (from project directory): + lune run preprocessRelease 0.0.0 +--]] + +local DateTime = require("@lune/datetime") +local fs = require("@lune/fs") +local process = require("@lune/process") + +local version: string = process.args[1] +assert(version, "No version specified") +assert(version:match("^%d+%.%d+%.%d+$"), `Invalid version format. Expected "x.y.z", got "{version}"`) + +local function updateFile(description: string, filePath: string, pattern: string, replacement: string) + local fileContents = fs.readFile(filePath) + local foundMatch = fileContents:match(pattern) + assert(foundMatch, `Could not find match for {description} in {filePath}`) + + local updatedContents = fileContents:gsub(pattern, replacement) + fs.writeFile(filePath, updatedContents) + print(`Updated {description} in {filePath} from {foundMatch} to {replacement:match(pattern)}`) +end + +-- If you add files to this list that you expect to be automatically updated, be sure to update .github/workflows/release.yml to include +-- the new file in the `paths` list of the `set_version` job. The workflow specifies a second source of truth on which files to commit as +-- a safeguard against accidentally automatically committing unexpected changes to main, which could happen if it just committed changes from all files. +local replacementData = { + { + description = "package version", + paths = { "README.md" }, + pattern = "stateq@([0-9]+%.[0-9]+%.[0-9]+)", + replacement = `stateq@{version}`, + }, + { + description = "package version", + paths = { "wally.toml" }, + pattern = 'version = "([0-9]+%.[0-9]+%.[0-9]+)"', + replacement = `version = "{version}"`, + }, + { + description = "package version", + paths = { "src/StateQ/init.luau" }, + pattern = "%-%- Version: ([0-9]+%.[0-9]+%.[0-9]+)", + replacement = `-- Version: {version}`, + }, + { + description = "copyright year", + paths = { "src/StateQ/init.luau", "LICENSE.md" }, + pattern = "Copyright %(c%) (%d+) BusyCityGuy", + replacement = `Copyright (c) {DateTime.now():toUniversalTime().year} BusyCityGuy`, + }, +} + +for _, data in replacementData do + for _, path in data.paths do + updateFile(data.description, path, data.pattern, data.replacement) + end +end + +process.exit(0) diff --git a/src/StateMachine/Modules/Logger.luau b/src/StateQ/Modules/Logger.luau similarity index 96% rename from src/StateMachine/Modules/Logger.luau rename to src/StateQ/Modules/Logger.luau index a4fab2f..a8ad27c 100644 --- a/src/StateMachine/Modules/Logger.luau +++ b/src/StateQ/Modules/Logger.luau @@ -1,7 +1,7 @@ --!strict --[[ - A lightweight, strictly-typed logger class designed with a minimal set of requirements for the StateMachine project, so it is not feature rich. + A lightweight, strictly typed logger class designed with a minimal set of requirements for the StateQ project, so it is not feature rich. This logger class includes a few features such: - A concept of log levels (Debug, Info, Warning, Error): These levels allow for categorizing the importance of the logs. - Methods for logging at these levels: Convenient methods for logging at each level. @@ -34,7 +34,7 @@ error("This is an error thrown from a wrapped function") end) - A primary purpose of this class existing is to be able to check for errors from within tests. The StateMachine queues events, + A primary purpose of this class existing is to be able to check for errors from within tests. The StateQ queues events, starting a new thread to process them, which means errors that occur are not propagated to the main thread and can't be tested for. This logger class allows for the testing of errors by adding a handler for errors, and then checking for those errors in tests. --]] diff --git a/src/StateMachine/Modules/Signal.luau b/src/StateQ/Modules/Signal.luau similarity index 100% rename from src/StateMachine/Modules/Signal.luau rename to src/StateQ/Modules/Signal.luau diff --git a/src/StateMachine/Modules/ThreadQueue.luau b/src/StateQ/Modules/ThreadQueue.luau similarity index 100% rename from src/StateMachine/Modules/ThreadQueue.luau rename to src/StateQ/Modules/ThreadQueue.luau diff --git a/src/StateMachine/init.luau b/src/StateQ/init.luau similarity index 93% rename from src/StateMachine/init.luau rename to src/StateQ/init.luau index 525d21b..c0cb213 100644 --- a/src/StateMachine/init.luau +++ b/src/StateQ/init.luau @@ -3,7 +3,7 @@ --[[ MIT License - Copyright (c) 2023 BusyCityGuy + Copyright (c) 2024 BusyCityGuy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,8 @@ --]] +-- Version: 0.0.4 + --[[ # What's a finite state machine? A Finite State Machine (FSM) provides a way to enforce specific logical flow among a set of States. Given an Event, the FSM responds by looking up the corresponding Transition for that Event in its current State. A Transition is a callback function that is invoked when an Event is given to the FSM, and it returns the next State for the FSM to move to. @@ -71,7 +73,7 @@ SwitchOff = "SwitchOff", } - local light = StateMachine.new(LightState.On, { + local light = StateQ.new(LightState.On, { [Event.SwitchOn] = { canBeFinal = true, from = { @@ -162,11 +164,11 @@ local checkAfterState = t.strict(t.optional(State)) local queueEventAsyncCheck = t.strict(t.tuple(EventName, Event)) local handleCheck = t.strict(EventName) -local StateMachine = {} -StateMachine.Logger = Logger -StateMachine.__index = StateMachine -StateMachine.__tostring = function(_self) - return "StateMachine" +local StateQ = {} +StateQ.Logger = Logger +StateQ.__index = StateQ +StateQ.__tostring = function(_self) + return "StateQ" end export type ClassType = typeof(setmetatable( @@ -186,12 +188,12 @@ export type ClassType = typeof(setmetatable( _logger: Logger.ClassType, _isDestroyed: boolean, }, - StateMachine + StateQ )) local machineNumber = 0 -function StateMachine.new( +function StateQ.new( initialState: State, eventsByName: { [EventName]: Event }, name: string?, @@ -223,14 +225,14 @@ function StateMachine.new( _isDestroyed = false, } - setmetatable(self, StateMachine) + setmetatable(self, StateQ) self:_createEventHandlers(eventsByName) return self end -function StateMachine._createEventHandlers(self: ClassType, eventsByName: { [EventName]: Event }) +function StateQ._createEventHandlers(self: ClassType, eventsByName: { [EventName]: Event }) self:getLogger():wrap(createEventHandlersCheck, eventsByName) for eventName, event in pairs(eventsByName) do @@ -246,7 +248,7 @@ function StateMachine._createEventHandlers(self: ClassType, eventsByName: { [Eve end end -function StateMachine._queueEventAsync(self: ClassType, eventName: EventName, event: Event, ...: any?) +function StateQ._queueEventAsync(self: ClassType, eventName: EventName, event: Event, ...: any?) self:getLogger():wrap(queueEventAsyncCheck, eventName, event) local args = { ... } @@ -305,7 +307,7 @@ function StateMachine._queueEventAsync(self: ClassType, eventName: EventName, ev end -- VarArgs get passed to the transition callbacks -function StateMachine.handle(self: ClassType, eventName: EventName, ...: any?) +function StateQ.handle(self: ClassType, eventName: EventName, ...: any?) self:getLogger():wrap(handleCheck, eventName) self:getLogger() :assert(not self._isDestroyed, `Attempt to handle event {eventName} after the state machine was destroyed`) @@ -317,19 +319,19 @@ function StateMachine.handle(self: ClassType, eventName: EventName, ...: any?) coroutine.wrap(handleEvent :: EventHandler)(...) end -function StateMachine.getLogger(self: ClassType): Logger.ClassType +function StateQ.getLogger(self: ClassType): Logger.ClassType return self._logger end -function StateMachine.getState(self: ClassType) +function StateQ.getState(self: ClassType) return self._currentState end -function StateMachine.getValidEvents(self: ClassType) +function StateQ.getValidEvents(self: ClassType) return self._currentState and self._validEventNamesByState[self._currentState] or {} end -function StateMachine.destroy(self: ClassType) +function StateQ.destroy(self: ClassType) self._isDestroyed = true self.beforeEvent:DisconnectAll() self.leavingState:DisconnectAll() @@ -338,4 +340,4 @@ function StateMachine.destroy(self: ClassType) self.finished:DisconnectAll() end -return StateMachine +return StateQ diff --git a/src/TestService/Source/Tests/StateMachine.spec.luau b/src/TestService/Source/Tests/StateQ.spec.luau similarity index 78% rename from src/TestService/Source/Tests/StateMachine.spec.luau rename to src/TestService/Source/Tests/StateQ.spec.luau index 4c95ac1..e31dbbc 100644 --- a/src/TestService/Source/Tests/StateMachine.spec.luau +++ b/src/TestService/Source/Tests/StateQ.spec.luau @@ -6,9 +6,8 @@ local TestService = game:GetService("TestService") local Freeze = require(TestService.Dependencies.Freeze) local JestGlobals = require(TestService.Dependencies.JestGlobals) -local Logger = require(ReplicatedStorage.Source.StateMachine.Modules.Logger) -local Signal = require(ReplicatedStorage.Source.StateMachine.Modules.Signal) -local StateMachine = require(ReplicatedStorage.Source.StateMachine) +local Logger = require(ReplicatedStorage.Source.StateQ.Modules.Logger) +local StateQ = require(ReplicatedStorage.Source.StateQ) -- Shortening things is generally bad practice, but this greatly improves readability of tests local Dict = Freeze.Dictionary @@ -84,14 +83,14 @@ describe("new", function() local badType = badTypes[i] it(`{i} bad: {typeof(badType)}`, function() expect(function() - StateMachine.new(badType, eventsByName) + StateQ.new(badType, eventsByName) end).toThrow("Bad tuple index #1") end) end it(`good: {typeof(goodType)}`, function() expect(function() - StateMachine.new(goodType, eventsByName) + StateQ.new(goodType, eventsByName) end).never.toThrow() end) end) @@ -122,14 +121,14 @@ describe("new", function() local badType = badTypes[i] it(`{i} bad: {typeof(badType)}`, function() expect(function() - StateMachine.new(X_STATE, badType) + StateQ.new(X_STATE, badType) end).toThrow("Bad tuple index #2") end) end it(`good: {typeof(goodEventsByName)}`, function() expect(function() - StateMachine.new(X_STATE, goodEventsByName) + StateQ.new(X_STATE, goodEventsByName) end).never.toThrow() end) end) @@ -162,7 +161,7 @@ describe("new", function() local badType = badTypes[i] it(`{i} bad: {typeof(badType)}`, function() expect(function() - StateMachine.new(X_STATE, eventsByName, badType) + StateQ.new(X_STATE, eventsByName, badType) end).toThrow("Bad tuple index #3") end) end @@ -171,7 +170,7 @@ describe("new", function() local goodType = goodTypes[i] it(`{i} good: {typeof(goodType)}`, function() expect(function() - StateMachine.new(X_STATE, eventsByName, goodType) + StateQ.new(X_STATE, eventsByName, goodType) end).never.toThrow() end) end @@ -198,17 +197,17 @@ describe("new", function() local goodTypes: { nil | Logger.LogLevel } = { nil, - StateMachine.Logger.LogLevel.Error, - StateMachine.Logger.LogLevel.Warn, - StateMachine.Logger.LogLevel.Info, - StateMachine.Logger.LogLevel.Debug, + StateQ.Logger.LogLevel.Error, + StateQ.Logger.LogLevel.Warn, + StateQ.Logger.LogLevel.Info, + StateQ.Logger.LogLevel.Debug, } for i = 1, #badTypes do local badType = badTypes[i] it(`{i} bad: {typeof(badType)}`, function() expect(function() - StateMachine.new(X_STATE, eventsByName, nil, badType) + StateQ.new(X_STATE, eventsByName, nil, badType) end).toThrow("Bad tuple index #4") end) end @@ -217,7 +216,7 @@ describe("new", function() local goodType: nil | Logger.LogLevel = goodTypes[i] it(`{i} good: {typeof(goodType)}`, function() expect(function() - StateMachine.new(X_STATE, eventsByName, nil, goodType) + StateQ.new(X_STATE, eventsByName, nil, goodType) end).never.toThrow() end) end @@ -237,12 +236,12 @@ describe("new", function() }, } - local stateMachine1 = StateMachine.new(initialState, eventsByName) - local stateMachine2 = StateMachine.new(initialState, eventsByName) + local stateQ1 = StateQ.new(initialState, eventsByName) + local stateQ2 = StateQ.new(initialState, eventsByName) - expect(stateMachine1).toBeInstanceOf(StateMachine) - expect(stateMachine2).toBeInstanceOf(StateMachine) - expect(stateMachine1 == stateMachine2).toBe(false) + expect(stateQ1).toBeInstanceOf(StateQ) + expect(stateQ2).toBeInstanceOf(StateQ) + expect(stateQ1 == stateQ2).toBe(false) end) describe("should initialize", function() @@ -259,8 +258,8 @@ describe("new", function() }, } - local stateMachine = StateMachine.new(initialState, eventsByName) - expect(stateMachine._currentState).toBe(initialState) + local stateQ = StateQ.new(initialState, eventsByName) + expect(stateQ._currentState).toBe(initialState) end) it("valid event names by state", function() @@ -286,9 +285,9 @@ describe("new", function() }, } - local stateMachine = StateMachine.new(X_STATE, eventsByName) - local validEventNamesFromX = stateMachine._validEventNamesByState[X_STATE] - local validEventNamesFromY = stateMachine._validEventNamesByState[Y_STATE] + local stateQ = StateQ.new(X_STATE, eventsByName) + local validEventNamesFromX = stateQ._validEventNamesByState[X_STATE] + local validEventNamesFromY = stateQ._validEventNamesByState[Y_STATE] expect(validEventNamesFromX).toEqual(expect.any("table")) expect(validEventNamesFromY).toEqual(expect.any("table")) @@ -324,8 +323,8 @@ describe("new", function() }, } - local stateMachine = StateMachine.new(X_STATE, eventsByName) - local handlers = stateMachine._handlersByEventName + local stateQ = StateQ.new(X_STATE, eventsByName) + local handlers = stateQ._handlersByEventName expect(Dict.count(handlers)).toBe(2) expect(handlers[TO_X_EVENT]).toEqual(expect.any("function")) @@ -344,14 +343,14 @@ describe("new", function() }, } - local stateMachine = StateMachine.new(X_STATE, eventsByName) + local stateQ = StateQ.new(X_STATE, eventsByName) -- FIXME: Can't use toBeInstanceOf because of some weird behavior with ReducedInstance for running tests in lune - expect(stateMachine[BEFORE_EVENT_SIGNAL]).never.toBeNil() - expect(stateMachine[LEAVING_STATE_SIGNAL]).never.toBeNil() - expect(stateMachine[STATE_ENTERED_SIGNAL]).never.toBeNil() - expect(stateMachine[AFTER_EVENT_SIGNAL]).never.toBeNil() - expect(stateMachine[FINISHED_SIGNAL]).never.toBeNil() + expect(stateQ[BEFORE_EVENT_SIGNAL]).never.toBeNil() + expect(stateQ[LEAVING_STATE_SIGNAL]).never.toBeNil() + expect(stateQ[STATE_ENTERED_SIGNAL]).never.toBeNil() + expect(stateQ[AFTER_EVENT_SIGNAL]).never.toBeNil() + expect(stateQ[FINISHED_SIGNAL]).never.toBeNil() end) end) end) @@ -371,7 +370,7 @@ describe("handle", function() }, } - local stateMachine = StateMachine.new(X_STATE, eventsByName) + local stateQ = StateQ.new(X_STATE, eventsByName) local badTypes: { any } = { 1, @@ -384,16 +383,16 @@ describe("handle", function() for _, badType in badTypes do expect(function() - stateMachine:handle(badType) + stateQ:handle(badType) end).toThrow(`string expected, got {typeof(badType)}`) end expect(function() - stateMachine:handle(nonexistentEventName) + stateQ:handle(nonexistentEventName) end).toThrow(`Invalid event name passed to handle: {nonexistentEventName}`) expect(function() - StateMachine.new(goodType, eventsByName) + StateQ.new(goodType, eventsByName) end).never.toThrow() end) @@ -411,13 +410,13 @@ describe("handle", function() }, } - local stateMachine = StateMachine.new(initialState, eventsByName) + local stateQ = StateQ.new(initialState, eventsByName) local resultSignalOrder: { string } = {} local signalConnections: { Signal.SignalConnection } = {} -- Set up event connections for _, signalName in ORDERED_SIGNALS do - local newSignalConnection = (stateMachine[signalName] :: Signal.ClassType):Connect(function(_, _) + local newSignalConnection = (stateQ[signalName] :: Signal.ClassType):Connect(function(_, _) table.insert(resultSignalOrder, signalName) if #resultSignalOrder == #ORDERED_SIGNALS then @@ -436,7 +435,7 @@ describe("handle", function() table.insert(signalConnections, newSignalConnection) end - stateMachine:handle(FINISH_EVENT) + stateQ:handle(FINISH_EVENT) end, 50) describe(`with the correct parameters and state`, function() @@ -472,79 +471,79 @@ describe("handle", function() }, } - local stateMachine + local stateQ beforeEach(function() receivedParameters = nil - stateMachine = StateMachine.new(initialState, eventsByName) + stateQ = StateQ.new(initialState, eventsByName) end) it(BEFORE_EVENT_SIGNAL, function(_, done) local signalConnection - signalConnection = stateMachine[BEFORE_EVENT_SIGNAL]:Connect(function(...) + signalConnection = stateQ[BEFORE_EVENT_SIGNAL]:Connect(function(...) signalConnection:Disconnect() receivedParameters = { ... } xpcall(function() expect(#receivedParameters).toBe(2) expect(receivedParameters[1]).toBe(handledEventName) expect(receivedParameters[2]).toBe(initialState) - expect(stateMachine._currentState).toBe(initialState) + expect(stateQ._currentState).toBe(initialState) done() end, function(err) done(err) end) end) - stateMachine:handle(handledEventName, table.unpack(variadicArgs)) + stateQ:handle(handledEventName, table.unpack(variadicArgs)) end, timeout) it(LEAVING_STATE_SIGNAL, function(_, done) local expectedAfterState = Y_STATE local signalConnection - signalConnection = stateMachine[LEAVING_STATE_SIGNAL]:Connect(function(...) + signalConnection = stateQ[LEAVING_STATE_SIGNAL]:Connect(function(...) signalConnection:Disconnect() receivedParameters = { ... } xpcall(function() expect(#receivedParameters).toBe(2) expect(receivedParameters[1]).toBe(initialState) expect(receivedParameters[2]).toBe(expectedAfterState) - expect(stateMachine._currentState).toBe(initialState) + expect(stateQ._currentState).toBe(initialState) done() end, function(err) done(err) end) end) - stateMachine:handle(handledEventName, table.unpack(variadicArgs)) + stateQ:handle(handledEventName, table.unpack(variadicArgs)) end, timeout) it(STATE_ENTERED_SIGNAL, function(_, done) local expectedAfterState = Y_STATE local signalConnection - signalConnection = stateMachine[STATE_ENTERED_SIGNAL]:Connect(function(...) + signalConnection = stateQ[STATE_ENTERED_SIGNAL]:Connect(function(...) signalConnection:Disconnect() receivedParameters = { ... } xpcall(function() expect(#receivedParameters).toBe(2) expect(receivedParameters[1]).toBe(expectedAfterState) expect(receivedParameters[2]).toBe(initialState) - expect(stateMachine._currentState).toBe(expectedAfterState) + expect(stateQ._currentState).toBe(expectedAfterState) done() end, function(err) done(err) end) end) - stateMachine:handle(handledEventName, table.unpack(variadicArgs)) + stateQ:handle(handledEventName, table.unpack(variadicArgs)) end, timeout) it(AFTER_EVENT_SIGNAL, function(_, done) local expectedAfterState = Y_STATE local signalConnection - signalConnection = stateMachine[AFTER_EVENT_SIGNAL]:Connect(function(...) + signalConnection = stateQ[AFTER_EVENT_SIGNAL]:Connect(function(...) signalConnection:Disconnect() receivedParameters = { ... } xpcall(function() @@ -552,32 +551,32 @@ describe("handle", function() expect(receivedParameters[1]).toBe(handledEventName) expect(receivedParameters[2]).toBe(expectedAfterState) expect(receivedParameters[3]).toBe(initialState) - expect(stateMachine._currentState).toBe(expectedAfterState) + expect(stateQ._currentState).toBe(expectedAfterState) done() end, function(err) done(err) end) end) - stateMachine:handle(handledEventName, table.unpack(variadicArgs)) + stateQ:handle(handledEventName, table.unpack(variadicArgs)) end, timeout) it(FINISHED_SIGNAL, function(_, done) local signalConnection - signalConnection = stateMachine[FINISHED_SIGNAL]:Connect(function(...) + signalConnection = stateQ[FINISHED_SIGNAL]:Connect(function(...) signalConnection:Disconnect() receivedParameters = { ... } xpcall(function() expect(#receivedParameters).toBe(1) expect(receivedParameters[1]).toBe(initialState) - expect(stateMachine._currentState).toBe(FINISH_STATE) + expect(stateQ._currentState).toBe(FINISH_STATE) done() end, function(err) done(err) end) end) - stateMachine:handle(FINISH_EVENT, table.unpack(variadicArgs)) + stateQ:handle(FINISH_EVENT, table.unpack(variadicArgs)) end, timeout) end) end) @@ -607,42 +606,42 @@ describe("handle", function() }, } - local stateMachine = StateMachine.new(initialState, eventsByName) + local stateQ = StateQ.new(initialState, eventsByName) local signalConnections = {} - stateMachine:handle(FINISH_EVENT) + stateQ:handle(FINISH_EVENT) table.insert( signalConnections, - stateMachine[BEFORE_EVENT_SIGNAL]:Connect(function() + stateQ[BEFORE_EVENT_SIGNAL]:Connect(function() table.insert(firedSignals, BEFORE_EVENT_SIGNAL) end) ) table.insert( signalConnections, - stateMachine[LEAVING_STATE_SIGNAL]:Connect(function() + stateQ[LEAVING_STATE_SIGNAL]:Connect(function() table.insert(firedSignals, LEAVING_STATE_SIGNAL) end) ) table.insert( signalConnections, - stateMachine[STATE_ENTERED_SIGNAL]:Connect(function() + stateQ[STATE_ENTERED_SIGNAL]:Connect(function() table.insert(firedSignals, STATE_ENTERED_SIGNAL) end) ) table.insert( signalConnections, - stateMachine[AFTER_EVENT_SIGNAL]:Connect(function() + stateQ[AFTER_EVENT_SIGNAL]:Connect(function() table.insert(firedSignals, AFTER_EVENT_SIGNAL) end) ) table.insert( signalConnections, - stateMachine[FINISHED_SIGNAL]:Connect(function() + stateQ[FINISHED_SIGNAL]:Connect(function() table.insert(firedSignals, FINISHED_SIGNAL) end) ) @@ -688,7 +687,7 @@ describe("handle", function() local handledEventName = FINISH_EVENT -- local expectedAfterState = FINISH_STATE local receivedParameters - local stateMachine + local stateQ local eventsByName = { [FINISH_EVENT] = { canBeFinal = true, @@ -710,14 +709,14 @@ describe("handle", function() }, } - stateMachine = StateMachine.new(initialState, eventsByName) + stateQ = StateQ.new(initialState, eventsByName) -- Test beforeAsync timeoutThread = task.delay(timeout, function() coroutine.resume(mainThread, `timeout waiting {timeout} seconds for beforeAsync invocation`) end) - stateMachine:handle(handledEventName, table.unpack(variadicArgs)) + stateQ:handle(handledEventName, table.unpack(variadicArgs)) local invokedCallback = coroutine.yield(mainThread) expect(invokedCallback).toBe("beforeAsync") @@ -725,7 +724,7 @@ describe("handle", function() expect(receivedParameters[index]).toBe(variadicArg) end expect(#receivedParameters).toBe(#variadicArgs) - expect(stateMachine._currentState).toBe(initialState) + expect(stateQ._currentState).toBe(initialState) -- Test afterAsync timeoutThread = task.delay(timeout, function() @@ -738,7 +737,7 @@ describe("handle", function() -- expect(receivedParameters[index]).toBe(variadicArg) -- end -- expect(#receivedParameters).toBe(#variadicArgs) - -- expect(stateMachine._currentState).toBe(expectedAfterState) + -- expect(stateQ._currentState).toBe(expectedAfterState) end) end) @@ -791,18 +790,18 @@ describe("handle", function() }, } - local stateMachine = StateMachine.new(initialState, eventsByName) + local stateQ = StateQ.new(initialState, eventsByName) -- Queue events for _, handledEventName in ipairs(orderedHandledEvents) do - stateMachine:handle(handledEventName) + stateQ:handle(handledEventName) end local timeoutThread = task.delay(timeout, function() coroutine.resume(mainThread, `timeout waiting {timeout} seconds for finished signal`) end) - local signalConnection = stateMachine[FINISHED_SIGNAL]:Connect(function() + local signalConnection = stateQ[FINISHED_SIGNAL]:Connect(function() task.cancel(timeoutThread) coroutine.resume(mainThread, FINISHED_SIGNAL) end) @@ -828,9 +827,9 @@ describe("handle", function() }, } - local stateMachine = StateMachine.new(X_STATE, eventsByName) + local stateQ = StateQ.new(X_STATE, eventsByName) local mainThread = coroutine.running() - local logger = stateMachine:getLogger() + local logger = stateQ:getLogger() local timeout = 0.5 local timeoutMessage = `timeout waiting {timeout} seconds for finished or error message` @@ -838,9 +837,9 @@ describe("handle", function() coroutine.resume(mainThread, timeoutMessage) end) - stateMachine:handle(FINISH_EVENT) - stateMachine.finished:Wait() - expect(stateMachine._currentState).toBe(FINISH_STATE) + stateQ:handle(FINISH_EVENT) + stateQ.finished:Wait() + expect(stateQ._currentState).toBe(FINISH_STATE) logger:addHandler(logger.LogLevel.Error, function(level: Logger.LogLevel, _name: string, message: string) if level ~= logger.LogLevel.Error then @@ -856,7 +855,7 @@ describe("handle", function() return logger.HandlerResult.Sink end) - stateMachine:handle(FINISH_EVENT) + stateQ:handle(FINISH_EVENT) local errorMessage = coroutine.yield() expect(errorMessage == timeoutMessage).never.toBe(true) expect(errorMessage).toEqual( @@ -880,15 +879,15 @@ end) -- }, -- } --- local stateMachine = StateMachine.new(initialState, eventsByName) +-- local stateQ = StateQ.new(initialState, eventsByName) -- -- Test getting the current state --- local state = stateMachine:getState() +-- local state = stateQ:getState() -- expect(state).toBe(initialState) -- -- Test getting the state after a transition --- stateMachine:handle("toB") --- state = stateMachine:getState() +-- stateQ:handle("toB") +-- state = stateQ:getState() -- expect(state).toBe("B") -- end) -- end) @@ -916,16 +915,16 @@ end) -- }, -- } --- local stateMachine = StateMachine.new(initialState, eventsByName) +-- local stateQ = StateQ.new(initialState, eventsByName) -- -- Test getting valid events for the initial state --- local validEvents = stateMachine:getValidEvents() +-- local validEvents = stateQ:getValidEvents() -- expect(#validEvents).toBe(1) -- expect(validEvents[1]).toBe("toB") -- -- Test getting valid events after a transition --- stateMachine:handle("toB") --- validEvents = stateMachine:getValidEvents() +-- stateQ:handle("toB") +-- validEvents = stateQ:getValidEvents() -- expect(#validEvents).toBe(1) -- expect(validEvents[1]).toBe("toA") -- end) @@ -945,8 +944,8 @@ end) -- }, -- } --- local stateMachine = StateMachine.new(X_STATE, eventsByName) --- expect(stateMachine._isDebugEnabled).toBe(false) +-- local stateQ = StateQ.new(X_STATE, eventsByName) +-- expect(stateQ._isDebugEnabled).toBe(false) -- end) -- describe("setter", function() @@ -962,7 +961,7 @@ end) -- }, -- } --- local stateMachine = StateMachine.new(X_STATE, eventsByName) +-- local stateQ = StateQ.new(X_STATE, eventsByName) -- local badTypes = { -- 1, @@ -973,7 +972,7 @@ end) -- for _, badType in badTypes do -- expect(function() --- stateMachine:setDebugEnabled(badType) +-- stateQ:setDebugEnabled(badType) -- end).toThrow(`boolean expected, got {typeof(badType)}`) -- end -- end) @@ -990,13 +989,13 @@ end) -- }, -- } --- local stateMachine = StateMachine.new(X_STATE, eventsByName) +-- local stateQ = StateQ.new(X_STATE, eventsByName) --- stateMachine:setDebugEnabled(true) --- expect(stateMachine._isDebugEnabled).toBe(true) +-- stateQ:setDebugEnabled(true) +-- expect(stateQ._isDebugEnabled).toBe(true) --- stateMachine:setDebugEnabled(false) --- expect(stateMachine._isDebugEnabled).toBe(false) +-- stateQ:setDebugEnabled(false) +-- expect(stateQ._isDebugEnabled).toBe(false) -- end) -- end) -- end) @@ -1016,21 +1015,21 @@ end) -- }, -- } --- local stateMachine = StateMachine.new(initialState, eventsByName) +-- local stateQ = StateQ.new(initialState, eventsByName) -- -- Test destroying the state machine --- stateMachine:destroy() --- expect(stateMachine._isDestroyed).toBe(true) --- expect(stateMachine[BEFORE_EVENT_SIGNAL]:getConnectionCount()).toBe(0) --- expect(stateMachine[LEAVING_STATE_SIGNAL]:getConnectionCount()).toBe(0) --- expect(stateMachine[STATE_ENTERED_SIGNAL]:getConnectionCount()).toBe(0) --- expect(stateMachine[AFTER_EVENT_SIGNAL]:getConnectionCount()).toBe(0) --- expect(stateMachine[FINISHED_SIGNAL]:getConnectionCount()).toBe(0) +-- stateQ:destroy() +-- expect(stateQ._isDestroyed).toBe(true) +-- expect(stateQ[BEFORE_EVENT_SIGNAL]:getConnectionCount()).toBe(0) +-- expect(stateQ[LEAVING_STATE_SIGNAL]:getConnectionCount()).toBe(0) +-- expect(stateQ[STATE_ENTERED_SIGNAL]:getConnectionCount()).toBe(0) +-- expect(stateQ[AFTER_EVENT_SIGNAL]:getConnectionCount()).toBe(0) +-- expect(stateQ[FINISHED_SIGNAL]:getConnectionCount()).toBe(0) -- end) -- end) -- return function() --- local StateMachine = require(script.Parent.Parent.StateMachine) +-- local StateQ = require(script.Parent.Parent.StateQ) -- local function createTestMachine() -- local states = { @@ -1086,26 +1085,26 @@ end) -- }, -- } --- local machine = StateMachine.new("A", states) +-- local machine = StateQ.new("A", states) -- machine:setDebugEnabled(true) -- return machine -- end -- describe("new", function() --- it("should create a new StateMachine", function() +-- it("should create a new StateQ", function() -- local machine = createTestMachine() -- expect(machine).never.toBeNil() -- end) -- it("should require an initial state", function() -- expect(function() --- StateMachine.new() +-- StateQ.new() -- end).toThrow() -- end) -- it("should require events", function() -- expect(function() --- StateMachine.new("A") +-- StateQ.new("A") -- end).toThrow() -- end) -- end) diff --git a/test.project.json b/test.project.json index 2133a43..b36d0d1 100644 --- a/test.project.json +++ b/test.project.json @@ -1,33 +1,33 @@ { - "emitLegacyScripts": false, - "name": "StateMachine-Test", - "tree": { - "$className": "DataModel", - "ReplicatedStorage": { - "$className": "ReplicatedStorage", - "Source": { - "$className": "Folder", - "StateMachine": { - "$path": "src/StateMachine", - "Dependencies": { - "$path": "Packages" - } - } - } - }, - "TestService": { - "$className": "TestService", - "$properties": { - "ExecuteWithStudioRun": true - }, - "Source": { - "$className": "Folder", - "$path": "src/TestService/Source" - }, - "Dependencies": { - "$className": "Folder", - "$path": "DevPackages" - } - } - } -} \ No newline at end of file + "emitLegacyScripts": false, + "name": "stateq-test", + "tree": { + "$className": "DataModel", + "ReplicatedStorage": { + "$className": "ReplicatedStorage", + "Source": { + "$className": "Folder", + "StateQ": { + "$path": "src/StateQ", + "Dependencies": { + "$path": "Packages" + } + } + } + }, + "TestService": { + "$className": "TestService", + "$properties": { + "ExecuteWithStudioRun": true + }, + "Source": { + "$className": "Folder", + "$path": "src/TestService/Source" + }, + "Dependencies": { + "$className": "Folder", + "$path": "DevPackages" + } + } + } +} diff --git a/wally.lock b/wally.lock index 4e8db64..4f618ab 100644 --- a/wally.lock +++ b/wally.lock @@ -3,9 +3,9 @@ registry = "test" [[package]] -name = "busycityguy/finite-state-machine-luau" -version = "0.1.0" -dependencies = [["t", "osyrisrblx/t@3.0.0"], ["Freeze", "duckarmor/freeze@0.1.4"], ["Jest", "jsdotlua/jest@3.6.1-rc.2"], ["JestGlobals", "jsdotlua/jest-globals@3.6.1-rc.2"]] +name = "busycityguy/stateq" +version = "0.0.0" +dependencies = [["t", "osyrisrblx/t@3.1.1"], ["Freeze", "duckarmor/freeze@0.1.4"], ["Jest", "jsdotlua/jest@3.6.1-rc.2"], ["JestGlobals", "jsdotlua/jest-globals@3.6.1-rc.2"]] [[package]] name = "duckarmor/freeze" @@ -14,8 +14,8 @@ dependencies = [["TestEZ", "roblox/testez@0.4.1"]] [[package]] name = "jsdotlua/boolean" -version = "1.2.6" -dependencies = [["number", "jsdotlua/number@1.2.6"]] +version = "1.2.7" +dependencies = [["number", "jsdotlua/number@1.2.7"]] [[package]] name = "jsdotlua/chalk" @@ -24,37 +24,37 @@ dependencies = [] [[package]] name = "jsdotlua/collections" -version = "1.2.6" -dependencies = [["es7-types", "jsdotlua/es7-types@1.2.6"], ["instance-of", "jsdotlua/instance-of@1.2.6"]] +version = "1.2.7" +dependencies = [["es7-types", "jsdotlua/es7-types@1.2.7"], ["instance-of", "jsdotlua/instance-of@1.2.7"]] [[package]] name = "jsdotlua/console" -version = "1.2.6" -dependencies = [["collections", "jsdotlua/collections@1.2.6"]] +version = "1.2.7" +dependencies = [["collections", "jsdotlua/collections@1.2.7"]] [[package]] name = "jsdotlua/diff-sequences" version = "3.6.1-rc.2" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"]] +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"]] [[package]] name = "jsdotlua/emittery" version = "3.6.1-rc.2" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["promise", "jsdotlua/promise@3.5.2"]] +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["promise", "jsdotlua/promise@3.5.2"]] [[package]] name = "jsdotlua/es7-types" -version = "1.2.6" +version = "1.2.7" dependencies = [] [[package]] name = "jsdotlua/expect" version = "3.6.1-rc.2" -dependencies = [["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-matcher-utils", "jsdotlua/jest-matcher-utils@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-snapshot", "jsdotlua/jest-snapshot@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["promise", "jsdotlua/promise@3.5.2"]] +dependencies = [["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-matcher-utils", "jsdotlua/jest-matcher-utils@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-snapshot", "jsdotlua/jest-snapshot@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["promise", "jsdotlua/promise@3.5.2"]] [[package]] name = "jsdotlua/instance-of" -version = "1.2.6" +version = "1.2.7" dependencies = [] [[package]] @@ -65,122 +65,122 @@ dependencies = [["jest-core", "jsdotlua/jest-core@3.6.1-rc.2"]] [[package]] name = "jsdotlua/jest-circus" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["expect", "jsdotlua/expect@3.6.1-rc.2"], ["jest-each", "jsdotlua/jest-each@3.6.1-rc.2"], ["jest-environment", "jsdotlua/jest-environment@3.6.1-rc.2"], ["jest-matcher-utils", "jsdotlua/jest-matcher-utils@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-runtime", "jsdotlua/jest-runtime@3.6.1-rc.2"], ["jest-snapshot", "jsdotlua/jest-snapshot@3.6.1-rc.2"], ["jest-test-result", "jsdotlua/jest-test-result@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"], ["promise", "jsdotlua/promise@3.5.2"], ["throat", "jsdotlua/throat@3.6.1-rc.2"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["expect", "jsdotlua/expect@3.6.1-rc.2"], ["jest-each", "jsdotlua/jest-each@3.6.1-rc.2"], ["jest-environment", "jsdotlua/jest-environment@3.6.1-rc.2"], ["jest-matcher-utils", "jsdotlua/jest-matcher-utils@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-runtime", "jsdotlua/jest-runtime@3.6.1-rc.2"], ["jest-snapshot", "jsdotlua/jest-snapshot@3.6.1-rc.2"], ["jest-test-result", "jsdotlua/jest-test-result@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"], ["promise", "jsdotlua/promise@3.5.2"], ["throat", "jsdotlua/throat@3.6.1-rc.2"]] [[package]] name = "jsdotlua/jest-config" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-each", "jsdotlua/jest-each@3.6.1-rc.2"], ["jest-environment-roblox", "jsdotlua/jest-environment-roblox@3.6.1-rc.2"], ["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["jest-validate", "jsdotlua/jest-validate@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["promise", "jsdotlua/promise@3.5.2"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-each", "jsdotlua/jest-each@3.6.1-rc.2"], ["jest-environment-roblox", "jsdotlua/jest-environment-roblox@3.6.1-rc.2"], ["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["jest-validate", "jsdotlua/jest-validate@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["promise", "jsdotlua/promise@3.5.2"]] [[package]] name = "jsdotlua/jest-console" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-each", "jsdotlua/jest-each@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-each", "jsdotlua/jest-each@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"]] [[package]] name = "jsdotlua/jest-core" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["emittery", "jsdotlua/emittery@3.6.1-rc.2"], ["jest-config", "jsdotlua/jest-config@3.6.1-rc.2"], ["jest-console", "jsdotlua/jest-console@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-reporters", "jsdotlua/jest-reporters@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-runner", "jsdotlua/jest-runner@3.6.1-rc.2"], ["jest-runtime", "jsdotlua/jest-runtime@3.6.1-rc.2"], ["jest-snapshot", "jsdotlua/jest-snapshot@3.6.1-rc.2"], ["jest-test-result", "jsdotlua/jest-test-result@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"], ["promise", "jsdotlua/promise@3.5.2"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["emittery", "jsdotlua/emittery@3.6.1-rc.2"], ["jest-config", "jsdotlua/jest-config@3.6.1-rc.2"], ["jest-console", "jsdotlua/jest-console@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-reporters", "jsdotlua/jest-reporters@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-runner", "jsdotlua/jest-runner@3.6.1-rc.2"], ["jest-runtime", "jsdotlua/jest-runtime@3.6.1-rc.2"], ["jest-snapshot", "jsdotlua/jest-snapshot@3.6.1-rc.2"], ["jest-test-result", "jsdotlua/jest-test-result@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"], ["promise", "jsdotlua/promise@3.5.2"]] [[package]] name = "jsdotlua/jest-diff" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["diff-sequences", "jsdotlua/diff-sequences@3.6.1-rc.2"], ["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["diff-sequences", "jsdotlua/diff-sequences@3.6.1-rc.2"], ["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"]] [[package]] name = "jsdotlua/jest-each" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"]] [[package]] name = "jsdotlua/jest-environment" version = "3.6.1-rc.2" -dependencies = [["jest-fake-timers", "jsdotlua/jest-fake-timers@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"]] +dependencies = [["jest-fake-timers", "jsdotlua/jest-fake-timers@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"]] [[package]] name = "jsdotlua/jest-environment-roblox" version = "3.6.1-rc.2" -dependencies = [["jest-environment", "jsdotlua/jest-environment@3.6.1-rc.2"], ["jest-fake-timers", "jsdotlua/jest-fake-timers@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["promise", "jsdotlua/promise@3.5.2"]] +dependencies = [["jest-environment", "jsdotlua/jest-environment@3.6.1-rc.2"], ["jest-fake-timers", "jsdotlua/jest-fake-timers@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["promise", "jsdotlua/promise@3.5.2"]] [[package]] name = "jsdotlua/jest-fake-timers" version = "3.6.1-rc.2" -dependencies = [["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"]] +dependencies = [["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"]] [[package]] name = "jsdotlua/jest-get-type" version = "3.6.1-rc.2" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"]] +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"]] [[package]] name = "jsdotlua/jest-globals" version = "3.6.1-rc.2" -dependencies = [["expect", "jsdotlua/expect@3.6.1-rc.2"], ["jest-environment", "jsdotlua/jest-environment@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"]] +dependencies = [["expect", "jsdotlua/expect@3.6.1-rc.2"], ["jest-environment", "jsdotlua/jest-environment@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"]] [[package]] name = "jsdotlua/jest-matcher-utils" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-diff", "jsdotlua/jest-diff@3.6.1-rc.2"], ["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-diff", "jsdotlua/jest-diff@3.6.1-rc.2"], ["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"]] [[package]] name = "jsdotlua/jest-message-util" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"]] [[package]] name = "jsdotlua/jest-mock" version = "3.6.1-rc.2" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"]] +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"]] [[package]] name = "jsdotlua/jest-reporters" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-console", "jsdotlua/jest-console@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-test-result", "jsdotlua/jest-test-result@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["path", "jsdotlua/path@3.6.1-rc.2"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-console", "jsdotlua/jest-console@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-test-result", "jsdotlua/jest-test-result@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["path", "jsdotlua/path@3.6.1-rc.2"]] [[package]] name = "jsdotlua/jest-roblox-shared" version = "3.6.1-rc.2" -dependencies = [["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"]] +dependencies = [["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"]] [[package]] name = "jsdotlua/jest-runner" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["emittery", "jsdotlua/emittery@3.6.1-rc.2"], ["jest-circus", "jsdotlua/jest-circus@3.6.1-rc.2"], ["jest-console", "jsdotlua/jest-console@3.6.1-rc.2"], ["jest-environment", "jsdotlua/jest-environment@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-runtime", "jsdotlua/jest-runtime@3.6.1-rc.2"], ["jest-test-result", "jsdotlua/jest-test-result@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"], ["promise", "jsdotlua/promise@3.5.2"], ["throat", "jsdotlua/throat@3.6.1-rc.2"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["emittery", "jsdotlua/emittery@3.6.1-rc.2"], ["jest-circus", "jsdotlua/jest-circus@3.6.1-rc.2"], ["jest-console", "jsdotlua/jest-console@3.6.1-rc.2"], ["jest-environment", "jsdotlua/jest-environment@3.6.1-rc.2"], ["jest-message-util", "jsdotlua/jest-message-util@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-runtime", "jsdotlua/jest-runtime@3.6.1-rc.2"], ["jest-test-result", "jsdotlua/jest-test-result@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["jest-util", "jsdotlua/jest-util@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"], ["promise", "jsdotlua/promise@3.5.2"], ["throat", "jsdotlua/throat@3.6.1-rc.2"]] [[package]] name = "jsdotlua/jest-runtime" version = "3.6.1-rc.2" -dependencies = [["emittery", "jsdotlua/emittery@3.6.1-rc.2"], ["expect", "jsdotlua/expect@3.6.1-rc.2"], ["jest-fake-timers", "jsdotlua/jest-fake-timers@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["jest-snapshot", "jsdotlua/jest-snapshot@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["promise", "jsdotlua/promise@3.5.2"]] +dependencies = [["emittery", "jsdotlua/emittery@3.6.1-rc.2"], ["expect", "jsdotlua/expect@3.6.1-rc.2"], ["jest-fake-timers", "jsdotlua/jest-fake-timers@3.6.1-rc.2"], ["jest-mock", "jsdotlua/jest-mock@3.6.1-rc.2"], ["jest-snapshot", "jsdotlua/jest-snapshot@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["promise", "jsdotlua/promise@3.5.2"]] [[package]] name = "jsdotlua/jest-snapshot" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-diff", "jsdotlua/jest-diff@3.6.1-rc.2"], ["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-matcher-utils", "jsdotlua/jest-matcher-utils@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"], ["promise", "jsdotlua/promise@3.5.2"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-diff", "jsdotlua/jest-diff@3.6.1-rc.2"], ["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-matcher-utils", "jsdotlua/jest-matcher-utils@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["pretty-format", "jsdotlua/pretty-format@3.6.1-rc.2"], ["promise", "jsdotlua/promise@3.5.2"]] [[package]] name = "jsdotlua/jest-test-result" version = "3.6.1-rc.2" -dependencies = [["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"]] +dependencies = [["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"]] [[package]] name = "jsdotlua/jest-types" version = "3.6.1-rc.2" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"]] +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"]] [[package]] name = "jsdotlua/jest-util" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["picomatch", "jsdotlua/picomatch@0.4.0"], ["promise", "jsdotlua/promise@3.5.2"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["jest-types", "jsdotlua/jest-types@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["picomatch", "jsdotlua/picomatch@0.4.0"], ["promise", "jsdotlua/promise@3.5.2"]] [[package]] name = "jsdotlua/jest-validate" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"]] [[package]] name = "jsdotlua/luau-polyfill" -version = "1.2.6" -dependencies = [["boolean", "jsdotlua/boolean@1.2.6"], ["collections", "jsdotlua/collections@1.2.6"], ["console", "jsdotlua/console@1.2.6"], ["es7-types", "jsdotlua/es7-types@1.2.6"], ["instance-of", "jsdotlua/instance-of@1.2.6"], ["math", "jsdotlua/math@1.2.6"], ["number", "jsdotlua/number@1.2.6"], ["string", "jsdotlua/string@1.2.6"], ["symbol-luau", "jsdotlua/symbol-luau@1.0.1"], ["timers", "jsdotlua/timers@1.2.6"]] +version = "1.2.7" +dependencies = [["boolean", "jsdotlua/boolean@1.2.7"], ["collections", "jsdotlua/collections@1.2.7"], ["console", "jsdotlua/console@1.2.7"], ["es7-types", "jsdotlua/es7-types@1.2.7"], ["instance-of", "jsdotlua/instance-of@1.2.7"], ["math", "jsdotlua/math@1.2.7"], ["number", "jsdotlua/number@1.2.7"], ["string", "jsdotlua/string@1.2.7"], ["symbol-luau", "jsdotlua/symbol-luau@1.0.1"], ["timers", "jsdotlua/timers@1.2.7"]] [[package]] name = "jsdotlua/luau-regexp" @@ -189,28 +189,28 @@ dependencies = [] [[package]] name = "jsdotlua/math" -version = "1.2.6" +version = "1.2.7" dependencies = [] [[package]] name = "jsdotlua/number" -version = "1.2.6" +version = "1.2.7" dependencies = [] [[package]] name = "jsdotlua/path" version = "3.6.1-rc.2" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"]] +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"]] [[package]] name = "jsdotlua/picomatch" version = "0.4.0" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["promise", "jsdotlua/promise@3.5.2"]] +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["promise", "jsdotlua/promise@3.5.2"]] [[package]] name = "jsdotlua/pretty-format" version = "3.6.1-rc.2" -dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["react-is", "jsdotlua/react-is@17.1.0"]] +dependencies = [["chalk", "jsdotlua/chalk@0.2.1"], ["jest-get-type", "jsdotlua/jest-get-type@3.6.1-rc.2"], ["jest-roblox-shared", "jsdotlua/jest-roblox-shared@3.6.1-rc.2"], ["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["luau-regexp", "jsdotlua/luau-regexp@0.2.1"], ["react-is", "jsdotlua/react-is@17.1.0"]] [[package]] name = "jsdotlua/promise" @@ -225,12 +225,12 @@ dependencies = [["shared", "jsdotlua/shared@17.1.0"]] [[package]] name = "jsdotlua/shared" version = "17.1.0" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"]] +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"]] [[package]] name = "jsdotlua/string" -version = "1.2.6" -dependencies = [["es7-types", "jsdotlua/es7-types@1.2.6"], ["number", "jsdotlua/number@1.2.6"]] +version = "1.2.7" +dependencies = [["es7-types", "jsdotlua/es7-types@1.2.7"], ["number", "jsdotlua/number@1.2.7"]] [[package]] name = "jsdotlua/symbol-luau" @@ -240,16 +240,16 @@ dependencies = [] [[package]] name = "jsdotlua/throat" version = "3.6.1-rc.2" -dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.6"], ["promise", "jsdotlua/promise@3.5.2"]] +dependencies = [["luau-polyfill", "jsdotlua/luau-polyfill@1.2.7"], ["promise", "jsdotlua/promise@3.5.2"]] [[package]] name = "jsdotlua/timers" -version = "1.2.6" -dependencies = [["collections", "jsdotlua/collections@1.2.6"]] +version = "1.2.7" +dependencies = [["collections", "jsdotlua/collections@1.2.7"]] [[package]] name = "osyrisrblx/t" -version = "3.0.0" +version = "3.1.1" dependencies = [] [[package]] diff --git a/wally.toml b/wally.toml index 546de84..11711a0 100644 --- a/wally.toml +++ b/wally.toml @@ -1,11 +1,20 @@ [package] -name = "busycityguy/finite-state-machine-luau" -description = "A feature rich and fully typed implementation of a Finite State Machine in Luau, developed for use in Roblox experiences" -version = "0.1.0" +name = "busycityguy/stateq" +description = "An intuitive fully-typed Finite State Machine in Luau that supports async transitions by queueing events" +version = "0.0.4" license = "MIT" authors = ["BusyCityGuy"] realm = "shared" registry = "https://github.com/UpliftGames/wally-index" +exclude = ["*"] +include = [ + "src/StateQ", + "src/StateQ/**", + "default.project.json", + "wally.toml", + "README.md", + "LICENSE.md", +] [dependencies] t = "osyrisrblx/t@3.0.0"