Skip to content

classify: filter undefined values from JS objects - #86

Merged
andreypopp merged 1 commit into
mainfrom
classify-drop-undefined
Apr 28, 2026
Merged

classify: filter undefined values from JS objects#86
andreypopp merged 1 commit into
mainfrom
classify-drop-undefined

Conversation

@andreypopp

Copy link
Copy Markdown
Collaborator

The browser PPX emits Js.Undefined.empty for record fields with [@json.option] [@json.drop_default] when the value is None, so the JS object carries a key with an undefined value. Js.Dict.entries exposes those entries, and classify previously tripped on them with "unknown JSON value type: undefined".

Filter undefined entries in the `Assoc branch so that dropped fields are unobservable to consumers, matching the intent of [@json.option].

The browser PPX emits Js.Undefined.empty for record fields with
[@json.option] [@json.drop_default] when the value is None, so the
JS object carries a key with an undefined value. Js.Dict.entries
exposes those entries, and classify previously tripped on them with
"unknown JSON value type: undefined".

Filter undefined entries in the `Assoc branch so that dropped fields
are unobservable to consumers, matching the intent of [@json.option].

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread src/classify.ml
Comment on lines +5 to +15
let dict_to_list_without_undefined dict =
let keys = Js.Dict.keys dict in
let l = Array.length keys in
let xs = ref [] in
for i = l - 1 downto 0 do
let key = Array.unsafe_get keys i in
let value = Js.Dict.unsafeGet dict key in
if not ((Obj.magic value : _ Js.Undefined.t) == Js.undefined) then
xs := (key, value) :: !xs
done;
!xs

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably there is some performance issues, but why don't do this:

let dict_to_list_without_undefined dict =
  Js.Dict.entries dict
  |> Array.to_list
  |> List.filter (fun (_, value) ->
         not ((Obj.magic value : _ Js.Undefined.t) == Js.undefined))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or

let dict_to_list_without_undefined dict =
  Array.fold_right
    (fun (key, value) acc ->
      if not ((Obj.magic value : _ Js.Undefined.t) == Js.undefined) then
        (key, value) :: acc
      else acc)
    (Js.Dict.entries dict) []

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I wanted to reduce number of allocations as much as possible, so no intermediate lists/arrays.

@pedrobslisboa pedrobslisboa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments above are just for curiosity.

Comment thread src/classify.ml
for i = l - 1 downto 0 do
let key = Array.unsafe_get keys i in
let value = Js.Dict.unsafeGet dict key in
if not ((Obj.magic value : _ Js.Undefined.t) == Js.undefined) then

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably the same reason of the other comment, but why not Js.typeof value <> "undefined" in this case instead of Obj.magic?

@andreypopp
andreypopp merged commit 4d22e74 into main Apr 28, 2026
1 check passed
@andreypopp
andreypopp deleted the classify-drop-undefined branch April 28, 2026 17:21
jchavarri added a commit that referenced this pull request Jun 29, 2026
* main: (40 commits)
  Respect nonrec type declarations in json derivers (#94)
  ppx/test: cover encode behavior for @drop_default variants (#84)
  allow @@compact_variants to parse ["Tag"] in addition to "Tag" for nullary variants (#93)
  Make extra JSON fields allowed by default (#92)
  Fix error messages for `[@@json.compact_variants]` (#91)
  Revert "Fix error message for @@compact_variants" (#90)
  Fix error message for @@compact_variants (#87)
  ppx: add [@json.catch_all] for forward-compatible string enums (#88)
  classify: filter undefined values from JS objects (#86)
  Add primitives semantics table to readme (#82)
  Support @json.compact_variants on polyvariant types (#79)
  ppx: allow dropping arbitrary values with `[@drop_default]` (#77)
  .gitignore: .claude
  upgrade ppxlib to 0.36 / handle Ptyp_open (#60)
  build with Melange 6 / OCaml 5.4 (#72)
  fmt: format using OCamlformat 0.28 (#75)
  fix: use `opam-check-npm-deps` compatible with OPAM 2.5 (#74)
  native: re_export yojson
  browser: remove dup of_json_error_to_string
  native: +of_json_error_to_string
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants