You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
6.3 KiB
254 lines
6.3 KiB
import { toEffectRaw, type Effect, type EffectRaw, fromEffectRaw } from "./assignment"
|
|
|
|
export default interface Script {
|
|
name: string
|
|
lines: ScriptLine[]
|
|
}
|
|
|
|
export interface Trigger {
|
|
id: string
|
|
name: string
|
|
event: "Button" | "Time"
|
|
deviceMatch: string
|
|
parameter: string
|
|
scriptTarget: string
|
|
scriptName: string
|
|
scriptPre: ScriptLine[]
|
|
scriptPost: ScriptLine[]
|
|
}
|
|
|
|
export interface TriggerInput extends Pick<Trigger, Exclude<keyof Trigger, "id">> {
|
|
id: string | undefined
|
|
}
|
|
|
|
export interface TriggerEditable {
|
|
id: string | null
|
|
name: string
|
|
event: "Button" | "Time"
|
|
deviceMatch: string
|
|
time: string
|
|
button: string
|
|
scriptTarget: string
|
|
scriptName: string
|
|
scriptPre: ScriptLineEditable[]
|
|
scriptPost: ScriptLineEditable[]
|
|
}
|
|
|
|
type ScriptLineEditableData = ScriptLineIf & ScriptLineAssign & ScriptLineSet & ScriptLineSelect
|
|
|
|
export interface ScriptLineEditable {
|
|
kind: "if" | "assign" | "set" | "select"
|
|
condition: Required<ScriptCondition>
|
|
effect: EffectRaw
|
|
matchKind: "all" | "name" | "role" | "raw"
|
|
matchValue: string
|
|
scope: string
|
|
key: string
|
|
value: string
|
|
then: ScriptLineEditable[]
|
|
else: ScriptLineEditable[]
|
|
}
|
|
|
|
export type ScriptLine =
|
|
| { if: ScriptLineIf }
|
|
| { assign: ScriptLineAssign }
|
|
| { set: ScriptLineSet }
|
|
| { select: ScriptLineSelect }
|
|
|
|
export interface ScriptLineIf {
|
|
condition: ScriptCondition
|
|
then: ScriptLine[]
|
|
else: ScriptLine[]
|
|
}
|
|
|
|
export interface ScriptCondition {
|
|
scope: string
|
|
key: string
|
|
op: string
|
|
value?: string
|
|
not?: boolean
|
|
}
|
|
|
|
export interface ScriptLineAssign {
|
|
match: string
|
|
effect: Effect
|
|
}
|
|
|
|
export interface ScriptLineSet {
|
|
scope: string
|
|
key: string
|
|
value: string
|
|
}
|
|
|
|
export interface ScriptLineAssign {
|
|
match: string
|
|
effect: Effect
|
|
}
|
|
|
|
export interface ScriptLineSelect {
|
|
match: string
|
|
then: ScriptLine[]
|
|
}
|
|
|
|
export function fromEditableScriptLine(line: ScriptLineEditable): ScriptLine {
|
|
switch (line.kind) {
|
|
case "if": return {
|
|
if: {
|
|
condition: line.condition,
|
|
then: line.then.map(fromEditableScriptLine),
|
|
else: line.else.map(fromEditableScriptLine),
|
|
}
|
|
};
|
|
case "assign": return {
|
|
assign: {
|
|
match: fromMatchKindValue(line),
|
|
effect: fromEffectRaw(line.effect),
|
|
}
|
|
}
|
|
case "select": return {
|
|
select: {
|
|
match: fromMatchKindValue(line),
|
|
then: line.then.map(fromEditableScriptLine),
|
|
}
|
|
}
|
|
case "set": return {
|
|
set: {
|
|
key: line.key,
|
|
scope: line.scope,
|
|
value: line.value,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export function newEditableScriptLine(): ScriptLineEditable {
|
|
return toEditableScriptLine({if: {
|
|
condition: { scope: "global", key: "", op: "eq" },
|
|
then: [],
|
|
else: [],
|
|
}})
|
|
}
|
|
|
|
export function toEditableScriptLine(line: ScriptLine): ScriptLineEditable {
|
|
const base = emptyEditable();
|
|
|
|
if ("assign" in line) {
|
|
base.kind = "assign";
|
|
base.effect = toEffectRaw(line.assign.effect);
|
|
Object.assign(base, toMatchKindValue(line.assign.match));
|
|
} else if ("if" in line) {
|
|
base.kind = "if";
|
|
base.condition = {
|
|
...line.if.condition,
|
|
not: line.if.condition.not || false,
|
|
value: line.if.condition.value || "",
|
|
};
|
|
base.then = (line.if.then||[]).map(toEditableScriptLine);
|
|
base.else = (line.if.else||[]).map(toEditableScriptLine);
|
|
} else if ("select" in line) {
|
|
base.kind = "select";
|
|
Object.assign(base, toMatchKindValue(line.select.match));
|
|
base.then = (line.select.then||[]).map(toEditableScriptLine);
|
|
} else if ("set" in line) {
|
|
base.kind = "set";
|
|
base.key = line.set.key
|
|
base.scope = line.set.scope
|
|
base.value = line.set.value
|
|
}
|
|
|
|
return base;
|
|
}
|
|
|
|
function toMatchKindValue(match: string): { matchKind: "all" | "name" | "role" | "raw", matchValue: string } {
|
|
if (match.startsWith("lucifer:name:")) {
|
|
return { matchKind: "name", matchValue: match.slice("lucifer:name:".length) };
|
|
} else if (match.startsWith("lucifer:role:")) {
|
|
return { matchKind: "role", matchValue: match.slice("lucifer:role:".length) };
|
|
} else if (match === "*") {
|
|
return { matchKind: "all", matchValue: "*" };
|
|
} else {
|
|
return { matchKind: "raw", matchValue: match }
|
|
}
|
|
}
|
|
|
|
function fromMatchKindValue({matchKind, matchValue }: { matchKind: "all" | "name" | "role" | "raw", matchValue: string }): string {
|
|
switch (matchKind) {
|
|
case "name": return `lucifer:name:${matchValue}`;
|
|
case "role": return `lucifer:role:${matchValue}`;
|
|
case "all": return "*";
|
|
case "raw": return matchValue;
|
|
}
|
|
}
|
|
|
|
function emptyEditable(): ScriptLineEditable {
|
|
return {
|
|
condition: {
|
|
key: "",
|
|
op: "add",
|
|
scope: "global",
|
|
not: false,
|
|
value: "",
|
|
},
|
|
effect: toEffectRaw({
|
|
solid: {
|
|
states: [
|
|
{color: null, intensity: null, power: null, temperature: null}
|
|
],
|
|
interleave: 0,
|
|
animationMs: 0,
|
|
}
|
|
}),
|
|
key: "",
|
|
kind: "assign",
|
|
matchKind: "name",
|
|
matchValue: "*",
|
|
scope: "match",
|
|
value: "",
|
|
then: [],
|
|
else: [],
|
|
}
|
|
}
|
|
|
|
export function newEditableTrigger(deviceMatch: string, scriptName: string): TriggerEditable {
|
|
return {
|
|
id: null,
|
|
name: "",
|
|
event: "Button",
|
|
deviceMatch: deviceMatch,
|
|
button: "On",
|
|
time: "00:00",
|
|
scriptName: scriptName,
|
|
scriptTarget: deviceMatch,
|
|
scriptPre: [],
|
|
scriptPost: [],
|
|
}
|
|
}
|
|
|
|
export function toEditableTrigger(trigger: Trigger): TriggerEditable {
|
|
return {
|
|
id: trigger.id,
|
|
name: trigger.name,
|
|
event: trigger.event,
|
|
deviceMatch: trigger.deviceMatch,
|
|
button: trigger.event === "Button" ? trigger.parameter : "Up",
|
|
time: trigger.event === "Time" ? trigger.parameter : "00:00",
|
|
scriptName: trigger.scriptName,
|
|
scriptTarget: trigger.scriptTarget,
|
|
scriptPre: trigger.scriptPre.map(toEditableScriptLine),
|
|
scriptPost: trigger.scriptPost.map(toEditableScriptLine),
|
|
}
|
|
}
|
|
|
|
export function fromEditableTrigger(editable: TriggerEditable): TriggerInput {
|
|
return {
|
|
id: editable.id || undefined,
|
|
name: editable.name,
|
|
event: editable.event,
|
|
deviceMatch: editable.deviceMatch,
|
|
parameter: (editable.event === "Button") ? editable.button : editable.time,
|
|
scriptTarget: editable.scriptTarget,
|
|
scriptName: editable.scriptName,
|
|
scriptPre: editable.scriptPre.map(fromEditableScriptLine),
|
|
scriptPost: editable.scriptPost.map(fromEditableScriptLine),
|
|
}
|
|
}
|