question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

notes on the future namespace-based API

See original GitHub issue

In light of https://github.com/ianstormtaylor/slate/issues/2495 and switching to using an interface-based API with plain JavaScript objects and arrays, the core API will change. Using plain JavaScript data means that we can eliminate a decent amount of code I think, and it means we’ll move to mimicking native namespaced utils like Object.entries(object).

This issue is just note to keep track of the “ideal” future interface-and-namespace-based API, as I think of improvements. We’ll work towards it over a series of versions, since we want to keep things incremental and deprecation-friendly whenever possible.

But here’s a sketch…

const Slate = {
  // Creators
  createAnnotation(props, root = null) {},
  createDecoration(props, root = null) {},
  createMark(props) {},
  createNode(props) {},
  createRange(props, root = null) {},
  createPath(array, root = null) {},
  createPoint(props, root = null) {},
  createSelection(props, root = null) {},
  createValue(props) {},

  // Producers
  produce() {}, // for producing new immutable values, delegates to immer
  apply(value, operation) {},
}
const Node = {
  // Getters
  get(root, path) {}, // lookup by path in a `root`
  path(root, node) {}, // lookup a path by `node` instance
  slice(root, range) {}, // slice out a fragment by range
  offset(root, path) {}, // compute the text offset by path
  text(root) {}, // get the concatenated text content of a node

  // Testers
  has(root, path) {}, // test if a path exists
  hasBlocks(root) {},
  hasInlines(root) {},
  isInVoid(root, path) {}, // test if a path is in a void
  isLeafBlock(root) {},
  isLeafInline(root) {},

  // Iterables
  ancestors(root, path) {},
  blocks(root) {},
  descendants(root) {},
  inlines(root) {},
  marks(root) {},
  siblings(root, path) {},
  texts(root) {},

  // Searching
  closest(root, path, predicate = identity) {},
  furthest(root, path, predicate = identity) {},

  // Convenience
  firstBlock(root) {},
  lastBlock(root) {},
  nextBlock(root, path) {},
  previousBlock(root, path) {},
  closestBlock(root, path) {},
  furthestBlock(root, path) {},
  firstInline(root) {},
  lastInline(root) {},
  nextInline(root, path) {},
  previousInline(root, path) {},
  closestInline(root, path) {},
  furthestInline(root, path) {},
  nextSibling(root, path) {},
  previousSibling(root, path) {},
  firstText(root) {},
  lastText(root) {},
  nextText(root, path) {},
  previousText(root, path) {},
  closestVoid(root, path) {},
  furthestVoid(root, path) {},

  // Producers
  addMark(root, path, mark) {},
  removeMark(root, path, mark) {},
  setMark(root, path, mark, newProperties) {},
  insertNode(root, path, node) {},
  removeNode(root, path) {},
  insertText(root, path, offset, text) {},
  removeText(root, path, offset, length) {},
  splitNode(root, path, position) {},
  mergeNode(root, path) {},
  setNode(root, path, newProperties) {},
  setData(node, data) {},
  setObject(node, object) {},
  setType(node, type) {},
  setNodes(node, nodes) {},
}
const Point = {
  // Testers
  isAfter(point, pointOrRange) {},
  isBefore(point, pointOrRange) {},
  isAtEndOf(point, range) {},
  isAtStartOf(point, range) {},
  isIn(point, range) {},

  // Producers
  moveBackward(point, n, root, options) {}, // can specify `options.unit` (char, word, …)
  moveForward(point, n, root, options) {}, // can specify `options.unit` (char, word, …)
  moveTo(point, path, offset, root) {},
  setPath(point, path) {},
  setOffset(point, offset) {},
}
const Range = {
  // Testers
  isBackward(range) {},
  isCollapsed(range) {},
  isExpanded(range) {},
  isForward(range) {},
  isSet(range) {},
  isUnset(range) {},

  // Getters 
  start(range) {},
  end(range) {},

  // Iterables
  points(range) {}, // returns `[start, end]` for convenience

  // Producers
  flip(range) {},
  unset(range) {},
  moveBackward(range, n, root, options) {}, // can specify `options.unit` (char, word, …)
  moveForward(range, n, root, options) {}, // can specify `options.unit` (char, word, …)
  moveTo(range, path, offset) {},
  setAnchor(range, fn) {},
  setFocus(range, fn) {},
  setStart(range, fn) {},
  setEnd(range, fn) {},
  setPoints(range, fn) {},
}
// TODO: the other interfaces...

It’s funny, I thought it was going to make things more verbose, but in reality the before and after is pretty similar (and in some cases more clear) for many of them:

// Before...
const node = document.getNode(path)

// After...
const node = Node.get(document, path)

And the iterators are similar to how Object.entries() works:

for (const [block, path] of Node.blocks(document)) {
  // ...
}

Overall pretty excited for how it’s shaking out. If you want to help make this happen, anything to further https://github.com/ianstormtaylor/slate/issues/2495 is the best way to do that! Thanks.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:3
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
ianstormtaylorcommented, May 21, 2019

@steida that’s a good point, we could consider exporting both and just seeing which one is most useful over time if only one ends up being used.

0reactions
ianstormtaylorcommented, Nov 28, 2019
Read more comments on GitHub >

github_iconTop Results From Across the Web

Namespaces in API notes - C++ interoperability - Swift Forums
Being able to add API notes to namespaces types is blocking me from building a more complete prototype of importing MLIR APIs into...
Read more >
REST API: Introduce dashboard namespace - Make WordPress
Summary. We propose to introduce a dashboard REST API namespace prefix, ... Future iterations of the Dashboard that need to break API ......
Read more >
Best practices for REST API design - Stack Overflow Blog
In this article, we'll look at how to design REST APIs to be easy to understand for anyone consuming them, future-proof, and secure...
Read more >
Kubernetes API Concepts
The Kubernetes API is a resource-based (RESTful) programmatic interface ... A resource type is the name used in the URL ( pods ,...
Read more >
Kubernetes best practices: Specifying Namespaces in YAML
Note : I'll deep dive into gRPC, Istio, Spinnaker, RBAC, and resources in future episodes! Enterprise. At this scale, there are groups that...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found