mirror of
https://github.com/loro-dev/loro.git
synced 2025-02-05 12:14:43 +00:00
docs: update ts docs (#529)
* docs: update ts docs * docs: update rust docs * test: add js doc tests and fix outdated js docs
This commit is contained in:
parent
afec0b8c2e
commit
e2be56b0c2
7 changed files with 748 additions and 220 deletions
|
@ -76,7 +76,7 @@ type JsResult<T> = Result<T, JsValue>;
|
|||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } import "loro-crdt"
|
||||
/// import { LoroDoc } from "loro-crdt"
|
||||
///
|
||||
/// const loro = new LoroDoc();
|
||||
/// const text = loro.getText("text");
|
||||
|
@ -84,8 +84,6 @@ type JsResult<T> = Result<T, JsValue>;
|
|||
/// const map = loro.getMap("Map");
|
||||
/// const tree = loro.getTree("tree");
|
||||
/// ```
|
||||
///
|
||||
// When FinalizationRegistry is unavailable, it's the users' responsibility to free the document.
|
||||
#[wasm_bindgen]
|
||||
pub struct LoroDoc(Arc<LoroDocInner>);
|
||||
|
||||
|
@ -332,7 +330,7 @@ impl ChangeMeta {
|
|||
impl LoroDoc {
|
||||
/// Create a new loro document.
|
||||
///
|
||||
/// New document will have random peer id.
|
||||
/// New document will have a random peer id.
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
let doc = LoroDocInner::new();
|
||||
|
@ -372,12 +370,12 @@ impl LoroDoc {
|
|||
|
||||
/// Set whether to record the timestamp of each change. Default is `false`.
|
||||
///
|
||||
/// If enabled, the Unix timestamp will be recorded for each change automatically.
|
||||
/// If enabled, the Unix timestamp (in seconds) will be recorded for each change automatically.
|
||||
///
|
||||
/// You can also set each timestamp manually when you commit a change.
|
||||
/// The timestamp manually set will override the automatic one.
|
||||
///
|
||||
/// NOTE: Timestamps are forced to be in ascending order.
|
||||
/// NOTE: Timestamps are forced to be in ascending order in the OpLog's history.
|
||||
/// If you commit a new change with a timestamp that is less than the existing one,
|
||||
/// the largest existing timestamp will be used instead.
|
||||
#[wasm_bindgen(js_name = "setRecordTimestamp")]
|
||||
|
@ -387,7 +385,7 @@ impl LoroDoc {
|
|||
|
||||
/// If two continuous local changes are within the interval, they will be merged into one change.
|
||||
///
|
||||
/// The default value is 1_000_000, the default unit is milliseconds.
|
||||
/// The default value is 1_000_000, the default unit is seconds.
|
||||
#[wasm_bindgen(js_name = "setChangeMergeInterval")]
|
||||
pub fn set_change_merge_interval(&self, interval: f64) {
|
||||
self.0.set_change_merge_interval(interval as i64);
|
||||
|
@ -458,15 +456,17 @@ impl LoroDoc {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Get a loro document from the snapshot.
|
||||
/// Create a loro document from the snapshot.
|
||||
///
|
||||
/// @see You can check out what is the snapshot [here](#).
|
||||
/// @see You can learn more [here](https://loro.dev/docs/tutorial/encoding).
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } import "loro-crdt"
|
||||
/// import { LoroDoc } from "loro-crdt"
|
||||
///
|
||||
/// const bytes = /* The bytes encoded from other loro document *\/;
|
||||
/// const doc = new LoroDoc();
|
||||
/// // ...
|
||||
/// const bytes = doc.export({ mode: "snapshot" });
|
||||
/// const loro = LoroDoc.fromSnapshot(bytes);
|
||||
/// ```
|
||||
///
|
||||
|
@ -484,7 +484,7 @@ impl LoroDoc {
|
|||
/// > In a detached state, the document is not editable, and any `import` operations will be
|
||||
/// > recorded in the `OpLog` without being applied to the `DocState`.
|
||||
///
|
||||
/// This method has the same effect as invoking `checkout_to_latest`.
|
||||
/// This method has the same effect as invoking `checkoutToLatest`.
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
|
@ -494,9 +494,9 @@ impl LoroDoc {
|
|||
/// const text = doc.getText("text");
|
||||
/// const frontiers = doc.frontiers();
|
||||
/// text.insert(0, "Hello World!");
|
||||
/// loro.checkout(frontiers);
|
||||
/// doc.checkout(frontiers);
|
||||
/// // you need call `attach()` or `checkoutToLatest()` before changing the doc.
|
||||
/// loro.attach();
|
||||
/// doc.attach();
|
||||
/// text.insert(0, "Hi");
|
||||
/// ```
|
||||
pub fn attach(&mut self) {
|
||||
|
@ -507,11 +507,9 @@ impl LoroDoc {
|
|||
///
|
||||
/// > The document becomes detached during a `checkout` operation.
|
||||
/// > Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`.
|
||||
/// > In a detached state, the document is not editable, and any `import` operations will be
|
||||
/// > In a detached state, the document is not editable by default, and any `import` operations will be
|
||||
/// > recorded in the `OpLog` without being applied to the `DocState`.
|
||||
///
|
||||
/// When `detached`, the document is not editable.
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
|
@ -520,11 +518,11 @@ impl LoroDoc {
|
|||
/// const text = doc.getText("text");
|
||||
/// const frontiers = doc.frontiers();
|
||||
/// text.insert(0, "Hello World!");
|
||||
/// console.log(doc.is_detached()); // false
|
||||
/// loro.checkout(frontiers);
|
||||
/// console.log(doc.is_detached()); // true
|
||||
/// loro.attach();
|
||||
/// console.log(doc.is_detached()); // false
|
||||
/// console.log(doc.isDetached()); // false
|
||||
/// doc.checkout(frontiers);
|
||||
/// console.log(doc.isDetached()); // true
|
||||
/// doc.attach();
|
||||
/// console.log(doc.isDetached()); // false
|
||||
/// ```
|
||||
///
|
||||
#[wasm_bindgen(js_name = "isDetached")]
|
||||
|
@ -543,7 +541,7 @@ impl LoroDoc {
|
|||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// doc.detach();
|
||||
/// console.log(doc.is_detached()); // true
|
||||
/// console.log(doc.isDetached()); // true
|
||||
/// ```
|
||||
pub fn detach(&self) {
|
||||
self.0.detach()
|
||||
|
@ -568,7 +566,7 @@ impl LoroDoc {
|
|||
///
|
||||
/// > The document becomes detached during a `checkout` operation.
|
||||
/// > Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`.
|
||||
/// > In a detached state, the document is not editable, and any `import` operations will be
|
||||
/// > In a detached state, the document is not editable by default, and any `import` operations will be
|
||||
/// > recorded in the `OpLog` without being applied to the `DocState`.
|
||||
///
|
||||
/// This has the same effect as `attach`.
|
||||
|
@ -581,9 +579,9 @@ impl LoroDoc {
|
|||
/// const text = doc.getText("text");
|
||||
/// const frontiers = doc.frontiers();
|
||||
/// text.insert(0, "Hello World!");
|
||||
/// loro.checkout(frontiers);
|
||||
/// doc.checkout(frontiers);
|
||||
/// // you need call `checkoutToLatest()` or `attach()` before changing the doc.
|
||||
/// loro.checkoutToLatest();
|
||||
/// doc.checkoutToLatest();
|
||||
/// text.insert(0, "Hi");
|
||||
/// ```
|
||||
#[wasm_bindgen(js_name = "checkoutToLatest")]
|
||||
|
@ -592,7 +590,10 @@ impl LoroDoc {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Visit all the ancestors of the changes in causal order.
|
||||
///
|
||||
/// @param ids - the changes to visit
|
||||
/// @param f - the callback function, return `true` to continue visiting, return `false` to stop
|
||||
#[wasm_bindgen(js_name = "travelChangeAncestors")]
|
||||
pub fn travel_change_ancestors(&self, ids: Vec<JsID>, f: js_sys::Function) -> JsResult<()> {
|
||||
let observer = observer::Observer::new(f);
|
||||
|
@ -652,7 +653,7 @@ impl LoroDoc {
|
|||
/// const text = doc.getText("text");
|
||||
/// const frontiers = doc.frontiers();
|
||||
/// text.insert(0, "Hello World!");
|
||||
/// loro.checkout(frontiers);
|
||||
/// doc.checkout(frontiers);
|
||||
/// console.log(doc.toJSON()); // {"text": ""}
|
||||
/// ```
|
||||
pub fn checkout(&mut self, frontiers: Vec<JsID>) -> JsResult<()> {
|
||||
|
@ -690,7 +691,8 @@ impl LoroDoc {
|
|||
///
|
||||
/// You can specify the `origin`, `timestamp`, and `message` of the commit.
|
||||
///
|
||||
/// The `origin` is used to mark the event, and the `message` works like a git commit message.
|
||||
/// - The `origin` is used to mark the event
|
||||
/// - The `message` works like a git commit message, which will be recorded and synced to peers
|
||||
///
|
||||
/// The events will be emitted after a transaction is committed. A transaction is committed when:
|
||||
///
|
||||
|
@ -984,7 +986,7 @@ impl LoroDoc {
|
|||
Ok(ans)
|
||||
}
|
||||
|
||||
/// Get the encoded version vector of the current document.
|
||||
/// Get the version vector of the current document state.
|
||||
///
|
||||
/// If you checkout to a specific version, the version vector will change.
|
||||
#[inline(always)]
|
||||
|
@ -1020,15 +1022,15 @@ impl LoroDoc {
|
|||
frontiers_to_ids(&self.0.shallow_since_frontiers())
|
||||
}
|
||||
|
||||
/// Get the encoded version vector of the latest version in OpLog.
|
||||
/// Get the version vector of the latest known version in OpLog.
|
||||
///
|
||||
/// If you checkout to a specific version, the version vector will not change.
|
||||
/// If you checkout to a specific version, this version vector will not change.
|
||||
#[wasm_bindgen(js_name = "oplogVersion")]
|
||||
pub fn oplog_version(&self) -> VersionVector {
|
||||
VersionVector(self.0.oplog_vv())
|
||||
}
|
||||
|
||||
/// Get the frontiers of the current document.
|
||||
/// Get the [frontiers](https://loro.dev/docs/advanced/version_deep_dive) of the current document state.
|
||||
///
|
||||
/// If you checkout to a specific version, this value will change.
|
||||
#[inline]
|
||||
|
@ -1036,7 +1038,7 @@ impl LoroDoc {
|
|||
frontiers_to_ids(&self.0.state_frontiers())
|
||||
}
|
||||
|
||||
/// Get the frontiers of the latest version in OpLog.
|
||||
/// Get the [frontiers](https://loro.dev/docs/advanced/version_deep_dive) of the latest version in OpLog.
|
||||
///
|
||||
/// If you checkout to a specific version, this value will not change.
|
||||
#[inline(always)]
|
||||
|
@ -1102,8 +1104,8 @@ impl LoroDoc {
|
|||
}
|
||||
}
|
||||
|
||||
/// Export the snapshot of current version, it's include all content of
|
||||
/// operations and states
|
||||
/// Export the snapshot of current version.
|
||||
/// It includes all the history and the document state
|
||||
///
|
||||
/// @deprecated Use `export({mode: "snapshot"})` instead
|
||||
#[wasm_bindgen(js_name = "exportSnapshot")]
|
||||
|
@ -1141,7 +1143,7 @@ impl LoroDoc {
|
|||
///
|
||||
/// @param mode - The export mode to use. Can be one of:
|
||||
/// - `{ mode: "snapshot" }`: Export a full snapshot of the document.
|
||||
/// - `{ mode: "update", from: VersionVector }`: Export updates from the given version vector.
|
||||
/// - `{ mode: "update", from?: VersionVector }`: Export updates from the given version vector.
|
||||
/// - `{ mode: "updates-in-range", spans: { id: ID, len: number }[] }`: Export updates within the specified ID spans.
|
||||
/// - `{ mode: "shallow-snapshot", frontiers: Frontiers }`: Export a garbage-collected snapshot up to the given frontiers.
|
||||
///
|
||||
|
@ -1149,34 +1151,36 @@ impl LoroDoc {
|
|||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
/// import { LoroDoc, LoroText } from "loro-crdt";
|
||||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// doc.setText("text", "Hello World");
|
||||
/// doc.setPeerId("1");
|
||||
/// doc.getText("text").update("Hello World");
|
||||
///
|
||||
/// // Export a full snapshot
|
||||
/// const snapshotBytes = doc.export({ mode: "snapshot" });
|
||||
///
|
||||
/// // Export updates from a specific version
|
||||
/// const vv = doc.oplogVersion();
|
||||
/// doc.setText("text", "Hello Loro");
|
||||
/// doc.getText("text").update("Hello Loro");
|
||||
/// const updateBytes = doc.export({ mode: "update", from: vv });
|
||||
///
|
||||
/// // Export a garbage-collected snapshot
|
||||
/// const gcBytes = doc.export({ mode: "shallow-snapshot", frontiers: doc.oplogFrontiers() });
|
||||
/// // Export a shallow snapshot that only includes the history since the frontiers
|
||||
/// const shallowBytes = doc.export({ mode: "shallow-snapshot", frontiers: doc.oplogFrontiers() });
|
||||
///
|
||||
/// // Export updates within specific ID spans
|
||||
/// const spanBytes = doc.export({
|
||||
/// mode: "updates-in-range",
|
||||
/// spans: [{ id: "1", len: 10 }, { id: "2", len: 5 }]
|
||||
/// spans: [{ id: { peer: "1", counter: 0 }, len: 10 }]
|
||||
/// });
|
||||
/// ```
|
||||
pub fn export(&self, mode: JsExportMode) -> JsResult<Vec<u8>> {
|
||||
let export_mode = js_to_export_mode(mode)?;
|
||||
let export_mode = js_to_export_mode(mode)
|
||||
.map_err(|e| JsValue::from_str(&format!("Invalid export mode. Error: {:?}", e)))?;
|
||||
Ok(self.0.export(export_mode)?)
|
||||
}
|
||||
|
||||
/// Export updates from the specific version to the current version with JSON format.
|
||||
/// Export updates in the given range in JSON format.
|
||||
#[wasm_bindgen(js_name = "exportJsonUpdates")]
|
||||
pub fn export_json_updates(
|
||||
&self,
|
||||
|
@ -1218,7 +1222,7 @@ impl LoroDoc {
|
|||
Ok(import_status_to_js_value(status).into())
|
||||
}
|
||||
|
||||
/// Import a snapshot or a update to current doc.
|
||||
/// Import snapshot or updates into current doc.
|
||||
///
|
||||
/// Note:
|
||||
/// - Updates within the current version will be ignored
|
||||
|
@ -1232,8 +1236,8 @@ impl LoroDoc {
|
|||
/// const text = doc.getText("text");
|
||||
/// text.insert(0, "Hello");
|
||||
/// // get all updates of the doc
|
||||
/// const updates = doc.exportFrom();
|
||||
/// const snapshot = doc.exportSnapshot();
|
||||
/// const updates = doc.export({ mode: "update" });
|
||||
/// const snapshot = doc.export({ mode: "snapshot" });
|
||||
/// const doc2 = new LoroDoc();
|
||||
/// // import snapshot
|
||||
/// doc2.import(snapshot);
|
||||
|
@ -1256,8 +1260,8 @@ impl LoroDoc {
|
|||
/// const doc = new LoroDoc();
|
||||
/// const text = doc.getText("text");
|
||||
/// text.insert(0, "Hello");
|
||||
/// const updates = doc.exportFrom();
|
||||
/// const snapshot = doc.exportSnapshot();
|
||||
/// const updates = doc.export({ mode: "update" });
|
||||
/// const snapshot = doc.export({ mode: "snapshot" });
|
||||
/// const doc2 = new LoroDoc();
|
||||
/// doc2.importUpdateBatch([snapshot, updates]);
|
||||
/// ```
|
||||
|
@ -1286,7 +1290,7 @@ impl LoroDoc {
|
|||
/// const list = doc.getList("list");
|
||||
/// const tree = doc.getTree("tree");
|
||||
/// const map = doc.getMap("map");
|
||||
/// const shallowValue = doc.toShallowJSON();
|
||||
/// const shallowValue = doc.getShallowValue();
|
||||
/// /*
|
||||
/// {"list": ..., "tree": ..., "map": ...}
|
||||
/// *\/
|
||||
|
@ -1298,11 +1302,11 @@ impl LoroDoc {
|
|||
Ok(json.into())
|
||||
}
|
||||
|
||||
/// Get the json format of the document state.
|
||||
/// Get the json format of the entire document state.
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
/// import { LoroDoc, LoroText, LoroMap } from "loro-crdt";
|
||||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// const list = doc.getList("list");
|
||||
|
@ -1323,14 +1327,14 @@ impl LoroDoc {
|
|||
}
|
||||
|
||||
/// Subscribe to the changes of the loro document. The function will be called when the
|
||||
/// transaction is committed or updates from remote are imported.
|
||||
/// transaction is committed and after importing updates/snapshot from remote.
|
||||
///
|
||||
/// Returns a subscription ID, which can be used to unsubscribe.
|
||||
/// Returns a subscription callback, which can be used to unsubscribe.
|
||||
///
|
||||
/// The events will be emitted after a transaction is committed. A transaction is committed when:
|
||||
///
|
||||
/// - `doc.commit()` is called.
|
||||
/// - `doc.exportFrom(version)` is called.
|
||||
/// - `doc.export(mode)` is called.
|
||||
/// - `doc.import(data)` is called.
|
||||
/// - `doc.checkout(version)` is called.
|
||||
///
|
||||
|
@ -1340,12 +1344,14 @@ impl LoroDoc {
|
|||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// const text = doc.getText("text");
|
||||
/// doc.subscribe((event)=>{
|
||||
/// const sub = doc.subscribe((event)=>{
|
||||
/// console.log(event);
|
||||
/// });
|
||||
/// text.insert(0, "Hello");
|
||||
/// // the events will be emitted when `commit()` is called.
|
||||
/// doc.commit();
|
||||
/// // unsubscribe
|
||||
/// sub();
|
||||
/// ```
|
||||
// TODO: convert event and event sub config
|
||||
pub fn subscribe(&self, f: js_sys::Function) -> JsValue {
|
||||
|
@ -1382,20 +1388,22 @@ impl LoroDoc {
|
|||
console_log!("{:#?}", oplog.diagnose_size());
|
||||
}
|
||||
|
||||
/// Get all of changes in the oplog
|
||||
/// Get all of changes in the oplog.
|
||||
///
|
||||
/// Note: this method is expensive when the oplog is large. O(n)
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
/// import { LoroDoc, LoroText } from "loro-crdt";
|
||||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// const text = doc.getText("text");
|
||||
/// text.insert(0, "Hello");
|
||||
/// const changes = doc.getAllChanges();
|
||||
///
|
||||
/// for (let [peer, changes] of changes.entries()){
|
||||
/// for (let [peer, c] of changes.entries()){
|
||||
/// console.log("peer: ", peer);
|
||||
/// for (let change in changes){
|
||||
/// for (let change of c){
|
||||
/// console.log("change: ", change);
|
||||
/// }
|
||||
/// }
|
||||
|
@ -1438,7 +1446,7 @@ impl LoroDoc {
|
|||
value.into()
|
||||
}
|
||||
|
||||
/// Get the change of a specific ID
|
||||
/// Get the change that contains the specific ID
|
||||
#[wasm_bindgen(js_name = "getChangeAt")]
|
||||
pub fn get_change_at(&self, id: JsID) -> JsResult<JsChange> {
|
||||
let id = js_id_to_id(id)?;
|
||||
|
@ -1500,7 +1508,7 @@ impl LoroDoc {
|
|||
Ok(change.to_js().into())
|
||||
}
|
||||
|
||||
/// Get all ops of the change of a specific ID
|
||||
/// Get all ops of the change that contains the specific ID
|
||||
#[wasm_bindgen(js_name = "getOpsInChange")]
|
||||
pub fn get_ops_in_change(&self, id: JsID) -> JsResult<Vec<JsValue>> {
|
||||
let id = js_id_to_id(id)?;
|
||||
|
@ -1517,7 +1525,9 @@ impl LoroDoc {
|
|||
Ok(ops)
|
||||
}
|
||||
|
||||
/// Convert frontiers to a readable version vector
|
||||
/// Convert frontiers to a version vector
|
||||
///
|
||||
/// Learn more about frontiers and version vector [here](https://loro.dev/docs/advanced/version_deep_dive)
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
|
@ -1730,34 +1740,6 @@ fn convert_container_path_to_js_value(path: &[(ContainerID, Index)]) -> Array {
|
|||
|
||||
/// The handler of a text container. It supports rich text CRDT.
|
||||
///
|
||||
/// ## Updating Text Content Using a Diff Algorithm
|
||||
///
|
||||
/// A common requirement is to update the current text to a target text.
|
||||
/// You can implement this using a text diff algorithm of your choice.
|
||||
/// Below is a sample you can directly copy into your code, which uses the
|
||||
/// [fast-diff](https://www.npmjs.com/package/fast-diff) package.
|
||||
///
|
||||
/// ```ts
|
||||
/// import { diff } from "fast-diff";
|
||||
/// import { LoroText } from "loro-crdt";
|
||||
///
|
||||
/// function updateText(text: LoroText, newText: string) {
|
||||
/// const src = text.toString();
|
||||
/// const delta = diff(src, newText);
|
||||
/// let index = 0;
|
||||
/// for (const [op, text] of delta) {
|
||||
/// if (op === 0) {
|
||||
/// index += text.length;
|
||||
/// } else if (op === 1) {
|
||||
/// text.insert(index, text);
|
||||
/// index += text.length;
|
||||
/// } else {
|
||||
/// text.delete(index, text.length);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// Learn more at https://loro.dev/docs/tutorial/text
|
||||
#[derive(Clone)]
|
||||
#[wasm_bindgen]
|
||||
|
@ -1775,7 +1757,7 @@ struct MarkRange {
|
|||
|
||||
#[wasm_bindgen]
|
||||
impl LoroText {
|
||||
/// Create a new detached LoroText.
|
||||
/// Create a new detached LoroText (not attached to any LoroDoc).
|
||||
///
|
||||
/// The edits on a detached container will not be persisted.
|
||||
/// To attach the container to the document, please insert it into an attached container.
|
||||
|
@ -1815,7 +1797,13 @@ impl LoroText {
|
|||
})
|
||||
}
|
||||
|
||||
/// Update the current text based on the provided text.
|
||||
/// Update the current text to the target text.
|
||||
///
|
||||
/// It will calculate the minimal difference and apply it to the current text.
|
||||
/// It uses Myers' diff algorithm to compute the optimal difference.
|
||||
///
|
||||
/// This could take a long time for large texts (e.g. > 50_000 characters).
|
||||
/// In that case, you should use `updateByLine` instead.
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
|
@ -1825,18 +1813,21 @@ impl LoroText {
|
|||
/// const text = doc.getText("text");
|
||||
/// text.insert(0, "Hello");
|
||||
/// text.update("Hello World");
|
||||
/// console.log(text.toString()); // "Hello World"
|
||||
/// ```
|
||||
pub fn update(&self, text: &str) {
|
||||
self.handler.update(text);
|
||||
}
|
||||
|
||||
/// Update the current text based on the provided text line by line.
|
||||
/// Update the current text to the target text, the difference is calculated line by line.
|
||||
///
|
||||
/// It uses Myers' diff algorithm to compute the optimal difference.
|
||||
#[wasm_bindgen(js_name = "updateByLine")]
|
||||
pub fn update_by_line(&self, text: &str) {
|
||||
self.handler.update_by_line(text);
|
||||
}
|
||||
|
||||
/// Insert some string at index.
|
||||
/// Insert the string at the given index (utf-16 index).
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
|
@ -1851,7 +1842,7 @@ impl LoroText {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Get a string slice.
|
||||
/// Get a string slice (utf-16 index).
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
|
@ -1869,7 +1860,7 @@ impl LoroText {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the character at the given position.
|
||||
/// Get the character at the given position (utf-16 index).
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
|
@ -1888,7 +1879,7 @@ impl LoroText {
|
|||
}
|
||||
}
|
||||
|
||||
/// Delete and return the string at the given range and insert a string at the same position.
|
||||
/// Delete and return the string at the given range and insert a string at the same position (utf-16 index).
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
|
@ -1922,7 +1913,7 @@ impl LoroText {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Delete elements from index to index + len
|
||||
/// Delete elements from index to index + len (utf-16 index).
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
|
@ -1959,7 +1950,7 @@ impl LoroText {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Mark a range of text with a key and a value.
|
||||
/// Mark a range of text with a key and a value (utf-16 index).
|
||||
///
|
||||
/// > You should call `configTextStyle` before using `mark` and `unmark`.
|
||||
///
|
||||
|
@ -1984,7 +1975,7 @@ impl LoroText {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Unmark a range of text with a key and a value.
|
||||
/// Unmark a range of text with a key and a value (utf-16 index).
|
||||
///
|
||||
/// > You should call `configTextStyle` before using `mark` and `unmark`.
|
||||
///
|
||||
|
@ -2008,7 +1999,7 @@ impl LoroText {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Convert the state to string
|
||||
/// Convert the text to a string
|
||||
#[allow(clippy::inherent_to_string)]
|
||||
#[wasm_bindgen(js_name = "toString")]
|
||||
pub fn to_string(&self) -> String {
|
||||
|
@ -2053,7 +2044,7 @@ impl LoroText {
|
|||
value.into()
|
||||
}
|
||||
|
||||
/// Get the length of text
|
||||
/// Get the length of text (utf-16 length).
|
||||
#[wasm_bindgen(js_name = "length", method, getter)]
|
||||
pub fn length(&self) -> usize {
|
||||
self.handler.len_utf16()
|
||||
|
@ -2064,11 +2055,11 @@ impl LoroText {
|
|||
/// The events will be emitted after a transaction is committed. A transaction is committed when:
|
||||
///
|
||||
/// - `doc.commit()` is called.
|
||||
/// - `doc.exportFrom(version)` is called.
|
||||
/// - `doc.export(mode)` is called.
|
||||
/// - `doc.import(data)` is called.
|
||||
/// - `doc.checkout(version)` is called.
|
||||
///
|
||||
/// returns a subscription id, which can be used to unsubscribe.
|
||||
/// returns a subscription callback, which can be used to unsubscribe.
|
||||
pub fn subscribe(&self, f: js_sys::Function) -> JsResult<JsValue> {
|
||||
let observer = observer::Observer::new(f);
|
||||
let doc = self
|
||||
|
@ -2100,8 +2091,6 @@ impl LoroText {
|
|||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// const text = doc.getText("text");
|
||||
/// doc.configTextStyle({bold: {expand: "after"}});
|
||||
|
@ -2121,7 +2110,7 @@ impl LoroText {
|
|||
|
||||
/// Get the parent container.
|
||||
///
|
||||
/// - The parent container of the root tree is `undefined`.
|
||||
/// - The parent of the root is `undefined`.
|
||||
/// - The object returned is a new js object each time because it need to cross
|
||||
/// the WASM boundary.
|
||||
pub fn parent(&self) -> JsContainerOrUndefined {
|
||||
|
@ -2132,7 +2121,7 @@ impl LoroText {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether the container is attached to a document.
|
||||
/// Whether the container is attached to a LoroDoc.
|
||||
///
|
||||
/// If it's detached, the operations on the container will not be persisted.
|
||||
#[wasm_bindgen(js_name = "isAttached")]
|
||||
|
@ -2142,7 +2131,7 @@ impl LoroText {
|
|||
|
||||
/// Get the attached container associated with this.
|
||||
///
|
||||
/// Returns an attached `Container` that equals to this or created by this, otherwise `undefined`.
|
||||
/// Returns an attached `Container` that is equal to this or created by this; otherwise, it returns `undefined`.
|
||||
#[wasm_bindgen(js_name = "getAttached")]
|
||||
pub fn get_attached(&self) -> JsLoroTextOrUndefined {
|
||||
if self.is_attached() {
|
||||
|
@ -2157,7 +2146,10 @@ impl LoroText {
|
|||
}
|
||||
}
|
||||
|
||||
/// get the cursor at the given position.
|
||||
/// Get the cursor at the given position.
|
||||
///
|
||||
/// - The first argument is the position (utf16-index).
|
||||
/// - The second argument is the side: `-1` for left, `0` for middle, `1` for right.
|
||||
#[wasm_bindgen(skip_typescript)]
|
||||
pub fn getCursor(&self, pos: usize, side: JsSide) -> Option<Cursor> {
|
||||
let mut side_value = Side::Middle;
|
||||
|
@ -2189,7 +2181,7 @@ pub struct LoroMap {
|
|||
|
||||
#[wasm_bindgen]
|
||||
impl LoroMap {
|
||||
/// Create a new detached LoroMap.
|
||||
/// Create a new detached LoroMap (not attached to any LoroDoc).
|
||||
///
|
||||
/// The edits on a detached container will not be persisted.
|
||||
/// To attach the container to the document, please insert it into an attached container.
|
||||
|
@ -2369,14 +2361,14 @@ impl LoroMap {
|
|||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
/// import { LoroDoc, LoroText } from "loro-crdt";
|
||||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// const map = doc.getMap("map");
|
||||
/// map.set("foo", "bar");
|
||||
/// const text = map.setContainer("text", new LoroText());
|
||||
/// text.insert(0, "Hello");
|
||||
/// console.log(map.getDeepValue()); // {"foo": "bar", "text": "Hello"}
|
||||
/// console.log(map.toJSON()); // {"foo": "bar", "text": "Hello"}
|
||||
/// ```
|
||||
#[wasm_bindgen(js_name = "toJSON")]
|
||||
pub fn to_json(&self) -> JsValue {
|
||||
|
@ -2387,7 +2379,7 @@ impl LoroMap {
|
|||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
/// import { LoroDoc, LoroText } from "loro-crdt";
|
||||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// const map = doc.getMap("map");
|
||||
|
@ -2404,12 +2396,12 @@ impl LoroMap {
|
|||
|
||||
/// Subscribe to the changes of the map.
|
||||
///
|
||||
/// Returns a subscription id, which can be used to unsubscribe.
|
||||
/// Returns a subscription callback, which can be used to unsubscribe.
|
||||
///
|
||||
/// The events will be emitted after a transaction is committed. A transaction is committed when:
|
||||
///
|
||||
/// - `doc.commit()` is called.
|
||||
/// - `doc.exportFrom(version)` is called.
|
||||
/// - `doc.export(mode)` is called.
|
||||
/// - `doc.import(data)` is called.
|
||||
/// - `doc.checkout(version)` is called.
|
||||
///
|
||||
|
@ -2522,7 +2514,7 @@ pub struct LoroList {
|
|||
|
||||
#[wasm_bindgen]
|
||||
impl LoroList {
|
||||
/// Create a new detached LoroList.
|
||||
/// Create a new detached LoroList (not attached to any LoroDoc).
|
||||
///
|
||||
/// The edits on a detached container will not be persisted.
|
||||
/// To attach the container to the document, please insert it into an attached container.
|
||||
|
@ -2613,7 +2605,7 @@ impl LoroList {
|
|||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
/// import { LoroDoc, LoroText } from "loro-crdt";
|
||||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// const list = doc.getList("list");
|
||||
|
@ -2646,14 +2638,14 @@ impl LoroList {
|
|||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
/// import { LoroDoc, LoroText } from "loro-crdt";
|
||||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// const list = doc.getList("list");
|
||||
/// list.insert(0, 100);
|
||||
/// const text = list.insertContainer(1, new LoroText());
|
||||
/// text.insert(0, "Hello");
|
||||
/// console.log(list.getDeepValue()); // [100, "Hello"];
|
||||
/// console.log(list.toJSON()); // [100, "Hello"];
|
||||
/// ```
|
||||
#[wasm_bindgen(js_name = "toJSON")]
|
||||
pub fn to_json(&self) -> JsValue {
|
||||
|
@ -2665,14 +2657,14 @@ impl LoroList {
|
|||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
/// import { LoroDoc, LoroText } from "loro-crdt";
|
||||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// const list = doc.getList("list");
|
||||
/// list.insert(0, 100);
|
||||
/// const text = list.insertContainer(1, new LoroText());
|
||||
/// text.insert(0, "Hello");
|
||||
/// console.log(list.getDeepValue()); // [100, "Hello"];
|
||||
/// console.log(list.toJSON()); // [100, "Hello"];
|
||||
/// ```
|
||||
#[wasm_bindgen(js_name = "insertContainer", skip_typescript)]
|
||||
pub fn insert_container(&mut self, index: usize, child: JsContainer) -> JsResult<JsContainer> {
|
||||
|
@ -2683,12 +2675,12 @@ impl LoroList {
|
|||
|
||||
/// Subscribe to the changes of the list.
|
||||
///
|
||||
/// Returns a subscription id, which can be used to unsubscribe.
|
||||
/// Returns a subscription callback, which can be used to unsubscribe.
|
||||
///
|
||||
/// The events will be emitted after a transaction is committed. A transaction is committed when:
|
||||
///
|
||||
/// - `doc.commit()` is called.
|
||||
/// - `doc.exportFrom(version)` is called.
|
||||
/// - `doc.export(mode)` is called.
|
||||
/// - `doc.import(data)` is called.
|
||||
/// - `doc.checkout(version)` is called.
|
||||
///
|
||||
|
@ -2777,6 +2769,9 @@ impl LoroList {
|
|||
}
|
||||
|
||||
/// Get the cursor at the position.
|
||||
///
|
||||
/// - The first argument is the position .
|
||||
/// - The second argument is the side: `-1` for left, `0` for middle, `1` for right.
|
||||
#[wasm_bindgen(skip_typescript)]
|
||||
pub fn getCursor(&self, pos: usize, side: JsSide) -> Option<Cursor> {
|
||||
let mut side_value = Side::Middle;
|
||||
|
@ -2839,7 +2834,7 @@ impl Default for LoroMovableList {
|
|||
|
||||
#[wasm_bindgen]
|
||||
impl LoroMovableList {
|
||||
/// Create a new detached LoroList.
|
||||
/// Create a new detached LoroMovableList (not attached to any LoroDoc).
|
||||
///
|
||||
/// The edits on a detached container will not be persisted.
|
||||
/// To attach the container to the document, please insert it into an attached container.
|
||||
|
@ -2930,7 +2925,7 @@ impl LoroMovableList {
|
|||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
/// import { LoroDoc, LoroText } from "loro-crdt";
|
||||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// const list = doc.getList("list");
|
||||
|
@ -2963,14 +2958,14 @@ impl LoroMovableList {
|
|||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
/// import { LoroDoc, LoroText } from "loro-crdt";
|
||||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// const list = doc.getList("list");
|
||||
/// list.insert(0, 100);
|
||||
/// const text = list.insertContainer(1, new LoroText());
|
||||
/// text.insert(0, "Hello");
|
||||
/// console.log(list.getDeepValue()); // [100, "Hello"];
|
||||
/// console.log(list.toJSON()); // [100, "Hello"];
|
||||
/// ```
|
||||
#[wasm_bindgen(js_name = "toJSON")]
|
||||
pub fn to_json(&self) -> JsValue {
|
||||
|
@ -2982,14 +2977,14 @@ impl LoroMovableList {
|
|||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
/// import { LoroDoc, LoroText } from "loro-crdt";
|
||||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// const list = doc.getList("list");
|
||||
/// list.insert(0, 100);
|
||||
/// const text = list.insertContainer(1, new LoroText());
|
||||
/// text.insert(0, "Hello");
|
||||
/// console.log(list.getDeepValue()); // [100, "Hello"];
|
||||
/// console.log(list.toJSON()); // [100, "Hello"];
|
||||
/// ```
|
||||
#[wasm_bindgen(js_name = "insertContainer", skip_typescript)]
|
||||
pub fn insert_container(&mut self, index: usize, child: JsContainer) -> JsResult<JsContainer> {
|
||||
|
@ -3000,12 +2995,12 @@ impl LoroMovableList {
|
|||
|
||||
/// Subscribe to the changes of the list.
|
||||
///
|
||||
/// Returns a subscription id, which can be used to unsubscribe.
|
||||
/// Returns a subscription callback, which can be used to unsubscribe.
|
||||
///
|
||||
/// The events will be emitted after a transaction is committed. A transaction is committed when:
|
||||
///
|
||||
/// - `doc.commit()` is called.
|
||||
/// - `doc.exportFrom(version)` is called.
|
||||
/// - `doc.export(mode)` is called.
|
||||
/// - `doc.import(data)` is called.
|
||||
/// - `doc.checkout(version)` is called.
|
||||
///
|
||||
|
@ -3271,10 +3266,10 @@ impl LoroTreeNode {
|
|||
/// ```ts
|
||||
/// const doc = new LoroDoc();
|
||||
/// const tree = doc.getTree("tree");
|
||||
/// const root = tree.createChildNode();
|
||||
/// const node = root.createChildNode();
|
||||
/// const node2 = node.createChildNode();
|
||||
/// node2.moveTo(undefined, 0);
|
||||
/// const root = tree.createNode();
|
||||
/// const node = root.createNode();
|
||||
/// const node2 = node.createNode();
|
||||
/// node2.move(undefined, 0);
|
||||
/// // node2 root
|
||||
/// // |
|
||||
/// // node
|
||||
|
@ -3416,7 +3411,7 @@ impl LoroTreeNode {
|
|||
|
||||
#[wasm_bindgen]
|
||||
impl LoroTree {
|
||||
/// Create a new detached LoroTree.
|
||||
/// Create a new detached LoroTree (not attached to any LoroDoc).
|
||||
///
|
||||
/// The edits on a detached container will not be persisted.
|
||||
/// To attach the container to the document, please insert it into an attached container.
|
||||
|
@ -3480,9 +3475,9 @@ impl LoroTree {
|
|||
/// const root = tree.createNode();
|
||||
/// const node = root.createNode();
|
||||
/// const node2 = node.createNode();
|
||||
/// tree.move(node2, root);
|
||||
/// tree.move(node2.id, root.id);
|
||||
/// // Error will be thrown if move operation creates a cycle
|
||||
/// tree.move(root, node);
|
||||
/// // tree.move(root.id, node.id);
|
||||
/// ```
|
||||
#[wasm_bindgen(js_name = "move")]
|
||||
pub fn mov(
|
||||
|
@ -3677,7 +3672,7 @@ impl LoroTree {
|
|||
|
||||
/// Subscribe to the changes of the tree.
|
||||
///
|
||||
/// Returns a subscription id, which can be used to unsubscribe.
|
||||
/// Returns a subscription callback, which can be used to unsubscribe.
|
||||
///
|
||||
/// Trees have three types of events: `create`, `delete`, and `move`.
|
||||
/// - `create`: Creates a new node with its `target` TreeID. If `parent` is undefined,
|
||||
|
@ -3695,7 +3690,7 @@ impl LoroTree {
|
|||
/// The events will be emitted after a transaction is committed. A transaction is committed when:
|
||||
///
|
||||
/// - `doc.commit()` is called.
|
||||
/// - `doc.exportFrom(version)` is called.
|
||||
/// - `doc.export(mode)` is called.
|
||||
/// - `doc.import(data)` is called.
|
||||
/// - `doc.checkout(version)` is called.
|
||||
///
|
||||
|
@ -3766,12 +3761,14 @@ impl LoroTree {
|
|||
}
|
||||
}
|
||||
|
||||
/// Set whether to generate fractional index for Tree Position.
|
||||
/// Set whether to generate a fractional index for moving and creating.
|
||||
///
|
||||
/// The jitter is used to avoid conflicts when multiple users are creating the node at the same position.
|
||||
/// value 0 is default, which means no jitter, any value larger than 0 will enable jitter.
|
||||
/// A fractional index can be used to determine the position of tree nodes among their siblings.
|
||||
///
|
||||
/// Generally speaking, jitter will affect the growth rate of document size.
|
||||
/// The jitter is used to avoid conflicts when multiple users are creating a node at the same position.
|
||||
/// A value of 0 is the default, which means no jitter; any value larger than 0 will enable jitter.
|
||||
///
|
||||
/// Generally speaking, higher jitter value will increase the size of the operation
|
||||
/// [Read more about it](https://www.loro.dev/blog/movable-tree#implementation-and-encoding-size)
|
||||
#[wasm_bindgen(js_name = "enableFractionalIndex")]
|
||||
pub fn enable_fractional_index(&self, jitter: u8) {
|
||||
|
@ -3779,7 +3776,7 @@ impl LoroTree {
|
|||
}
|
||||
|
||||
/// Disable the fractional index generation for Tree Position when
|
||||
/// you don't need the Tree's siblings to be sorted. The fractional index will be always default.
|
||||
/// you don't need the Tree's siblings to be sorted. The fractional index will always be set to default.
|
||||
#[wasm_bindgen(js_name = "disableFractionalIndex")]
|
||||
pub fn disable_fractional_index(&self) {
|
||||
self.handler.disable_fractional_index();
|
||||
|
@ -4385,13 +4382,12 @@ const TYPES: &'static str = r#"
|
|||
* It is most commonly used to specify the type of sub-container to be created.
|
||||
* @example
|
||||
* ```ts
|
||||
* import { LoroDoc } from "loro-crdt";
|
||||
* import { LoroDoc, LoroText } from "loro-crdt";
|
||||
*
|
||||
* const doc = new LoroDoc();
|
||||
* const list = doc.getList("list");
|
||||
* list.insert(0, 100);
|
||||
* const containerType = "Text";
|
||||
* const text = list.insertContainer(1, containerType);
|
||||
* const text = list.insertContainer(1, new LoroText());
|
||||
* ```
|
||||
*/
|
||||
export type ContainerType = "Text" | "Map" | "List"| "Tree" | "MovableList";
|
||||
|
|
|
@ -195,7 +195,7 @@ impl LoroDoc {
|
|||
self.doc.is_detached_editing_enabled()
|
||||
}
|
||||
|
||||
/// Set the interval of mergeable changes, in milliseconds.
|
||||
/// Set the interval of mergeable changes, in seconds.
|
||||
///
|
||||
/// If two continuous local changes are within the interval, they will be merged into one change.
|
||||
/// The default value is 1000 seconds.
|
||||
|
@ -229,10 +229,10 @@ impl LoroDoc {
|
|||
|
||||
/// Checkout the `DocState` to a specific version.
|
||||
///
|
||||
/// > The document becomes detached during a `checkout` operation.
|
||||
/// > Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`.
|
||||
/// > In a detached state, the document is not editable, and any `import` operations will be
|
||||
/// > recorded in the `OpLog` without being applied to the `DocState`.
|
||||
/// The document becomes detached during a `checkout` operation.
|
||||
/// Being `detached` implies that the `DocState` is not synchronized with the latest version of the `OpLog`.
|
||||
/// In a detached state, the document is not editable, and any `import` operations will be
|
||||
/// recorded in the `OpLog` without being applied to the `DocState`.
|
||||
///
|
||||
/// You should call `attach` to attach the `DocState` to the latest version of `OpLog`.
|
||||
#[inline]
|
||||
|
@ -358,7 +358,7 @@ impl LoroDoc {
|
|||
/// The events will be emitted after a transaction is committed. A transaction is committed when:
|
||||
///
|
||||
/// - `doc.commit()` is called.
|
||||
/// - `doc.exportFrom(version)` is called.
|
||||
/// - `doc.export(mode)` is called.
|
||||
/// - `doc.import(data)` is called.
|
||||
/// - `doc.checkout(version)` is called.
|
||||
#[inline]
|
||||
|
@ -485,7 +485,7 @@ impl LoroDoc {
|
|||
self.doc.oplog_vv()
|
||||
}
|
||||
|
||||
/// Get the `VersionVector` version of `OpLog`
|
||||
/// Get the `VersionVector` version of `DocState`
|
||||
#[inline]
|
||||
pub fn state_vv(&self) -> VersionVector {
|
||||
self.doc.state_vv()
|
||||
|
@ -529,13 +529,13 @@ impl LoroDoc {
|
|||
self.doc.get_value()
|
||||
}
|
||||
|
||||
/// Get the current state of the document.
|
||||
/// Get the entire state of the current DocState
|
||||
#[inline]
|
||||
pub fn get_deep_value(&self) -> LoroValue {
|
||||
self.doc.get_deep_value()
|
||||
}
|
||||
|
||||
/// Get the current state with container id of the doc
|
||||
/// Get the entire state of the current DocState with container id
|
||||
pub fn get_deep_value_with_id(&self) -> LoroValue {
|
||||
self.doc
|
||||
.app_state()
|
||||
|
@ -552,7 +552,7 @@ impl LoroDoc {
|
|||
|
||||
/// Get the `Frontiers` version of `DocState`
|
||||
///
|
||||
/// [Learn more about `Frontiers`]()
|
||||
/// Learn more about [`Frontiers`](https://loro.dev/docs/advanced/version_deep_dive)
|
||||
#[inline]
|
||||
pub fn state_frontiers(&self) -> Frontiers {
|
||||
self.doc.state_frontiers()
|
||||
|
@ -566,7 +566,7 @@ impl LoroDoc {
|
|||
|
||||
/// Change the PeerID
|
||||
///
|
||||
/// NOTE: You need ot make sure there is no chance two peer have the same PeerID.
|
||||
/// NOTE: You need to make sure there is no chance two peer have the same PeerID.
|
||||
/// If it happens, the document will be corrupted.
|
||||
#[inline]
|
||||
pub fn set_peer_id(&self, peer: PeerID) -> LoroResult<()> {
|
||||
|
@ -576,12 +576,12 @@ impl LoroDoc {
|
|||
/// Subscribe the events of a container.
|
||||
///
|
||||
/// The callback will be invoked after a transaction that change the container.
|
||||
/// Returns a subscription id that can be used to unsubscribe.
|
||||
/// Returns a subscription that can be used to unsubscribe.
|
||||
///
|
||||
/// The events will be emitted after a transaction is committed. A transaction is committed when:
|
||||
///
|
||||
/// - `doc.commit()` is called.
|
||||
/// - `doc.exportFrom(version)` is called.
|
||||
/// - `doc.export(mode)` is called.
|
||||
/// - `doc.import(data)` is called.
|
||||
/// - `doc.checkout(version)` is called.
|
||||
///
|
||||
|
@ -614,6 +614,8 @@ impl LoroDoc {
|
|||
/// text.insert(0, "123").unwrap();
|
||||
/// doc.commit();
|
||||
/// assert!(ran.load(std::sync::atomic::Ordering::Relaxed));
|
||||
/// // unsubscribe
|
||||
/// sub.unsubscribe();
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn subscribe(&self, container_id: &ContainerID, callback: Subscriber) -> Subscription {
|
||||
|
@ -628,12 +630,12 @@ impl LoroDoc {
|
|||
/// Subscribe all the events.
|
||||
///
|
||||
/// The callback will be invoked when any part of the [loro_internal::DocState] is changed.
|
||||
/// Returns a subscription id that can be used to unsubscribe.
|
||||
/// Returns a subscription that can be used to unsubscribe.
|
||||
///
|
||||
/// The events will be emitted after a transaction is committed. A transaction is committed when:
|
||||
///
|
||||
/// - `doc.commit()` is called.
|
||||
/// - `doc.exportFrom(version)` is called.
|
||||
/// - `doc.export(mode)` is called.
|
||||
/// - `doc.import(data)` is called.
|
||||
/// - `doc.checkout(version)` is called.
|
||||
#[inline]
|
||||
|
@ -2266,7 +2268,7 @@ impl ContainerTrait for LoroUnknown {
|
|||
|
||||
use enum_as_inner::EnumAsInner;
|
||||
|
||||
/// All the CRDT containers supported by loro.
|
||||
/// All the CRDT containers supported by Loro.
|
||||
#[derive(Clone, Debug, EnumAsInner)]
|
||||
pub enum Container {
|
||||
/// [LoroList container](https://loro.dev/docs/tutorial/list)
|
||||
|
|
|
@ -3,23 +3,23 @@ export type * from "loro-wasm";
|
|||
import {
|
||||
Container,
|
||||
ContainerID,
|
||||
ContainerType,
|
||||
Delta,
|
||||
LoroCounter,
|
||||
LoroDoc,
|
||||
LoroList,
|
||||
LoroMap,
|
||||
LoroText,
|
||||
LoroTree,
|
||||
LoroCounter,
|
||||
OpId,
|
||||
TreeID,
|
||||
Value,
|
||||
ContainerType,
|
||||
} from "loro-wasm";
|
||||
|
||||
/**
|
||||
* @deprecated Please use LoroDoc
|
||||
*/
|
||||
export class Loro extends LoroDoc { }
|
||||
export class Loro extends LoroDoc {}
|
||||
export { Awareness } from "./awareness";
|
||||
|
||||
export type Frontiers = OpId[];
|
||||
|
@ -97,7 +97,12 @@ export type TreeDiffItem =
|
|||
index: number;
|
||||
fractionalIndex: string;
|
||||
}
|
||||
| { target: TreeID; action: "delete"; oldParent: TreeID | undefined; oldIndex: number }
|
||||
| {
|
||||
target: TreeID;
|
||||
action: "delete";
|
||||
oldParent: TreeID | undefined;
|
||||
oldIndex: number;
|
||||
}
|
||||
| {
|
||||
target: TreeID;
|
||||
action: "move";
|
||||
|
@ -116,7 +121,7 @@ export type TreeDiff = {
|
|||
export type CounterDiff = {
|
||||
type: "counter";
|
||||
increment: number;
|
||||
}
|
||||
};
|
||||
|
||||
export type Diff = ListDiff | TextDiff | MapDiff | TreeDiff | CounterDiff;
|
||||
|
||||
|
@ -124,7 +129,14 @@ interface Listener {
|
|||
(event: LoroEventBatch): void;
|
||||
}
|
||||
|
||||
const CONTAINER_TYPES = ["Map", "Text", "List", "Tree", "MovableList", "Counter"];
|
||||
const CONTAINER_TYPES = [
|
||||
"Map",
|
||||
"Text",
|
||||
"List",
|
||||
"Tree",
|
||||
"MovableList",
|
||||
"Counter",
|
||||
];
|
||||
|
||||
export function isContainerId(s: string): s is ContainerID {
|
||||
return s.startsWith("cid:");
|
||||
|
@ -145,6 +157,7 @@ export function isContainerId(s: string): s is ContainerID {
|
|||
* isContainer(123); // false
|
||||
* isContainer("123"); // false
|
||||
* isContainer({}); // false
|
||||
* ```
|
||||
*/
|
||||
export function isContainer(value: any): value is Container {
|
||||
if (typeof value !== "object" || value == null) {
|
||||
|
@ -178,14 +191,10 @@ export function isContainer(value: any): value is Container {
|
|||
*/
|
||||
export function getType<T>(
|
||||
value: T,
|
||||
): T extends LoroText
|
||||
? "Text"
|
||||
: T extends LoroMap<any>
|
||||
? "Map"
|
||||
: T extends LoroTree<any>
|
||||
? "Tree"
|
||||
: T extends LoroList<any>
|
||||
? "List"
|
||||
): T extends LoroText ? "Text"
|
||||
: T extends LoroMap<any> ? "Map"
|
||||
: T extends LoroTree<any> ? "Tree"
|
||||
: T extends LoroList<any> ? "List"
|
||||
: T extends LoroCounter ? "Counter"
|
||||
: "Json" {
|
||||
if (isContainer(value)) {
|
||||
|
@ -293,14 +302,14 @@ declare module "loro-wasm" {
|
|||
}
|
||||
|
||||
interface LoroList<T = unknown> {
|
||||
new(): LoroList<T>;
|
||||
new (): LoroList<T>;
|
||||
/**
|
||||
* Get elements of the list. If the value is a child container, the corresponding
|
||||
* `Container` will be returned.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { LoroDoc } from "loro-crdt";
|
||||
* import { LoroDoc, LoroText } from "loro-crdt";
|
||||
*
|
||||
* const doc = new LoroDoc();
|
||||
* const list = doc.getList("list");
|
||||
|
@ -369,7 +378,7 @@ declare module "loro-wasm" {
|
|||
}
|
||||
|
||||
interface LoroMovableList<T = unknown> {
|
||||
new(): LoroMovableList<T>;
|
||||
new (): LoroMovableList<T>;
|
||||
/**
|
||||
* Get elements of the list. If the value is a child container, the corresponding
|
||||
* `Container` will be returned.
|
||||
|
@ -393,7 +402,7 @@ declare module "loro-wasm" {
|
|||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { LoroDoc } from "loro-crdt";
|
||||
* import { LoroDoc, LoroText } from "loro-crdt";
|
||||
*
|
||||
* const doc = new LoroDoc();
|
||||
* const list = doc.getMovableList("list");
|
||||
|
@ -458,7 +467,7 @@ declare module "loro-wasm" {
|
|||
* import { LoroDoc } from "loro-crdt";
|
||||
*
|
||||
* const doc = new LoroDoc();
|
||||
* const list = doc.getList("list");
|
||||
* const list = doc.getMovableList("list");
|
||||
* list.insert(0, 100);
|
||||
* list.insert(1, "foo");
|
||||
* list.insert(2, true);
|
||||
|
@ -472,7 +481,7 @@ declare module "loro-wasm" {
|
|||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { LoroDoc } from "loro-crdt";
|
||||
* import { LoroDoc, LoroText } from "loro-crdt";
|
||||
*
|
||||
* const doc = new LoroDoc();
|
||||
* const list = doc.getMovableList("list");
|
||||
|
@ -491,7 +500,7 @@ declare module "loro-wasm" {
|
|||
interface LoroMap<
|
||||
T extends Record<string, unknown> = Record<string, unknown>,
|
||||
> {
|
||||
new(): LoroMap<T>;
|
||||
new (): LoroMap<T>;
|
||||
/**
|
||||
* Get the value of the key. If the value is a child container, the corresponding
|
||||
* `Container` will be returned.
|
||||
|
@ -514,13 +523,13 @@ declare module "loro-wasm" {
|
|||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { LoroDoc } from "loro-crdt";
|
||||
* import { LoroDoc, LoroText, LoroList } from "loro-crdt";
|
||||
*
|
||||
* const doc = new LoroDoc();
|
||||
* const map = doc.getMap("map");
|
||||
* map.set("foo", "bar");
|
||||
* const text = map.setContainer("text", new LoroText());
|
||||
* const list = map.setContainer("list", new LoroText());
|
||||
* const list = map.setContainer("list", new LoroList());
|
||||
* ```
|
||||
*/
|
||||
setContainer<C extends Container, Key extends keyof T>(
|
||||
|
@ -569,7 +578,7 @@ declare module "loro-wasm" {
|
|||
}
|
||||
|
||||
interface LoroText {
|
||||
new(): LoroText;
|
||||
new (): LoroText;
|
||||
insert(pos: number, text: string): void;
|
||||
delete(pos: number, len: number): void;
|
||||
subscribe(listener: Listener): Subscription;
|
||||
|
@ -578,7 +587,7 @@ declare module "loro-wasm" {
|
|||
interface LoroTree<
|
||||
T extends Record<string, unknown> = Record<string, unknown>,
|
||||
> {
|
||||
new(): LoroTree<T>;
|
||||
new (): LoroTree<T>;
|
||||
/**
|
||||
* Create a new tree node as the child of parent and return a `LoroTreeNode` instance.
|
||||
* If the parent is undefined, the tree node will be a root node.
|
||||
|
@ -617,7 +626,7 @@ declare module "loro-wasm" {
|
|||
* Get the associated metadata map container of a tree node.
|
||||
*/
|
||||
readonly data: LoroMap<T>;
|
||||
/**
|
||||
/**
|
||||
* Create a new node as the child of the current node and
|
||||
* return an instance of `LoroTreeNode`.
|
||||
*
|
||||
|
@ -664,6 +673,9 @@ export function newContainerID(id: OpId, type: ContainerType): ContainerID {
|
|||
return `cid:${id.counter}@${id.peer}:${type}`;
|
||||
}
|
||||
|
||||
export function newRootContainerID(name: string, type: ContainerType): ContainerID {
|
||||
export function newRootContainerID(
|
||||
name: string,
|
||||
type: ContainerType,
|
||||
): ContainerID {
|
||||
return `cid:root-${name}:${type}`;
|
||||
}
|
||||
|
|
|
@ -2,5 +2,8 @@
|
|||
"imports": {
|
||||
"@std/fs": "jsr:@std/fs@^1.0.2",
|
||||
"@std/toml": "jsr:@std/toml@^1.0.1"
|
||||
},
|
||||
"tasks": {
|
||||
"doc-test": "deno run --allow-env --allow-read --allow-run run-js-doc-tests.ts ../crates/loro-wasm/src/lib.rs ../loro-js/src/index.ts"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,319 @@
|
|||
{
|
||||
"version": "3",
|
||||
"packages": {
|
||||
"specifiers": {
|
||||
"jsr:@std/collections@^1.0.5": "jsr:@std/collections@1.0.5",
|
||||
"jsr:@std/fs@^1.0.2": "jsr:@std/fs@1.0.2",
|
||||
"jsr:@std/path@^1.0.3": "jsr:@std/path@1.0.3",
|
||||
"jsr:@std/toml@^1.0.1": "jsr:@std/toml@1.0.1"
|
||||
"version": "4",
|
||||
"specifiers": {
|
||||
"jsr:@std/collections@^1.0.5": "1.0.5",
|
||||
"jsr:@std/fs@^1.0.2": "1.0.2",
|
||||
"jsr:@std/path@^1.0.3": "1.0.3",
|
||||
"jsr:@std/toml@^1.0.1": "1.0.1",
|
||||
"npm:expect@29.7.0": "29.7.0",
|
||||
"npm:loro-crdt@1.0.7": "1.0.7"
|
||||
},
|
||||
"jsr": {
|
||||
"@std/collections@1.0.5": {
|
||||
"integrity": "ab9eac23b57a0c0b89ba45134e61561f69f3d001f37235a248ed40be260c0c10"
|
||||
},
|
||||
"jsr": {
|
||||
"@std/collections@1.0.5": {
|
||||
"integrity": "ab9eac23b57a0c0b89ba45134e61561f69f3d001f37235a248ed40be260c0c10"
|
||||
},
|
||||
"@std/fs@1.0.2": {
|
||||
"integrity": "af57555c7a224a6f147d5cced5404692974f7a628ced8eda67e0d22d92d474ec",
|
||||
"dependencies": [
|
||||
"jsr:@std/path@^1.0.3"
|
||||
]
|
||||
},
|
||||
"@std/path@1.0.3": {
|
||||
"integrity": "cd89d014ce7eb3742f2147b990f6753ee51d95276bfc211bc50c860c1bc7df6f"
|
||||
},
|
||||
"@std/toml@1.0.1": {
|
||||
"integrity": "b55b407159930f338d384b1f8fd317c8e8a35e27ebb8946155f49e3a158d16c4",
|
||||
"dependencies": [
|
||||
"jsr:@std/collections@^1.0.5"
|
||||
]
|
||||
}
|
||||
"@std/fs@1.0.2": {
|
||||
"integrity": "af57555c7a224a6f147d5cced5404692974f7a628ced8eda67e0d22d92d474ec",
|
||||
"dependencies": [
|
||||
"jsr:@std/path"
|
||||
]
|
||||
},
|
||||
"@std/path@1.0.3": {
|
||||
"integrity": "cd89d014ce7eb3742f2147b990f6753ee51d95276bfc211bc50c860c1bc7df6f"
|
||||
},
|
||||
"@std/toml@1.0.1": {
|
||||
"integrity": "b55b407159930f338d384b1f8fd317c8e8a35e27ebb8946155f49e3a158d16c4",
|
||||
"dependencies": [
|
||||
"jsr:@std/collections"
|
||||
]
|
||||
}
|
||||
},
|
||||
"npm": {
|
||||
"@babel/code-frame@7.25.9": {
|
||||
"integrity": "sha512-z88xeGxnzehn2sqZ8UdGQEvYErF1odv2CftxInpSYJt6uHuPe9YjahKZITGs3l5LeI9d2ROG+obuDAoSlqbNfQ==",
|
||||
"dependencies": [
|
||||
"@babel/highlight",
|
||||
"picocolors"
|
||||
]
|
||||
},
|
||||
"@babel/helper-validator-identifier@7.25.9": {
|
||||
"integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="
|
||||
},
|
||||
"@babel/highlight@7.25.9": {
|
||||
"integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==",
|
||||
"dependencies": [
|
||||
"@babel/helper-validator-identifier",
|
||||
"chalk@2.4.2",
|
||||
"js-tokens",
|
||||
"picocolors"
|
||||
]
|
||||
},
|
||||
"@jest/expect-utils@29.7.0": {
|
||||
"integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==",
|
||||
"dependencies": [
|
||||
"jest-get-type"
|
||||
]
|
||||
},
|
||||
"@jest/schemas@29.6.3": {
|
||||
"integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
|
||||
"dependencies": [
|
||||
"@sinclair/typebox"
|
||||
]
|
||||
},
|
||||
"@jest/types@29.6.3": {
|
||||
"integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
|
||||
"dependencies": [
|
||||
"@jest/schemas",
|
||||
"@types/istanbul-lib-coverage",
|
||||
"@types/istanbul-reports",
|
||||
"@types/node",
|
||||
"@types/yargs",
|
||||
"chalk@4.1.2"
|
||||
]
|
||||
},
|
||||
"@sinclair/typebox@0.27.8": {
|
||||
"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="
|
||||
},
|
||||
"@types/istanbul-lib-coverage@2.0.6": {
|
||||
"integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w=="
|
||||
},
|
||||
"@types/istanbul-lib-report@3.0.3": {
|
||||
"integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==",
|
||||
"dependencies": [
|
||||
"@types/istanbul-lib-coverage"
|
||||
]
|
||||
},
|
||||
"@types/istanbul-reports@3.0.4": {
|
||||
"integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==",
|
||||
"dependencies": [
|
||||
"@types/istanbul-lib-report"
|
||||
]
|
||||
},
|
||||
"@types/node@22.5.4": {
|
||||
"integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==",
|
||||
"dependencies": [
|
||||
"undici-types"
|
||||
]
|
||||
},
|
||||
"@types/stack-utils@2.0.3": {
|
||||
"integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="
|
||||
},
|
||||
"@types/yargs-parser@21.0.3": {
|
||||
"integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="
|
||||
},
|
||||
"@types/yargs@17.0.33": {
|
||||
"integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==",
|
||||
"dependencies": [
|
||||
"@types/yargs-parser"
|
||||
]
|
||||
},
|
||||
"ansi-styles@3.2.1": {
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dependencies": [
|
||||
"color-convert@1.9.3"
|
||||
]
|
||||
},
|
||||
"ansi-styles@4.3.0": {
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dependencies": [
|
||||
"color-convert@2.0.1"
|
||||
]
|
||||
},
|
||||
"ansi-styles@5.2.0": {
|
||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
|
||||
},
|
||||
"braces@3.0.3": {
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dependencies": [
|
||||
"fill-range"
|
||||
]
|
||||
},
|
||||
"chalk@2.4.2": {
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dependencies": [
|
||||
"ansi-styles@3.2.1",
|
||||
"escape-string-regexp@1.0.5",
|
||||
"supports-color@5.5.0"
|
||||
]
|
||||
},
|
||||
"chalk@4.1.2": {
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dependencies": [
|
||||
"ansi-styles@4.3.0",
|
||||
"supports-color@7.2.0"
|
||||
]
|
||||
},
|
||||
"ci-info@3.9.0": {
|
||||
"integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="
|
||||
},
|
||||
"color-convert@1.9.3": {
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dependencies": [
|
||||
"color-name@1.1.3"
|
||||
]
|
||||
},
|
||||
"color-convert@2.0.1": {
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dependencies": [
|
||||
"color-name@1.1.4"
|
||||
]
|
||||
},
|
||||
"color-name@1.1.3": {
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"color-name@1.1.4": {
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"diff-sequences@29.6.3": {
|
||||
"integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q=="
|
||||
},
|
||||
"escape-string-regexp@1.0.5": {
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
|
||||
},
|
||||
"escape-string-regexp@2.0.0": {
|
||||
"integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="
|
||||
},
|
||||
"expect@29.7.0": {
|
||||
"integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==",
|
||||
"dependencies": [
|
||||
"@jest/expect-utils",
|
||||
"jest-get-type",
|
||||
"jest-matcher-utils",
|
||||
"jest-message-util",
|
||||
"jest-util"
|
||||
]
|
||||
},
|
||||
"fill-range@7.1.1": {
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dependencies": [
|
||||
"to-regex-range"
|
||||
]
|
||||
},
|
||||
"graceful-fs@4.2.11": {
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
|
||||
},
|
||||
"has-flag@3.0.0": {
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
|
||||
},
|
||||
"has-flag@4.0.0": {
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
|
||||
},
|
||||
"is-number@7.0.0": {
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
||||
},
|
||||
"jest-diff@29.7.0": {
|
||||
"integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
|
||||
"dependencies": [
|
||||
"chalk@4.1.2",
|
||||
"diff-sequences",
|
||||
"jest-get-type",
|
||||
"pretty-format"
|
||||
]
|
||||
},
|
||||
"jest-get-type@29.6.3": {
|
||||
"integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw=="
|
||||
},
|
||||
"jest-matcher-utils@29.7.0": {
|
||||
"integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==",
|
||||
"dependencies": [
|
||||
"chalk@4.1.2",
|
||||
"jest-diff",
|
||||
"jest-get-type",
|
||||
"pretty-format"
|
||||
]
|
||||
},
|
||||
"jest-message-util@29.7.0": {
|
||||
"integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
|
||||
"dependencies": [
|
||||
"@babel/code-frame",
|
||||
"@jest/types",
|
||||
"@types/stack-utils",
|
||||
"chalk@4.1.2",
|
||||
"graceful-fs",
|
||||
"micromatch",
|
||||
"pretty-format",
|
||||
"slash",
|
||||
"stack-utils"
|
||||
]
|
||||
},
|
||||
"jest-util@29.7.0": {
|
||||
"integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
|
||||
"dependencies": [
|
||||
"@jest/types",
|
||||
"@types/node",
|
||||
"chalk@4.1.2",
|
||||
"ci-info",
|
||||
"graceful-fs",
|
||||
"picomatch"
|
||||
]
|
||||
},
|
||||
"js-tokens@4.0.0": {
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"loro-crdt@1.0.7": {
|
||||
"integrity": "sha512-BD9qx3dQdqhEegOTEYdYo2GvRoYAeZFAfwcJLDtNRKo20y/1dUsRmzAvtLzZI/cdcRg+DkpBBLr+wcL4jRYUNw==",
|
||||
"dependencies": [
|
||||
"loro-wasm"
|
||||
]
|
||||
},
|
||||
"loro-wasm@1.0.7": {
|
||||
"integrity": "sha512-WFIpGGzc6I7zRMDoRGxa3AHhno7gVnOgwqcrTfmpKWOtktZQ7BvhIV4kYgsdyuIBcMSrQEJTfOY/80xQSjUKTw=="
|
||||
},
|
||||
"micromatch@4.0.8": {
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"dependencies": [
|
||||
"braces",
|
||||
"picomatch"
|
||||
]
|
||||
},
|
||||
"picocolors@1.1.1": {
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
|
||||
},
|
||||
"picomatch@2.3.1": {
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
|
||||
},
|
||||
"pretty-format@29.7.0": {
|
||||
"integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
|
||||
"dependencies": [
|
||||
"@jest/schemas",
|
||||
"ansi-styles@5.2.0",
|
||||
"react-is"
|
||||
]
|
||||
},
|
||||
"react-is@18.3.1": {
|
||||
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
|
||||
},
|
||||
"slash@3.0.0": {
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
|
||||
},
|
||||
"stack-utils@2.0.6": {
|
||||
"integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
|
||||
"dependencies": [
|
||||
"escape-string-regexp@2.0.0"
|
||||
]
|
||||
},
|
||||
"supports-color@5.5.0": {
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dependencies": [
|
||||
"has-flag@3.0.0"
|
||||
]
|
||||
},
|
||||
"supports-color@7.2.0": {
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dependencies": [
|
||||
"has-flag@4.0.0"
|
||||
]
|
||||
},
|
||||
"to-regex-range@5.0.1": {
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dependencies": [
|
||||
"is-number"
|
||||
]
|
||||
},
|
||||
"undici-types@6.19.8": {
|
||||
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
|
||||
}
|
||||
},
|
||||
"remote": {},
|
||||
"workspace": {
|
||||
"dependencies": [
|
||||
"jsr:@std/fs@^1.0.2",
|
||||
|
|
113
scripts/doc-tests-tests/example.txt
Normal file
113
scripts/doc-tests-tests/example.txt
Normal file
|
@ -0,0 +1,113 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/** */
|
||||
export function run(): void;
|
||||
/**
|
||||
* @param {({ peer: PeerID, counter: number })[]} frontiers
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
export function encodeFrontiers(
|
||||
frontiers: ({ peer: PeerID; counter: number })[],
|
||||
): Uint8Array;
|
||||
/**
|
||||
* @param {Uint8Array} bytes
|
||||
* @returns {{ peer: PeerID, counter: number }[]}
|
||||
*/
|
||||
export function decodeFrontiers(
|
||||
bytes: Uint8Array,
|
||||
): { peer: PeerID; counter: number }[];
|
||||
/**
|
||||
* Enable debug info of Loro
|
||||
*/
|
||||
export function setDebug(): void;
|
||||
/**
|
||||
* Decode the metadata of the import blob.
|
||||
*
|
||||
* This method is useful to get the following metadata of the import blob:
|
||||
*
|
||||
* - startVersionVector
|
||||
* - endVersionVector
|
||||
* - startTimestamp
|
||||
* - endTimestamp
|
||||
* - isSnapshot
|
||||
* - changeNum
|
||||
* @param {Uint8Array} blob
|
||||
* @returns {ImportBlobMetadata}
|
||||
*/
|
||||
export function decodeImportBlobMeta(blob: Uint8Array): ImportBlobMetadata;
|
||||
|
||||
/**
|
||||
* Container types supported by loro.
|
||||
*
|
||||
* It is most commonly used to specify the type of sub-container to be created.
|
||||
* @example
|
||||
* ```ts
|
||||
* import { LoroDoc, LoroText } from "loro-crdt";
|
||||
*
|
||||
* const doc = new LoroDoc();
|
||||
* const list = doc.getList("list");
|
||||
* list.insert(0, 100);
|
||||
* const text = list.insertContainer(1, new LoroText());
|
||||
* ```
|
||||
*/
|
||||
export type ContainerType = "Text" | "Map" | "List" | "Tree" | "MovableList";
|
||||
|
||||
export type PeerID = `${number}`;
|
||||
/**
|
||||
* The unique id of each container.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { LoroDoc } from "loro-crdt";
|
||||
*
|
||||
* const doc = new LoroDoc();
|
||||
* const list = doc.getList("list");
|
||||
* const containerId = list.id;
|
||||
* ```
|
||||
*/
|
||||
export type ContainerID =
|
||||
| `cid:root-${string}:${ContainerType}`
|
||||
| `cid:${number}@${PeerID}:${ContainerType}`;
|
||||
|
||||
/**
|
||||
* The unique id of each tree node.
|
||||
*/
|
||||
export type TreeID = `${number}@${PeerID}`;
|
||||
|
||||
interface LoroDoc {
|
||||
/**
|
||||
* Export updates from the specific version to the current version
|
||||
*
|
||||
* @deprecated Use `export({mode: "update", from: version})` instead
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { LoroDoc } from "loro-crdt";
|
||||
*
|
||||
* const doc = new LoroDoc();
|
||||
* const text = doc.getText("text");
|
||||
* text.insert(0, "Hello");
|
||||
* // get all updates of the doc
|
||||
* const updates = doc.exportFrom();
|
||||
* const version = doc.oplogVersion();
|
||||
* text.insert(5, " World");
|
||||
* // get updates from specific version to the latest version
|
||||
* const updates2 = doc.exportFrom(version);
|
||||
* ```
|
||||
*/
|
||||
exportFrom(version?: VersionVector): Uint8Array;
|
||||
///
|
||||
/// Get the container corresponding to the container id
|
||||
///
|
||||
/// @example
|
||||
/// ```ts
|
||||
/// import { LoroDoc } from "loro-crdt";
|
||||
///
|
||||
/// const doc = new LoroDoc();
|
||||
/// let text = doc.getText("text");
|
||||
/// const textId = text.id;
|
||||
/// text = doc.getContainerById(textId);
|
||||
/// ```
|
||||
///
|
||||
getContainerById(id: ContainerID): Container;
|
||||
}
|
117
scripts/run-js-doc-tests.ts
Normal file
117
scripts/run-js-doc-tests.ts
Normal file
|
@ -0,0 +1,117 @@
|
|||
const LORO_VERSION = "1.0.7";
|
||||
|
||||
export interface CodeBlock {
|
||||
filename: string;
|
||||
filePath: string;
|
||||
lineNumber: number;
|
||||
lang: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export function extractCodeBlocks(
|
||||
fileContent: string,
|
||||
codeBlocks: CodeBlock[],
|
||||
name: string,
|
||||
path: string,
|
||||
) {
|
||||
// Regular expression to detect TypeScript code blocks
|
||||
const codeBlockRegex = /```(typescript|ts|js|javascript)\n([\s\S]*?)```/g;
|
||||
let match;
|
||||
while ((match = codeBlockRegex.exec(fileContent)) !== null) {
|
||||
const startLine =
|
||||
fileContent.substring(0, match.index).split("\n").length;
|
||||
let content = match[2];
|
||||
content = content.replace(/^\s*\*/g, "");
|
||||
content = content.replace(/\n\s*\*/g, "\n");
|
||||
content = content.replace(/^\s*\/\/\//g, "");
|
||||
content = content.replace(/\n\s*\/\/\//g, "\n");
|
||||
content = replaceImportVersion(content, LORO_VERSION);
|
||||
if (!content.includes("loro-crdt")) {
|
||||
content = IMPORTS + content;
|
||||
}
|
||||
codeBlocks.push({
|
||||
filename: name,
|
||||
filePath: path,
|
||||
lineNumber: startLine,
|
||||
content,
|
||||
lang: match[1],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function replaceImportVersion(input: string, targetVersion: string): string {
|
||||
const regex = /from "loro-crdt"/g;
|
||||
const replacement = `from "npm:loro-crdt@${targetVersion}"`;
|
||||
return input.replace(regex, replacement);
|
||||
}
|
||||
|
||||
const IMPORTS =
|
||||
`import { Loro, LoroDoc, LoroMap, LoroText, LoroList, Delta, UndoManager, getType, isContainer } from "npm:loro-crdt@${LORO_VERSION}";
|
||||
import { expect } from "npm:expect@29.7.0";\n
|
||||
`;
|
||||
|
||||
Deno.test("extract doc tests", async () => {
|
||||
const filePath = "./doc-tests-tests/example.txt";
|
||||
const fileContent = await Deno.readTextFile(filePath);
|
||||
const codeBlocks: CodeBlock[] = [];
|
||||
extractCodeBlocks(fileContent, codeBlocks, "example.txt", filePath);
|
||||
for (const block of codeBlocks) {
|
||||
console.log(block.content);
|
||||
console.log("==============================");
|
||||
}
|
||||
await runCodeBlocks(codeBlocks);
|
||||
});
|
||||
|
||||
export async function runDocTests(paths: string[]) {
|
||||
const codeBlocks: CodeBlock[] = [];
|
||||
for (const path of paths) {
|
||||
const fileContent = await Deno.readTextFile(path);
|
||||
extractCodeBlocks(fileContent, codeBlocks, path, path);
|
||||
}
|
||||
|
||||
await runCodeBlocks(codeBlocks);
|
||||
}
|
||||
|
||||
async function runCodeBlocks(codeBlocks: CodeBlock[]) {
|
||||
let testCases = 0;
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
for (const block of codeBlocks) {
|
||||
try {
|
||||
const command = new Deno.Command("deno", {
|
||||
args: ["eval", "--ext=ts", block.content],
|
||||
stdout: "null",
|
||||
stderr: "inherit",
|
||||
});
|
||||
const process = command.spawn();
|
||||
const status = await process.status;
|
||||
testCases += 1;
|
||||
if (status.success) {
|
||||
passed += 1;
|
||||
} else {
|
||||
console.log("----------------");
|
||||
console.log(block.content);
|
||||
console.log("-----------------");
|
||||
console.error(
|
||||
`\x1b[31;1mError in \x1b[4m${block.filePath}:${block.lineNumber}\x1b[0m\n\n\n\n\n`,
|
||||
);
|
||||
failed += 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
}
|
||||
await Deno.stdout.write(
|
||||
new TextEncoder().encode(
|
||||
`\r🧪 ${testCases} tests, ✅ ${passed} passed,${
|
||||
failed > 0 ? " ❌" : ""
|
||||
} ${failed} failed`,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (Deno.args.length > 0) {
|
||||
await runDocTests(Deno.args);
|
||||
} else {
|
||||
console.log("No paths provided. Please provide paths as arguments.");
|
||||
}
|
Loading…
Reference in a new issue