{"id":13726730,"url":"https://github.com/reasonml-community/bs-webapi-incubator","last_synced_at":"2025-10-04T21:30:22.643Z","repository":{"id":55429376,"uuid":"67062712","full_name":"reasonml-community/bs-webapi-incubator","owner":"reasonml-community","description":"BuckleScript bindings to the DOM and other Web APIs","archived":true,"fork":false,"pushed_at":"2021-10-31T18:13:13.000Z","size":873,"stargazers_count":294,"open_issues_count":17,"forks_count":73,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-01-17T11:40:58.620Z","etag":null,"topics":["bindings","bucklescript","javascript","ocaml","reason"],"latest_commit_sha":null,"homepage":"","language":"Reason","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/reasonml-community.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-08-31T18:21:36.000Z","updated_at":"2024-12-27T00:03:19.000Z","dependencies_parsed_at":"2022-08-15T00:01:14.297Z","dependency_job_id":null,"html_url":"https://github.com/reasonml-community/bs-webapi-incubator","commit_stats":null,"previous_names":["buckletypes/reason-js"],"tags_count":63,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reasonml-community%2Fbs-webapi-incubator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reasonml-community%2Fbs-webapi-incubator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reasonml-community%2Fbs-webapi-incubator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reasonml-community%2Fbs-webapi-incubator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reasonml-community","download_url":"https://codeload.github.com/reasonml-community/bs-webapi-incubator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235021616,"owners_count":18923606,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bindings","bucklescript","javascript","ocaml","reason"],"created_at":"2024-08-03T01:03:18.198Z","updated_at":"2025-10-04T21:30:22.316Z","avatar_url":"https://github.com/reasonml-community.png","language":"Reason","funding_links":[],"categories":["Reason"],"sub_categories":[],"readme":"# bs-webapi\n\n**IMPORTANT: this repository is deprecated in favour of** https://github.com/tinymce/rescript-webapi/\n\nPlease use ReScript-WebAPI going forward.\n\nExperimental bindings to the DOM and other Web APIs.\n\n[![npm](https://img.shields.io/npm/v/bs-webapi.svg)](https://npmjs.org/bs-webapi)\n[![Travis](https://img.shields.io/travis/reasonml-community/bs-webapi-incubator/master.svg)](https://travis-ci.org/reasonml-community/bs-webapi-incubator)\n\nAPI docs are available at\nhttps://reasonml-community.github.io/bs-webapi-incubator/api/Webapi/ , but\ndocumentation comments are sparse as the code mostly just consists of\nexternal declarations with type signatures. The bindings generally also\ncorrespond very well to the Web APIs they bind to, so using MDN along\nwith GitHub should go a long way.\n\n## Installation\n\n```\nnpm install bs-webapi\n```\nThen add `bs-webapi` to `bs-dependencies` in your `bsconfig.json`. A minimal example:\n```\n{\n  \"name\": \"my-thing\",\n  \"sources\": \"src\",\n  \"bs-dependencies\": [\"bs-webapi\"]\n}\n```\n\n## Usage\n\nSee the [examples folder](https://github.com/reasonml-community/bs-webapi-incubator/blob/master/examples/)\n\nPlease only use the modules exposed through the toplevel module `Webapi`, for example `Webapi.Dom.Element`. In particular, don't use the 'flat' modules like `Webapi__Dom__Element` as these are considered private and are not guaranteed to be backwards-compatible.\n\n## Some notes on the DOM API\n\nThe DOM API is mostly organized into interfaces and relies heavily on inheritance. The ergonomics of the API is also heavily dependent on dynamic typing, which makes it somewhat challenging to implement a thin binding layer that is both safe and ergonomic. To achieve this we employ subtyping and implementation inheritance, concepts which aren't very idiomatic to OCaml (or Reason), but all the more beneficial to understand in order to be able to use these bindings effectively.\n\n### Subtyping\n\nThe Dom types, and the relationships between them, are actually defined in the `Dom` module that ships with `bs-platform` ([Source code](https://github.com/glennsl/bucklescript/blob/master/jscomp/others/dom.mli)), where you'll find a bunch of types that look like this:\n\n```reason\ntype _element('a);\ntype element_like('a) = node_like(_element('a));\ntype element = element_like(_baseClass);\n```\n\nThis is subtyping implemented with abstract types and phantom arguments. The details of how this works isn't very important (but see [#23](https://github.com/reasonml-community/bs-webapi-incubator/pull/23) for a detailed explanation of how exactly this trickery works) in order to just use them, but there are a few things you should know:\n\n* If you expand the alias of a concrete DOM type, you'll discover it's actually a list of abstract types. e.g. `element` expands to `_baseClass _element _node _eventTarget_like` This means `element` is a subtype of `_element`, `_node` and `_eventTarget_like`.\n* The `_like` type are \"open\" (because they have a type variable). This means that a function accepting an `'a element_like` will accept any \"supertype\" of `element_like`. A function accepting just an `element` will only accept an `element` (Technically `element` is actually a \"supertype\" of `element_like` too).\n\nThis system works exceptionally well, but has one significant flaw: It makes type errors even more complicated than they normally are. If you know what to look for it's not that bad, but unfortunately the formatting of these errors don't make looking for it any easier. We hope to improve that in other ways (see [BetterErrors](https://github.com/reasonml/BetterErrors))\n\n### Implementation inheritance\n\nIf you've looked through the source code a bit, you've likely come across code like this:\n\n```reason\ninclude Webapi__Dom__EventTarget.Impl({ type nonrec t = t });\ninclude Webapi__Dom__Node.Impl({ type nonrec t = t });\ninclude Webapi__Dom__ParentNode.Impl({ type nonrec t = t });\ninclude Webapi__Dom__NonDocumentTypeChildNode.Impl({ type nonrec t = t });\ninclude Webapi__Dom__ChildNode.Impl({ type nonrec t = t });\ninclude Webapi__Dom__Slotable.Impl({ type nonrec t = t });\ninclude Impl({ type nonrec t = t });\n```\n\nThis is the implementation inheritance. Each \"inheritable\" module defines an \"Impl\" module where all its exported functions are defined. `include Webapi__Dom__Node.Impl { type nonrec t = t };` means that all the functions in `Webapi__Dom__Node.Impl` should be included in this module, but with the `t` type of that module replaced by the `t` type of this one. And that's it, it now has all the functions.\n\nImplementation inheritance is used instead of subtyping to make it easier to understand which functions operate on any given \"subject\". If you have an `element` and you need to use a function defined in `Node`, let's say `removeChild` you cannot just use `Node.removeChild`. Instead you need to use `Element.removeChild`, which you can since `Element` inherits from `Node`. As a general rule, always use the function in the module corresponding to the type you have. You'll find this makes it very easy to see what types you're dealing with just by reading the code.\n\n## Changes\n\nSee [CHANGELOG.md](CHANGELOG.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freasonml-community%2Fbs-webapi-incubator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freasonml-community%2Fbs-webapi-incubator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freasonml-community%2Fbs-webapi-incubator/lists"}