lightview 2.2.2 → 2.3.4

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/jprx/README.md CHANGED
@@ -10,8 +10,15 @@ JPRX is a **syntax** and an **expression engine**. While this repository provide
10
10
 
11
11
  - **Declarative Power**: Define relationships between data points as easily as writing an Excel formula.
12
12
  - **Security**: JPRX strictly avoids `eval()`. Expressions are handled by a custom high-performance Pratt parser and a registry of pre-defined helpers, making it safe for dynamic content.
13
- - **Portability**: Because JPRX expressions are strings within JSON structures, they are easily serialized, stored, and sent over the wire.
14
- - **Platform Agnostic**: While Lightview is the first implementation, JPRX can be used in any environment that manages reactive state.
13
+ - **Portability**: JPRX expressions are strings within JSON, making them easily serialized and platform-agnostic.
14
+ - **Schema-First**: Integrated support for JSON Schema and shorthand descriptors provides industrial-strength validation and "future-proof" reactivity.
15
+
16
+ ## UI Library Requirements
17
+
18
+ To fully support JPRX, an underlying UI library **MUST** provide:
19
+ - **Mount Lifecycle**: A hook (e.g., `onmount`) where state initialization can occur. JPRX relies on the library to trigger these initializers.
20
+ - **Event Handling**: Support for standard event handlers (like `oninput`, `onclick`) **SHOULD** be provided, though exact implementations may vary by platform.
21
+ - **Reactivity**: A way to resolve paths to reactive primitives (e.g., Signals or Proxies).
15
22
 
16
23
  ## Syntax & Features
17
24
 
@@ -19,112 +26,146 @@ JPRX extends the base JSON Pointer syntax with:
19
26
 
20
27
  | Feature | Syntax | Description |
21
28
  |---------|--------|-------------|
22
- | **Global Path** | `$/user/name` | Access global state via an absolute path. |
29
+ | **Global Path** | `=/user/name` | Access global state via an absolute path. |
23
30
  | **Relative Path** | `./count` | Access properties relative to the current context. |
24
- | **Parent Path** | `../id` | Traverse up the state hierarchy. |
25
- | **Functions** | `$sum(/items...price)` | Call registered core helpers. |
31
+ | **Parent Path** | `../id` | Traverse up the state hierarchy (UP-tree search). |
32
+ | **Functions** | `=sum(/items...price)` | Call registered core helpers. |
26
33
  | **Explosion** | `/items...name` | Extract a property from every object in an array (spread). |
27
- | **Operators** | `$++/count`, `$/a + $/b` | Familiar JS-style prefix, postfix, and infix operators. |
28
- | **Placeholders** | `_` (item), `$event` | Context-aware placeholders for iteration and interaction. |
34
+ | **Operators** | `=++/count`, `=/a + =/b` | Familiar JS-style prefix, postfix, and infix operators. |
35
+ | **Placeholders** | `_` (item), `$this`, `$event` | Context-aware placeholders for iteration and interaction. |
36
+ | **Two-Way Binding**| `=bind(/user/name)`| Create a managed, two-way reactive link for inputs. |
37
+ | **DOM Patches** | `=move(target, loc)`| Decentralized layout: Move/replace host element into a target. |
29
38
 
30
- ## Human & AI Utility
39
+ Once inside a JPRX expression, the `=` prefix is only needed at the start of the expression for paths or function names.
31
40
 
32
- JPRX is uniquely positioned to bridge the gap between human developers and AI coding assistants:
33
41
 
34
- ### For Humans: "The Excel Paradigm"
35
- Humans are often familiar with the "recalculation" model of spreadsheets. JPRX brings this to UI development. Instead of writing complex "glue code" (event listeners, state updates, DOM manipulation), developers specify the *formula* for a UI element once, and it stays updated forever.
42
+ ## State Management
36
43
 
37
- ### For AI: Structured & Concise
38
- Large Language Models (LLMs) are exceptionally good at generating structured data (JSON) and formulaic expressions. They are often prone to errors when generating large blocks of imperative JavaScript logic. JPRX provides a high-level, declarative "target" for AI to aim at, resulting in:
39
- - **Higher Accuracy**: Less boilerplate means fewer places for the AI to hallucinate.
40
- - **Safety**: AI can generate UI logic that remains sandboxed and secure.
41
- - **Compactness**: Entire interactive components can be described in a few lines of JSON.
44
+ JPRX utilizes explicit state initializers within lifecycle hooks:
42
45
 
43
- ## Operators
46
+ ### Scoped State
47
+ States can be attached to specific scopes (such as a DOM node or Component instance) using the `scope` property in the options argument.
48
+ - **Up-tree Resolution**: When resolving a path, JPRX walks up the provided scope chain looking for the nearest owner of that name.
49
+ - **Future Signals**: JPRX allows subscription to a named signal *before* it is initialized. The system will automatically "hook up" once the state is created via `$state` or `$signal`.
44
50
 
45
- JPRX supports a wide range of operators that provide a more concise and familiar syntax than function calls.
51
+ ### The `=state` and `=signal` Helpers
52
+ - `=state(value, { name: 'user', schema: 'UserProfile', scope: event.target })`
53
+ - `=signal(0, { name: 'count', schema: 'auto' })`
46
54
 
47
- ### Arithmetic & Logic (Infix)
48
- Infix operators require surrounding whitespace in JPRX to avoid ambiguity with path separators.
55
+ ## Schema Registry & Validation
49
56
 
50
- - **Arithmetic**: `+`, `-`, `*`, `/`, `mod`, `pow`
51
- - **Comparison**: `>`, `<`, `>=`, `<=`, `==`, `!=`
52
- - **Logic**: `&&`, `||`
57
+ JPRX integrates with a global Schema Registry via `jprx.registerSchema(name, definition)`.
53
58
 
54
- *Example:* `$/a + $/b * 10 > $/threshold`
59
+ ### Registering and Using Schemas
60
+ ```javascript
61
+ // 1. Register a schema centrally
62
+ jprx.registerSchema('UserProfile', {
63
+ name: "string",
64
+ age: "number",
65
+ email: { type: "string", format: "email" }
66
+ });
55
67
 
56
- ### Mutation & Unary (Prefix/Postfix)
57
- These operators are typically used in event handlers or for immediate state transformation.
68
+ // 2. Reference the registered schema by name (Scoped)
69
+ const user = =state({}, { name: 'user', schema: 'UserProfile', scope: $this });
70
+
71
+ // 3. Use the 'polymorphic' shorthand for auto-coercion
72
+ const settings = =state({ volume: 50 }, { name: 'settings', schema: 'polymorphic' });
73
+ // Result: settings.volume = "60" will automatically coerce to the number 60.
74
+ ```
58
75
 
59
- - **Increment**: `$++/count` (prefix) or `$/count++` (postfix)
60
- - **Decrement**: `$--/count` (prefix) or `$/count--` (postfix)
61
- - **Toggle**: `$!!/enabled` (logical NOT/toggle)
76
+ - **Polymorphic Schemas**:
77
+ - **`"auto"`**: Infers the fixed schema from the initial value. Strict type checking (e.g., setting a number to a string throws). New properties are not allowed.
78
+ - **`"dynamic"`**: Like `auto`, but allows new properties to be added to the state object.
79
+ - **`"polymorphic"`**: Includes **`dynamic`** behavior and automatically coerces values to match the inferred type (e.g., "50" -> 50) rather than throwing.
80
+ - **Shorthand**: A simple object like `{ name: "string" }` is internally normalized to a JSON Schema.
62
81
 
63
- ## Helper Functions
82
+ ### Transformation Schemas
83
+ Schemas can define transformations that occur during state updates, ensuring data remains in a consistent format regardless of how it was input.
64
84
 
65
- JPRX includes a comprehensive library of built-in helpers. For security, only registered helpers are available—there is no access to the global JavaScript environment.
85
+ ```json
86
+ {
87
+ "type": "object",
88
+ "properties": {
89
+ "username": {
90
+ "type": "string",
91
+ "transform": "lower"
92
+ }
93
+ }
94
+ }
95
+ ```
96
+ *Note: The `=bind` helper uses these transformations to automatically clean data as the user types.*
66
97
 
67
- ### Math
68
- `add`, `sub`, `mul`, `div`, `mod`, `pow`, `sqrt`, `abs`, `round`, `ceil`, `floor`, `min`, `max`
98
+ ## Two-Way Binding with `=bind`
69
99
 
70
- ### Stats
71
- `sum`, `avg`, `min`, `max`, `median`, `stdev`, `var`
100
+ The `=bind(path)` helper creates a managed, two-way link between the UI and a state path.
72
101
 
73
- ### String
74
- `upper`, `lower`, `trim`, `capitalize`, `titleCase`, `contains`, `startsWith`, `endsWith`, `replace`, `split`, `join`, `concat`, `len`, `default`
102
+ ### Strictness
103
+ To ensure unambiguous data flow, `=bind` only accepts direct paths. It cannot be used directly with computed expressions like `=bind(upper(/name))`.
75
104
 
76
- ### Array
77
- `count`, `map`, `filter`, `find`, `unique`, `sort`, `reverse`, `first`, `last`, `slice`, `flatten`, `join`, `len`
105
+ ### Handling Transformations
106
+ If you need to transform data during a two-way binding, there are two primary approaches:
107
+ 1. **Event-Based**: Use a manual `oninput` handler to apply the transformation, e.g., `=set(/name, upper($event/target/value))`.
108
+ 2. **Schema-Based**: Define a `transform` or `pattern` in the schema for the path. The `=bind` helper will respect the schema rules during the write-back phase.
78
109
 
79
- ### Logic & Comparison
80
- `if`, `and`, `or`, `not`, `eq`, `neq`, `gt`, `lt`, `gte`, `lte`, `between`, `in`
110
+ ---
81
111
 
82
- ### Formatting
83
- `number`, `currency`, `percent`, `thousands`
112
+ ## DOM Patches & Decentralized Layouts
84
113
 
85
- ### DateTime
86
- `now`, `today`, `date`, `formatDate`, `year`, `month`, `day`, `weekday`, `addDays`, `dateDiff`
114
+ One of the most powerful features of JPRX in UI environments (like Lightview) is the ability to perform **Decentralized DOM Patches** via the `=move(target, location)` helper.
87
115
 
88
- ### Lookup
89
- `lookup`, `vlookup`, `index`, `match`
116
+ ### The Problem: LLM Streaming & Layouts
117
+ When an LLM streams UI components, it often knows *what* it is creating before it knows exactly *where* that item belongs in a complex dashboard, or it may need to update an existing element that was created minutes ago.
90
118
 
91
- ### State Mutation
92
- `set`, `increment`, `decrement`, `toggle`, `push`, `pop`, `assign`, `clear`
119
+ ### The Solution: `=move`
120
+ The `=move` helper allows a component to "place itself" into the document upon mounting.
93
121
 
94
- ### Network
95
- `fetch(url, options?)` - *Auto-serializes JSON bodies and handles content-types.*
122
+ ```json
123
+ {
124
+ "tag": "div",
125
+ "id": "weather-widget",
126
+ "onmount": "=move('#dashboard-sidebar', 'afterbegin')",
127
+ "content": "Sunny, 75°F"
128
+ }
129
+ ```
130
+
131
+ **Key Behaviors:**
132
+ 1. **Teleportation**: The host element is physically moved from the "Stream Container" (where it was born) to the specified `target` (e.g., `#dashboard-sidebar`).
133
+ 2. **Idempotent Updates**: If the moving element has an `id` (e.g., `weather-widget`) and an element with that same ID already exists at the destination, the existing element is **replaced**. This allows the LLM to "patch" the UI simply by streaming the updated version of the component.
134
+ 3. **Flicker-Free**: By rendering the stream in a hidden container, the element is moved and appears in its final destination instantly.
135
+
136
+ ### The Delivery Vehicle: `=mount`
137
+ The `=mount(url, options?)` helper is the primary mechanism for fetching these decentralized updates.
138
+
139
+ 1. **Arrival**: `=mount` fetches the content and "lands" it at the end of the `document.body` (by default).
140
+ 2. **Mounting**: The content is hydrated and added to the DOM, triggering its `onmount` hook.
141
+ 3. **Teleportation**: If the content contains `=move`, it immediately relocates itself to its destination.
142
+
143
+ This separation of concerns makes the system incredibly robust: `=mount` handles the **delivery**, while `=move` handles the **logic** of where the content belongs.
144
+
145
+ ### Why Decentralized?
146
+ - **Low Overhead**: The LLM doesn't need to maintain a map of the entire DOM; it just needs to know the ID or Selector of where it wants to "push" its content.
147
+ - **Independence**: Components are self-contained. A "Notification" component knows how to display itself AND where notification stacks live.
148
+ - **Context Preservation**: In Lightview, moved elements retain their original reactive context ("backpack"), allowing them to stay linked to the stream that created them.
149
+
150
+ ---
96
151
 
97
152
  ## Example
98
153
 
99
- A simple reactive counter described in JPRX syntax:
154
+ A modern, lifecycle-based reactive counter:
100
155
 
101
156
  ```json
102
157
  {
103
158
  "div": {
104
- "cdom-state": { "count": 0 },
159
+ "onmount": "=state({ count: 0 }, { name: 'counter', schema: 'auto', scope: $this })",
105
160
  "children": [
106
- { "h2": "Counter" },
107
- { "p": ["Current Count: ", "$/count"] },
108
- { "button": { "onclick": "$increment(/count)", "children": ["+"] } },
109
- { "button": { "onclick": "$decrement(/count)", "children": ["-"] } }
161
+ { "h2": "Modern JPRX Counter" },
162
+ { "p": ["Current Count: ", "=/counter/count"] },
163
+ { "button": { "onclick": "=++/counter/count", "children": ["+"] } },
164
+ { "button": { "onclick": "=--/counter/count", "children": ["-"] } }
110
165
  ]
111
166
  }
112
167
  }
113
168
  ```
114
169
 
115
- ## Reference Implementation: Lightview
116
-
117
- JPRX was originally developed for [Lightview](https://github.com/anywhichway/lightview) to power its **Computational DOM (cDOM)**. Lightview serves as the primary example of how a UI library can hydrate JPRX expressions into a live, reactive interface.
118
-
119
- If you are building a UI library and want to support reactive JSON structures, this parser provides the foundation.
120
-
121
- ## Getting Started
122
-
123
- The JPRX package contains:
124
- 1. `parser.js`: The core Pratt parser and path resolution logic.
125
- 2. `helpers/`: A comprehensive library of math, logic, string, array, formatting, and state helpers.
126
-
127
- To use JPRX, you typically register your state-management primitives (like Signals or Proxies) with the parser's registry, and then call `hydrate()` or `resolveExpression()` to activate the logic.
128
-
129
170
  ---
130
171
  © 2026 Simon Y. Blackwell, AnyWhichWay LLC. Licensed under MIT.
@@ -64,6 +64,24 @@ export const clear = (target) => {
64
64
  return set(target, null);
65
65
  };
66
66
 
67
+ export function state(val, options) {
68
+ if (globalThis.Lightview) {
69
+ const finalOptions = typeof options === 'string' ? { name: options } : options;
70
+ return globalThis.Lightview.state(val, finalOptions);
71
+ }
72
+ throw new Error('JPRX: $state requires a UI library implementation.');
73
+ }
74
+
75
+ export function signal(val, options) {
76
+ if (globalThis.Lightview) {
77
+ const finalOptions = typeof options === 'string' ? { name: options } : options;
78
+ return globalThis.Lightview.signal(val, finalOptions);
79
+ }
80
+ throw new Error('JPRX: $signal requires a UI library implementation.');
81
+ }
82
+
83
+ export const bind = (path, options) => ({ __JPRX_BIND__: true, path, options });
84
+
67
85
  export const registerStateHelpers = (register) => {
68
86
  const opts = { pathAware: true };
69
87
  register('set', set, opts);
@@ -77,4 +95,7 @@ export const registerStateHelpers = (register) => {
77
95
  register('pop', pop, opts);
78
96
  register('assign', assign, opts);
79
97
  register('clear', clear, opts);
98
+ register('state', state);
99
+ register('signal', signal);
100
+ register('bind', bind);
80
101
  };
package/jprx/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jprx",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "JSON Reactive Path eXpressions - A reactive expression language for JSON data",
5
5
  "main": "index.js",
6
6
  "type": "module",