Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/assets/jaws.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ function jawsStoreKeys(name) {
function jawsPathTarget(keys) {
let obj = window;
for (let i = 0; i < keys.length - 1; i++) {
obj = obj[keys[i]];
obj = obj?.[keys[i]];
}
if (obj == null) {
throw "jaws: JsVar path undefined: " + keys.join('.');
Expand Down
34 changes: 34 additions & 0 deletions lib/assets/js_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,40 @@ process.stdout.write(JSON.stringify({
}
}

func TestJawsJS_MissingJsVarParent(t *testing.T) {
raw := runJawsJSSnippet(t, `
function attach(path) {
const elem = {
id: "Jid.1",
dataset: { jawsstore: path, jawsdata: "1" },
hasAttribute: function(name) { return name === "data-jawsstore"; },
};
try { jawsAttach(elem, true); return ""; }
catch (err) { return String(err); }
}
window.ok = {};
process.stdout.write(JSON.stringify({
shallow: attach("app.state"),
deep: attach("a.b.c"),
valid: attach("ok.state"),
value: window.ok.state,
}));
`)
var got struct {
Shallow string `json:"shallow"`
Deep string `json:"deep"`
Valid string `json:"valid"`
Value int `json:"value"`
}
if err := json.Unmarshal([]byte(raw), &got); err != nil {
t.Fatalf("failed to parse snippet output %q: %v", raw, err)
}
if got.Shallow != "jaws: JsVar path undefined: app.state" ||
got.Deep != "jaws: JsVar path undefined: a.b.c" || got.Valid != "" || got.Value != 1 {
t.Fatalf("JsVar parent handling = %+v", got)
}
}

func TestJawsJS_StoreReadAndOptimisticProposal(t *testing.T) {
raw := runJawsJSSnippet(t, `
function FakeSocket() { this.readyState = 1; this.sent = []; }
Expand Down
5 changes: 5 additions & 0 deletions lib/ui/jsvar.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ type JsVarStore[T any] struct {
// The name is a dot-separated path from window using JavaScript identifiers
// with ASCII letters, digits, underscore, or dollar sign. No component may be
// "__proto__", "constructor", or "prototype"; the limit is 4096 bytes.
// For dotted names, every parent object must exist on window before jaws.js runs;
// otherwise the client stops before opening its WebSocket. A top-level name
// needs no existing property.
// Initial data and patches assign to that live path, including browser-owned
// properties and setters.
//
Expand Down Expand Up @@ -168,6 +171,8 @@ func NewJsVarStore[T any](jw *jaws.Jaws, name string, locker sync.Locker, value
// Render each binding once during the Request's initial page render, outside
// regions that may later be replaced or removed. Browser names may neither
// duplicate nor contain one another within a Request.
// For dotted names, the parent objects must exist on window before jaws.js runs;
// otherwise the client stops before opening its WebSocket.
func (store *JsVarStore[T]) Bind() *JsVarBinding[T] {
return &JsVarBinding[T]{store: store}
}
Expand Down
Loading