@gesslar/muddy 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -0
- package/UNLICENSE.txt +24 -0
- package/package.json +69 -0
- package/src/Muddy.js +738 -0
- package/src/Type.js +113 -0
- package/src/Watch.js +139 -0
- package/src/cli.js +88 -0
- package/src/modules/Action.js +158 -0
- package/src/modules/Alias.js +45 -0
- package/src/modules/Key.js +61 -0
- package/src/modules/Mfile.js +16 -0
- package/src/modules/MudletModule.js +188 -0
- package/src/modules/Script.js +59 -0
- package/src/modules/Timer.js +76 -0
- package/src/modules/Trigger.js +259 -0
- package/src/modules/Variable.js +82 -0
package/src/Type.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import {URL} from "node:url"
|
|
2
|
+
import {Collection, Util} from "@gesslar/toolkit"
|
|
3
|
+
|
|
4
|
+
// Aliases
|
|
5
|
+
const {capitalize} = Util
|
|
6
|
+
const {allocateObject} = Collection
|
|
7
|
+
const {freeze} = Object
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Type constants and mappings for Mudlet module types.
|
|
11
|
+
*
|
|
12
|
+
* Provides mappings between singular/plural forms, class constructors,
|
|
13
|
+
* file names, URLs, and XML package tag names for all module types.
|
|
14
|
+
*/
|
|
15
|
+
const Type = {}
|
|
16
|
+
|
|
17
|
+
// Base
|
|
18
|
+
const single = () => freeze(new Array("alias", "key", "script", "timer", "trigger"))
|
|
19
|
+
const plural = () => freeze(new Array("aliases", "keys", "scripts", "timers", "triggers"))
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Array of singular module type names.
|
|
23
|
+
*
|
|
24
|
+
* @type {Array<string>}
|
|
25
|
+
*/
|
|
26
|
+
Type.SINGLE = single()
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Array of plural module type names.
|
|
30
|
+
*
|
|
31
|
+
* @type {Array<string>}
|
|
32
|
+
*/
|
|
33
|
+
Type.PLURAL = plural()
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Mapping from singular to plural module type names.
|
|
37
|
+
*
|
|
38
|
+
* @type {Readonly<Record<string, string>>}
|
|
39
|
+
*/
|
|
40
|
+
Type.TO_PLURAL = freeze(await allocateObject(single(), plural()))
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Mapping from plural to singular module type names.
|
|
44
|
+
*
|
|
45
|
+
* @type {Readonly<Record<string, string>>}
|
|
46
|
+
*/
|
|
47
|
+
Type.TO_SINGLE = freeze(await allocateObject(plural(), single()))
|
|
48
|
+
|
|
49
|
+
const classify = async e => (await import(`./modules/${capitalize(e)}.js`)).default
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Mapping from plural module type names to their class constructors.
|
|
53
|
+
*
|
|
54
|
+
* @type {Readonly<Record<string, Function>>}
|
|
55
|
+
*/
|
|
56
|
+
Type.CLASS = Object.freeze(await allocateObject(
|
|
57
|
+
plural(),
|
|
58
|
+
await Promise.all(single().map(classify))
|
|
59
|
+
))
|
|
60
|
+
|
|
61
|
+
const upper = e => e.toUpperCase()
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Mapping from uppercase type names to plural module type names.
|
|
65
|
+
*
|
|
66
|
+
* @type {Readonly<Record<string, string>>}
|
|
67
|
+
*/
|
|
68
|
+
Type.TYPES = Object.freeze(await allocateObject(
|
|
69
|
+
single().map(upper),
|
|
70
|
+
plural()
|
|
71
|
+
))
|
|
72
|
+
|
|
73
|
+
const file = e => `${e}.json`
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Mapping from plural module type names to their JSON file names.
|
|
77
|
+
*
|
|
78
|
+
* @type {Readonly<Record<string, string>>}
|
|
79
|
+
*/
|
|
80
|
+
Type.FILES = Object.freeze(await allocateObject(
|
|
81
|
+
plural(),
|
|
82
|
+
plural().map(file)
|
|
83
|
+
))
|
|
84
|
+
|
|
85
|
+
const baseUrl = "https://schema.gesslar.dev/muddler/v1/"
|
|
86
|
+
const url = e => new URL(`${e}.json`, baseUrl)
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Mapping from type names to their schema URLs.
|
|
90
|
+
*
|
|
91
|
+
* @type {Readonly<Record<string, URL>>}
|
|
92
|
+
*/
|
|
93
|
+
Type.URL = Object.freeze(await allocateObject(
|
|
94
|
+
["mfile", "common", ...plural()],
|
|
95
|
+
["mfile", "common", ...plural()].map(url)
|
|
96
|
+
))
|
|
97
|
+
|
|
98
|
+
const pack = e => `${capitalize(e)}Package`
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Mapping from plural module type names to their XML package tag names.
|
|
102
|
+
*
|
|
103
|
+
* @type {Readonly<Record<string, string>>}
|
|
104
|
+
*/
|
|
105
|
+
Type.PACKAGES = Object.freeze(await allocateObject(
|
|
106
|
+
plural(),
|
|
107
|
+
single().map(pack)
|
|
108
|
+
))
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Sealed Type object containing all module type constants and mappings.
|
|
112
|
+
*/
|
|
113
|
+
export default Object.seal(Type)
|
package/src/Watch.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import {Disposer, Notify, Sass, Term, Time} from "@gesslar/toolkit"
|
|
2
|
+
import {watch} from "node:fs/promises"
|
|
3
|
+
import process from "node:process"
|
|
4
|
+
|
|
5
|
+
import Muddy from "./Muddy.js"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @import {DirectoryObject} from "@gesslar/toolkit"
|
|
9
|
+
* @import {DisposerClass} from "@gesslar/toolkit"
|
|
10
|
+
* @import {FileObject} from "@gesslar/toolkit"
|
|
11
|
+
* @import {Glog} from "@gesslar/toolkit"
|
|
12
|
+
* @import {NotifyClass} from "@gesslar/toolkit"
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export default class Watch {
|
|
16
|
+
/** @type {DirectoryObject} */
|
|
17
|
+
#projectDirectory
|
|
18
|
+
/** @type {DirectoryObject} */
|
|
19
|
+
#srcDirectory
|
|
20
|
+
/** @type {FileObject} */
|
|
21
|
+
#mfile
|
|
22
|
+
/** @type {Glog} */
|
|
23
|
+
#glog
|
|
24
|
+
/** @type {NotifyClass} */
|
|
25
|
+
#notify
|
|
26
|
+
/** @type {DisposerClass} */
|
|
27
|
+
#disposer
|
|
28
|
+
// eslint-disable-next-line jsdoc/no-undefined-types
|
|
29
|
+
/** @type {Array<AsyncIterator>} */
|
|
30
|
+
#watchers = new Array()
|
|
31
|
+
/** @type {AbortController} */
|
|
32
|
+
#ac
|
|
33
|
+
/** @type {boolean} */
|
|
34
|
+
#pending = false
|
|
35
|
+
/** @type {boolean} */
|
|
36
|
+
#busy = false
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Main execution point.
|
|
40
|
+
*
|
|
41
|
+
* @param {DirectoryObject} projectDirectory - The directory of project.
|
|
42
|
+
* @param {Glog} log - The Glog instance object.
|
|
43
|
+
*/
|
|
44
|
+
async run(projectDirectory, log) {
|
|
45
|
+
this.#projectDirectory = projectDirectory
|
|
46
|
+
this.#srcDirectory = projectDirectory.getDirectory("src")
|
|
47
|
+
this.#mfile = this.#projectDirectory.getFile("mfile")
|
|
48
|
+
this.#glog = log
|
|
49
|
+
this.#notify = Notify
|
|
50
|
+
this.#disposer = Disposer
|
|
51
|
+
|
|
52
|
+
await new Muddy().run(this.#projectDirectory, this.#glog)
|
|
53
|
+
|
|
54
|
+
this.#initialiseInputHandler()
|
|
55
|
+
this.#startWatch()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async #startWatch() {
|
|
59
|
+
this.#ac = new AbortController()
|
|
60
|
+
|
|
61
|
+
const toWatch = [this.#srcDirectory, this.#mfile]
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
for(const w of toWatch) {
|
|
65
|
+
const watcher = watch(w.url, {
|
|
66
|
+
recursive: w.isDirectory ?? false,
|
|
67
|
+
persistent: true,
|
|
68
|
+
signal: this.#ac.signal,
|
|
69
|
+
overflow: "error"
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
this.#watchers.push(watcher)
|
|
73
|
+
|
|
74
|
+
;(async() => {
|
|
75
|
+
try {
|
|
76
|
+
for await(const _ of watcher) {
|
|
77
|
+
if(this.#busy) {
|
|
78
|
+
this.#pending = true
|
|
79
|
+
continue
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.#pending = false
|
|
83
|
+
this.#busy = true
|
|
84
|
+
|
|
85
|
+
while(true) {
|
|
86
|
+
await Time.after(50)
|
|
87
|
+
await new Muddy().run(this.#projectDirectory, this.#glog)
|
|
88
|
+
|
|
89
|
+
if(this.#pending) {
|
|
90
|
+
this.#pending = false
|
|
91
|
+
continue
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
break
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
this.#busy = false
|
|
98
|
+
}
|
|
99
|
+
} catch(err) {
|
|
100
|
+
if(err.name === "AbortError")
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
throw err
|
|
104
|
+
}
|
|
105
|
+
})()
|
|
106
|
+
}
|
|
107
|
+
} catch {}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Initialises the input handler for watch mode.
|
|
112
|
+
* Sets up raw mode input handling for interactive commands.
|
|
113
|
+
*
|
|
114
|
+
* @returns {void}
|
|
115
|
+
*/
|
|
116
|
+
async #initialiseInputHandler() {
|
|
117
|
+
Term
|
|
118
|
+
.setCharMode()
|
|
119
|
+
.resume()
|
|
120
|
+
.utf8()
|
|
121
|
+
.hideCursor()
|
|
122
|
+
|
|
123
|
+
process.stdin.on("data", async key => {
|
|
124
|
+
try {
|
|
125
|
+
if(key === "q" || key === "\u0003" || key === "\u0004") { // Ctrl+C
|
|
126
|
+
Term
|
|
127
|
+
.setLineMode()
|
|
128
|
+
.showCursor()
|
|
129
|
+
.pause()
|
|
130
|
+
.write("\nExiting.\n")
|
|
131
|
+
|
|
132
|
+
process.exit(0)
|
|
133
|
+
}
|
|
134
|
+
} catch(error) {
|
|
135
|
+
Sass.new("Processing input.", error).report(true)
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import c from "@gesslar/colours"
|
|
4
|
+
import {Collection, DirectoryObject, Glog, Sass, Term} from "@gesslar/toolkit"
|
|
5
|
+
import {Command} from "commander"
|
|
6
|
+
import process from "node:process"
|
|
7
|
+
|
|
8
|
+
import Muddy from "./Muddy.js"
|
|
9
|
+
import Watch from "./Watch.js"
|
|
10
|
+
|
|
11
|
+
const aliasNames = ["OK", "INFO", "WARN", "ERR"]
|
|
12
|
+
const aliasCodes = ["{<I}{F064}", "{<I}{F023}", "{<I}{F178}", "{<I}{F166}"]
|
|
13
|
+
const kindNames = ["aliases", "keys", "scripts", "timers", "triggers", "other"]
|
|
14
|
+
const kindCodes = ["{<I}{F167}", "{<I}{F135}", "{<I}{F026}", "{<I}{F223}", "{<I}{F204}", "{<I}{F136}"]
|
|
15
|
+
|
|
16
|
+
const glogColourNames = ["success", "info", "warn", "error"]
|
|
17
|
+
const glogColourCodes = ["{F035}", "{F033}", "{F208}", "{F032}"]
|
|
18
|
+
|
|
19
|
+
void (async() => {
|
|
20
|
+
const opts = {}, args = []
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
// Initialize colours aliases
|
|
24
|
+
aliasNames.forEach((e, i) => c.alias.set(e, aliasCodes[i]))
|
|
25
|
+
kindNames.forEach((e, i) => c.alias.set(e, kindCodes[i]))
|
|
26
|
+
|
|
27
|
+
// Initialize logging
|
|
28
|
+
const glog = new Glog()
|
|
29
|
+
.withName("MUDDY")
|
|
30
|
+
.withStackTrace()
|
|
31
|
+
.noDisplayName()
|
|
32
|
+
.withColours(await Collection.allocateObject(
|
|
33
|
+
glogColourNames,
|
|
34
|
+
glogColourCodes
|
|
35
|
+
))
|
|
36
|
+
.withSymbols(await Collection.allocateObject(
|
|
37
|
+
glogColourNames,
|
|
38
|
+
[`•`, `•`, `•`, `•`]
|
|
39
|
+
))
|
|
40
|
+
|
|
41
|
+
const program = new Command("muddy")
|
|
42
|
+
.argument("[directory]", "The project directory containing an 'mfile' file and 'src/' directory.")
|
|
43
|
+
.option("-w, --watch", "Enable watch mode.", false)
|
|
44
|
+
.option("-n, --nerd", "Nerd mode. Advanced error reporting.", false)
|
|
45
|
+
.parse()
|
|
46
|
+
|
|
47
|
+
Object.assign(opts, program.opts())
|
|
48
|
+
args.push(...program.args)
|
|
49
|
+
|
|
50
|
+
const dirArg = args.join(" ").trim()
|
|
51
|
+
const cwd = new DirectoryObject(dirArg || ".")
|
|
52
|
+
|
|
53
|
+
if(!await cwd.exists) {
|
|
54
|
+
glog.error(`No such directory '${dirArg}'.`)
|
|
55
|
+
process.exit(1)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if(!(await cwd.hasDirectory("src") && await cwd.hasFile("mfile"))) {
|
|
59
|
+
glog.error(`'${cwd.path}' is not a valid muddy project directory.`)
|
|
60
|
+
process.exit(1)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if(opts.watch) {
|
|
64
|
+
setupAbortHandlers()
|
|
65
|
+
await new Watch().run(cwd, glog)
|
|
66
|
+
} else {
|
|
67
|
+
await new Muddy().run(cwd, glog)
|
|
68
|
+
}
|
|
69
|
+
} catch(error) {
|
|
70
|
+
Sass.from(error, "Starting muddy.").report(opts.nerd ?? false)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Creates handlers for various reasons that the application may crash.
|
|
75
|
+
*/
|
|
76
|
+
function setupAbortHandlers() {
|
|
77
|
+
void["SIGINT", "SIGTERM", "SIGHUP"].forEach(signal => {
|
|
78
|
+
process.on(signal, () => {
|
|
79
|
+
Term
|
|
80
|
+
.setLineMode()
|
|
81
|
+
.showCursor()
|
|
82
|
+
.pause()
|
|
83
|
+
|
|
84
|
+
process.exit(0)
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
})()
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {Valid} from "@gesslar/toolkit"
|
|
2
|
+
|
|
3
|
+
import Module from "./MudletModule.js"
|
|
4
|
+
|
|
5
|
+
export default class Action extends Module {
|
|
6
|
+
#meta = new Map()
|
|
7
|
+
|
|
8
|
+
constructor(object={}) {
|
|
9
|
+
super(object)
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
css="",
|
|
13
|
+
commandButtonUp="",
|
|
14
|
+
commandButtonDown="",
|
|
15
|
+
icon="",
|
|
16
|
+
orientation=0,
|
|
17
|
+
location=0,
|
|
18
|
+
posX=0,
|
|
19
|
+
posY=0,
|
|
20
|
+
mButtonState=1,
|
|
21
|
+
sizeX=0,
|
|
22
|
+
sizeY=0,
|
|
23
|
+
buttonColumn=0,
|
|
24
|
+
buttonRotation=0
|
|
25
|
+
} = object
|
|
26
|
+
|
|
27
|
+
// Validate string fields
|
|
28
|
+
Valid.type(css, "String")
|
|
29
|
+
Valid.type(commandButtonUp, "String")
|
|
30
|
+
Valid.type(commandButtonDown, "String")
|
|
31
|
+
Valid.type(icon, "String")
|
|
32
|
+
|
|
33
|
+
// Validate orientation (0=horizontal, 1=vertical)
|
|
34
|
+
Valid.type(orientation, "Number")
|
|
35
|
+
Valid.assert(orientation === 0 || orientation === 1, "orientation must be 0 or 1")
|
|
36
|
+
|
|
37
|
+
// Validate location (0, 2, 3, or 4)
|
|
38
|
+
Valid.type(location, "Number")
|
|
39
|
+
Valid.assert([0, 2, 3, 4].includes(location), "location must be 0, 2, 3, or 4")
|
|
40
|
+
|
|
41
|
+
// Validate non-negative integers
|
|
42
|
+
Valid.type(posX, "Number")
|
|
43
|
+
Valid.assert(posX >= 0, "posX must be non-negative")
|
|
44
|
+
Valid.type(posY, "Number")
|
|
45
|
+
Valid.assert(posY >= 0, "posY must be non-negative")
|
|
46
|
+
Valid.type(sizeX, "Number")
|
|
47
|
+
Valid.assert(sizeX >= 0, "sizeX must be non-negative")
|
|
48
|
+
Valid.type(sizeY, "Number")
|
|
49
|
+
Valid.assert(sizeY >= 0, "sizeY must be non-negative")
|
|
50
|
+
Valid.type(buttonColumn, "Number")
|
|
51
|
+
Valid.assert(buttonColumn >= 0, "buttonColumn must be non-negative")
|
|
52
|
+
|
|
53
|
+
// Validate button state (1=unchecked/up, 2=checked/down)
|
|
54
|
+
Valid.type(mButtonState, "Number")
|
|
55
|
+
Valid.assert(mButtonState === 1 || mButtonState === 2, "mButtonState must be 1 or 2")
|
|
56
|
+
|
|
57
|
+
// Validate button rotation (0, 90, 180, or 270)
|
|
58
|
+
Valid.type(buttonRotation, "Number")
|
|
59
|
+
Valid.assert([0, 90, 180, 270].includes(buttonRotation), "buttonRotation must be 0, 90, 180, or 270")
|
|
60
|
+
|
|
61
|
+
// Store metadata
|
|
62
|
+
this.#meta.set("css", css)
|
|
63
|
+
this.#meta.set("commandButtonUp", commandButtonUp)
|
|
64
|
+
this.#meta.set("commandButtonDown", commandButtonDown)
|
|
65
|
+
this.#meta.set("icon", icon)
|
|
66
|
+
this.#meta.set("orientation", orientation)
|
|
67
|
+
this.#meta.set("location", location)
|
|
68
|
+
this.#meta.set("posX", posX)
|
|
69
|
+
this.#meta.set("posY", posY)
|
|
70
|
+
this.#meta.set("mButtonState", mButtonState)
|
|
71
|
+
this.#meta.set("sizeX", sizeX)
|
|
72
|
+
this.#meta.set("sizeY", sizeY)
|
|
73
|
+
this.#meta.set("buttonColumn", buttonColumn)
|
|
74
|
+
this.#meta.set("buttonRotation", buttonRotation)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get css() {
|
|
78
|
+
return this.#meta.get("css")
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get commandButtonUp() {
|
|
82
|
+
return this.#meta.get("commandButtonUp")
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get commandButtonDown() {
|
|
86
|
+
return this.#meta.get("commandButtonDown")
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get icon() {
|
|
90
|
+
return this.#meta.get("icon")
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
get orientation() {
|
|
94
|
+
return this.#meta.get("orientation")
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get location() {
|
|
98
|
+
return this.#meta.get("location")
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
get posX() {
|
|
102
|
+
return this.#meta.get("posX")
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
get posY() {
|
|
106
|
+
return this.#meta.get("posY")
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
get mButtonState() {
|
|
110
|
+
return this.#meta.get("mButtonState")
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get sizeX() {
|
|
114
|
+
return this.#meta.get("sizeX")
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
get sizeY() {
|
|
118
|
+
return this.#meta.get("sizeY")
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
get buttonColumn() {
|
|
122
|
+
return this.#meta.get("buttonColumn")
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
get buttonRotation() {
|
|
126
|
+
return this.#meta.get("buttonRotation")
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
toJSON() {
|
|
130
|
+
return Object.assign(
|
|
131
|
+
super.toJSON(),
|
|
132
|
+
{...Object.fromEntries(this.#meta)}
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
toXMLFragment() {
|
|
137
|
+
const frag = super.toXMLFragment()
|
|
138
|
+
|
|
139
|
+
// Add elements in schema order (after name, packageName, script from Module)
|
|
140
|
+
frag
|
|
141
|
+
.last()
|
|
142
|
+
.ele({css: this.css}).up()
|
|
143
|
+
.ele({commandButtonUp: this.commandButtonUp}).up()
|
|
144
|
+
.ele({commandButtonDown: this.commandButtonDown}).up()
|
|
145
|
+
.ele({icon: this.icon}).up()
|
|
146
|
+
.ele({orientation: this.orientation}).up()
|
|
147
|
+
.ele({location: this.location}).up()
|
|
148
|
+
.ele({posX: this.posX}).up()
|
|
149
|
+
.ele({posY: this.posY}).up()
|
|
150
|
+
.ele({mButtonState: this.mButtonState}).up()
|
|
151
|
+
.ele({sizeX: this.sizeX}).up()
|
|
152
|
+
.ele({sizeY: this.sizeY}).up()
|
|
153
|
+
.ele({buttonColumn: this.buttonColumn}).up()
|
|
154
|
+
.ele({buttonRotation: this.buttonRotation}).up()
|
|
155
|
+
|
|
156
|
+
return frag
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {Valid} from "@gesslar/toolkit"
|
|
2
|
+
|
|
3
|
+
import MudletModule from "./MudletModule.js"
|
|
4
|
+
|
|
5
|
+
export default class Alias extends MudletModule {
|
|
6
|
+
#meta = new Map()
|
|
7
|
+
|
|
8
|
+
constructor(object={regex: "", command: ""}) {
|
|
9
|
+
super(object)
|
|
10
|
+
|
|
11
|
+
const {regex="", command=""} = object
|
|
12
|
+
Valid.type(regex, "String")
|
|
13
|
+
Valid.type(command, "String")
|
|
14
|
+
|
|
15
|
+
this.#meta.set("regex", regex)
|
|
16
|
+
this.#meta.set("command", command)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get regex() {
|
|
20
|
+
return this.#meta.get("regex")
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get command() {
|
|
24
|
+
return this.#meta.get("command")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
toJSON() {
|
|
28
|
+
return Object.assign(
|
|
29
|
+
super.toJSON(),
|
|
30
|
+
{...Object.fromEntries(this.#meta)}
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
toXMLFragment() {
|
|
35
|
+
const frag = super.toXMLFragment()
|
|
36
|
+
|
|
37
|
+
// Add elements in schema order (after name, script, packageName from Module)
|
|
38
|
+
frag
|
|
39
|
+
.last()
|
|
40
|
+
.ele({command: this.command}).up()
|
|
41
|
+
.ele({regex: this.regex}).up()
|
|
42
|
+
|
|
43
|
+
return frag
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {Valid} from "@gesslar/toolkit"
|
|
2
|
+
|
|
3
|
+
import MudletModule from "./MudletModule.js"
|
|
4
|
+
|
|
5
|
+
export default class Key extends MudletModule {
|
|
6
|
+
#meta = new Map()
|
|
7
|
+
|
|
8
|
+
constructor(object={}) {
|
|
9
|
+
super(object)
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
command="",
|
|
13
|
+
keyCode=0,
|
|
14
|
+
keyModifier=0
|
|
15
|
+
} = object
|
|
16
|
+
|
|
17
|
+
// Validate string fields
|
|
18
|
+
Valid.type(command, "String")
|
|
19
|
+
|
|
20
|
+
// Validate integer fields
|
|
21
|
+
Valid.type(keyCode, "Number")
|
|
22
|
+
Valid.type(keyModifier, "Number")
|
|
23
|
+
|
|
24
|
+
// Store metadata
|
|
25
|
+
this.#meta.set("command", command)
|
|
26
|
+
this.#meta.set("keyCode", keyCode)
|
|
27
|
+
this.#meta.set("keyModifier", keyModifier)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get command() {
|
|
31
|
+
return this.#meta.get("command")
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get keyCode() {
|
|
35
|
+
return this.#meta.get("keyCode")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get keyModifier() {
|
|
39
|
+
return this.#meta.get("keyModifier")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
toJSON() {
|
|
43
|
+
return Object.assign(
|
|
44
|
+
super.toJSON(),
|
|
45
|
+
{...Object.fromEntries(this.#meta)}
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
toXMLFragment() {
|
|
50
|
+
const frag = super.toXMLFragment()
|
|
51
|
+
|
|
52
|
+
// Add elements in schema order (after name, packageName, script from Module)
|
|
53
|
+
frag
|
|
54
|
+
.last()
|
|
55
|
+
.ele({command: this.command}).up()
|
|
56
|
+
.ele({keyCode: this.keyCode}).up()
|
|
57
|
+
.ele({keyModifier: this.keyModifier}).up()
|
|
58
|
+
|
|
59
|
+
return frag
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const Mfile = new Object()
|
|
2
|
+
|
|
3
|
+
Mfile.FIELDS = Object.freeze([
|
|
4
|
+
"package", "title", "description", "version", "author", "icon",
|
|
5
|
+
"dependencies", "outputFile",
|
|
6
|
+
])
|
|
7
|
+
|
|
8
|
+
Mfile.MFILE_TO_CONFIG = Object.freeze(new Map([
|
|
9
|
+
["package", "mpackage"],
|
|
10
|
+
["author", "author"],
|
|
11
|
+
["icon", "icon"],
|
|
12
|
+
["description", "description"],
|
|
13
|
+
["version", "version"],
|
|
14
|
+
]))
|
|
15
|
+
|
|
16
|
+
export default Mfile
|