refactor: replace array-based expressions with typed class hierarchy
Replace the old Lisp-like array expression representation (["AND", ["PARAM", ...], ...]) with a class hierarchy rooted in an abstract Expression class (Literal, Parameter, Binary, Unary, FunctionCall, Conditional). This gives compile-time type safety to expression construction, evaluation, and pattern matching. Key changes: - New lib/common/expression.ts defines the class hierarchy with map/evaluate/toString methods - Rewrite parser as hand-rolled recursive descent, removing the parsimmon dependency - Extend Path with a colon separator to unify parameter identity and attributes into a single address space (e.g. "Device.WiFi.SSID.1.Name:writable"). The colon field tracks how many trailing segments are attribute qualifiers. PathSet rewritten with separate param/attr segment indexes - Flatten device attribute representation in the UI to colon-delimited keys mirroring the new path syntax
This commit is contained in:
1 parent
75908e624f
commit
6f3ce6f7c8
71 files changed
+4045
-3449
No files matched your search
+21
-14
@@ -1,12 +1,8 @@
|
||||
import { ClosureComponent, Component, Children } from "mithril";
|
||||
import { ClosureComponent, Children } from "mithril";
|
||||
import { m } from "./components.ts";
|
||||
import { stringify } from "../lib/common/expression/parser.ts";
|
||||
import memoize from "../lib/common/memoize.ts";
|
||||
import * as store from "./store.ts";
|
||||
import Expression from "../lib/common/expression.ts";
|
||||
|
||||
const memoizedStringify = memoize(stringify);
|
||||
|
||||
function drawChart(chartData): Children {
|
||||
function drawChart(chartData: Attrs["chart"]): Children {
|
||||
const slices = chartData.slices;
|
||||
const total: number = Array.from(Object.values(chartData.slices)).reduce(
|
||||
(a: number, s) => a + (s["count"]["value"] || 0),
|
||||
@@ -27,10 +23,10 @@ function drawChart(chartData): Children {
|
||||
m(
|
||||
"td",
|
||||
m("span.inline-block w-3 h-3 border border-stone-200 mr-1", {
|
||||
style: `background-color: ${store.evaluateExpression(slice["color"], null)} !important;`,
|
||||
style: `background-color: ${slice.color} !important;`,
|
||||
}),
|
||||
),
|
||||
m("td.w-full", store.evaluateExpression(slice["label"], null)),
|
||||
m("td.w-full", slice.label),
|
||||
m(
|
||||
"td.text-stone-500 text-right tabular-nums",
|
||||
`${Math.round(percent * 100)}%`,
|
||||
@@ -41,7 +37,7 @@ function drawChart(chartData): Children {
|
||||
"a.text-cyan-700 hover:text-cyan-900 font-medium ml-2",
|
||||
{
|
||||
href: `#!/devices/?${m.buildQueryString({
|
||||
filter: memoizedStringify(slice["filter"]),
|
||||
filter: slice.filter.toString(),
|
||||
})}`,
|
||||
},
|
||||
slice["count"]["value"] || 0,
|
||||
@@ -67,7 +63,7 @@ function drawChart(chartData): Children {
|
||||
paths.push(
|
||||
m("path.stroke-white stroke-1", {
|
||||
d: sketch,
|
||||
fill: store.evaluateExpression(slice["color"], null),
|
||||
fill: slice.color,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -81,7 +77,7 @@ function drawChart(chartData): Children {
|
||||
"a.opacity-0 hover:opacity-100 focus-visible:opacity-100 outline-hidden",
|
||||
{
|
||||
"xlink:href": `#!/devices/?${m.buildQueryString({
|
||||
filter: memoizedStringify(slice["filter"]),
|
||||
filter: slice.filter.toString(),
|
||||
})}`,
|
||||
},
|
||||
[
|
||||
@@ -137,10 +133,21 @@ function drawChart(chartData): Children {
|
||||
);
|
||||
}
|
||||
|
||||
const component: ClosureComponent = (): Component => {
|
||||
interface Attrs {
|
||||
chart: {
|
||||
label: string;
|
||||
slices: {
|
||||
label: string;
|
||||
filter: Expression;
|
||||
color: string;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
const component: ClosureComponent<Attrs> = () => {
|
||||
return {
|
||||
view: (vnode) => {
|
||||
return drawChart(vnode.attrs["chart"]);
|
||||
return drawChart(vnode.attrs.chart);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user