diff --git a/.github/workflows/y-octo-node.yml b/.github/workflows/y-octo-node.yml index cfc7151..3b8c2b8 100644 --- a/.github/workflows/y-octo-node.yml +++ b/.github/workflows/y-octo-node.yml @@ -52,7 +52,7 @@ jobs: uses: actions/upload-artifact@v3 with: name: y-octo.${{ matrix.settings.target }}.node - path: ./y-octo-node/*.node + path: ./y-octo-node/dist if-no-files-found: error test-node: @@ -104,7 +104,7 @@ jobs: uses: actions/download-artifact@v3 with: name: y-octo.${{ matrix.settings.target }}.node - path: ./y-octo-node + path: ./y-octo-node/dist - name: Run node binding tests run: ls -lah & ls -lah tests working-directory: y-octo-node diff --git a/.prettierignore b/.prettierignore index 67d217b..73c4f0a 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,6 +4,6 @@ target y-octo/README.md .cargo vendor -index.d.ts -index.js +yocto.d.ts +yocto.js .coverage \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index e9ad093..c1dd66e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ members = [ "y-octo", - "y-octo-node", + "y-octo-node/native", "y-octo-utils", "y-octo-utils/yrs-is-unsafe", ] diff --git a/package.json b/package.json index 760f758..5d64e5d 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "format:rs": "cargo +nightly-2024-07-06 fmt --all" }, "devDependencies": { - "@taplo/cli": "^0.5.2", + "@taplo/cli": "^0.7.0", "husky": "^8.0.3", "lint-staged": "^14.0.0", "npm-run-all": "^4.1.5", @@ -41,45 +41,49 @@ ] }, "resolutions": { - "array-buffer-byte-length": "npm:@nolyfill/array-buffer-byte-length@latest", - "arraybuffer.prototype.slice": "npm:@nolyfill/arraybuffer.prototype.slice@latest", - "available-typed-arrays": "npm:@nolyfill/available-typed-arrays@latest", - "define-properties": "npm:@nolyfill/define-properties@latest", - "es-set-tostringtag": "npm:@nolyfill/es-set-tostringtag@latest", - "function-bind": "npm:@nolyfill/function-bind@latest", - "function.prototype.name": "npm:@nolyfill/function.prototype.name@latest", - "get-symbol-description": "npm:@nolyfill/get-symbol-description@latest", - "globalthis": "npm:@nolyfill/globalthis@latest", - "gopd": "npm:@nolyfill/gopd@latest", - "has": "npm:@nolyfill/has@latest", - "has-property-descriptors": "npm:@nolyfill/has-property-descriptors@latest", - "has-proto": "npm:@nolyfill/has-proto@latest", - "has-symbols": "npm:@nolyfill/has-symbols@latest", - "has-tostringtag": "npm:@nolyfill/has-tostringtag@latest", - "internal-slot": "npm:@nolyfill/internal-slot@latest", - "is-array-buffer": "npm:@nolyfill/is-array-buffer@latest", - "is-date-object": "npm:@nolyfill/is-date-object@latest", - "is-regex": "npm:@nolyfill/is-regex@latest", - "is-shared-array-buffer": "npm:@nolyfill/is-shared-array-buffer@latest", - "is-string": "npm:@nolyfill/is-string@latest", - "is-symbol": "npm:@nolyfill/is-symbol@latest", - "is-weakref": "npm:@nolyfill/is-weakref@latest", - "object-keys": "npm:@nolyfill/object-keys@latest", - "object.assign": "npm:@nolyfill/object.assign@latest", - "regexp.prototype.flags": "npm:@nolyfill/regexp.prototype.flags@latest", - "safe-array-concat": "npm:@nolyfill/safe-array-concat@latest", - "safe-regex-test": "npm:@nolyfill/safe-regex-test@latest", - "side-channel": "npm:@nolyfill/side-channel@latest", - "string.prototype.padend": "npm:@nolyfill/string.prototype.padend@latest", - "string.prototype.trim": "npm:@nolyfill/string.prototype.trim@latest", - "string.prototype.trimend": "npm:@nolyfill/string.prototype.trimend@latest", - "string.prototype.trimstart": "npm:@nolyfill/string.prototype.trimstart@latest", - "typed-array-buffer": "npm:@nolyfill/typed-array-buffer@latest", - "typed-array-byte-length": "npm:@nolyfill/typed-array-byte-length@latest", - "typed-array-byte-offset": "npm:@nolyfill/typed-array-byte-offset@latest", - "typed-array-length": "npm:@nolyfill/typed-array-length@latest", - "unbox-primitive": "npm:@nolyfill/unbox-primitive@latest", - "which-boxed-primitive": "npm:@nolyfill/which-boxed-primitive@latest", - "which-typed-array": "npm:@nolyfill/which-typed-array@latest" + "array-buffer-byte-length": "npm:@nolyfill/array-buffer-byte-length@^1", + "arraybuffer.prototype.slice": "npm:@nolyfill/arraybuffer.prototype.slice@^1", + "available-typed-arrays": "npm:@nolyfill/available-typed-arrays@^1", + "define-properties": "npm:@nolyfill/define-properties@^1", + "es-set-tostringtag": "npm:@nolyfill/es-set-tostringtag@^1", + "function-bind": "npm:@nolyfill/function-bind@^1", + "function.prototype.name": "npm:@nolyfill/function.prototype.name@^1", + "get-symbol-description": "npm:@nolyfill/get-symbol-description@^1", + "globalthis": "npm:@nolyfill/globalthis@^1", + "gopd": "npm:@nolyfill/gopd@^1", + "has-property-descriptors": "npm:@nolyfill/has-property-descriptors@^1", + "has-proto": "npm:@nolyfill/has-proto@^1", + "has-symbols": "npm:@nolyfill/has-symbols@^1", + "has-tostringtag": "npm:@nolyfill/has-tostringtag@^1", + "hasown": "npm:@nolyfill/hasown@^1", + "internal-slot": "npm:@nolyfill/internal-slot@^1", + "is-array-buffer": "npm:@nolyfill/is-array-buffer@^1", + "is-core-module": "npm:@nolyfill/is-core-module@^1", + "is-date-object": "npm:@nolyfill/is-date-object@^1", + "is-regex": "npm:@nolyfill/is-regex@^1", + "is-shared-array-buffer": "npm:@nolyfill/is-shared-array-buffer@^1", + "is-string": "npm:@nolyfill/is-string@^1", + "is-symbol": "npm:@nolyfill/is-symbol@^1", + "is-typed-array": "npm:@nolyfill/is-typed-array@^1", + "is-weakref": "npm:@nolyfill/is-weakref@^1", + "isarray": "npm:@nolyfill/isarray@^1", + "object-keys": "npm:@nolyfill/object-keys@^1", + "object.assign": "npm:@nolyfill/object.assign@^1", + "regexp.prototype.flags": "npm:@nolyfill/regexp.prototype.flags@^1", + "safe-array-concat": "npm:@nolyfill/safe-array-concat@^1", + "safe-regex-test": "npm:@nolyfill/safe-regex-test@^1", + "set-function-length": "npm:@nolyfill/set-function-length@^1", + "side-channel": "npm:@nolyfill/side-channel@^1", + "string.prototype.padend": "npm:@nolyfill/string.prototype.padend@^1", + "string.prototype.trim": "npm:@nolyfill/string.prototype.trim@^1", + "string.prototype.trimend": "npm:@nolyfill/string.prototype.trimend@^1", + "string.prototype.trimstart": "npm:@nolyfill/string.prototype.trimstart@^1", + "typed-array-buffer": "npm:@nolyfill/typed-array-buffer@^1", + "typed-array-byte-length": "npm:@nolyfill/typed-array-byte-length@^1", + "typed-array-byte-offset": "npm:@nolyfill/typed-array-byte-offset@^1", + "typed-array-length": "npm:@nolyfill/typed-array-length@^1", + "unbox-primitive": "npm:@nolyfill/unbox-primitive@^1", + "which-boxed-primitive": "npm:@nolyfill/which-boxed-primitive@^1", + "which-typed-array": "npm:@nolyfill/which-typed-array@^1" } } diff --git a/tsconfig.json b/tsconfig.json index c014b81..8350fba 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -48,7 +48,7 @@ // Projects "composite": true, - "incremental": true, + // "incremental": true, // Completeness "skipLibCheck": true, // skip all type checks for .d.ts files diff --git a/y-octo-node/.gitignore b/y-octo-node/.gitignore index 28f2c68..c1d1555 100644 --- a/y-octo-node/.gitignore +++ b/y-octo-node/.gitignore @@ -1,2 +1,3 @@ +/lib *.node .coverage \ No newline at end of file diff --git a/y-octo-node/index.d.ts b/y-octo-node/index.d.ts deleted file mode 100644 index 10a5a16..0000000 --- a/y-octo-node/index.d.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ - -/* auto-generated by NAPI-RS */ - -export class YArray { - constructor() - get length(): number - get isEmpty(): boolean - get(index: number): T - insert(index: number, value: YArray | YMap | YText | boolean | number | string | Record | null | undefined): void - remove(index: number, len: number): void - toJson(): JsArray -} -export class Doc { - constructor(clientId?: number | undefined | null) - get clientId(): number - get guid(): string - get keys(): Array - getOrCreateArray(key: string): YArray - getOrCreateText(key: string): YText - getOrCreateMap(key: string): YMap - createArray(): YArray - createText(): YText - createMap(): YMap - applyUpdate(update: Buffer): void - encodeStateAsUpdateV1(state?: Buffer | undefined | null): Buffer - gc(): void - onUpdate(callback: (result: Uint8Array) => void): void -} -export class YMap { - constructor() - get length(): number - get isEmpty(): boolean - get(key: string): T - set(key: string, value: YArray | YMap | YText | boolean | number | string | Record | null | undefined): void - remove(key: string): void - toJson(): object -} -export class YText { - constructor() - get len(): number - get isEmpty(): boolean - insert(index: number, str: string): void - remove(index: number, len: number): void - get length(): number - toString(): string -} diff --git a/y-octo-node/index.js b/y-octo-node/index.js deleted file mode 100644 index 516ad7e..0000000 --- a/y-octo-node/index.js +++ /dev/null @@ -1,260 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -/* prettier-ignore */ - -/* auto-generated by NAPI-RS */ - -const { existsSync, readFileSync } = require('fs') -const { join } = require('path') - -const { platform, arch } = process - -let nativeBinding = null -let localFileExisted = false -let loadError = null - -function isMusl() { - // For Node 10 - if (!process.report || typeof process.report.getReport !== 'function') { - try { - const lddPath = require('child_process').execSync('which ldd').toString().trim() - return readFileSync(lddPath, 'utf8').includes('musl') - } catch (e) { - return true - } - } else { - const { glibcVersionRuntime } = process.report.getReport().header - return !glibcVersionRuntime - } -} - -switch (platform) { - case 'android': - switch (arch) { - case 'arm64': - localFileExisted = existsSync(join(__dirname, 'y-octo.android-arm64.node')) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.android-arm64.node') - } else { - nativeBinding = require('@y-octo/node-android-arm64') - } - } catch (e) { - loadError = e - } - break - case 'arm': - localFileExisted = existsSync(join(__dirname, 'y-octo.android-arm-eabi.node')) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.android-arm-eabi.node') - } else { - nativeBinding = require('@y-octo/node-android-arm-eabi') - } - } catch (e) { - loadError = e - } - break - default: - throw new Error(`Unsupported architecture on Android ${arch}`) - } - break - case 'win32': - switch (arch) { - case 'x64': - localFileExisted = existsSync( - join(__dirname, 'y-octo.win32-x64-msvc.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.win32-x64-msvc.node') - } else { - nativeBinding = require('@y-octo/node-win32-x64-msvc') - } - } catch (e) { - loadError = e - } - break - case 'ia32': - localFileExisted = existsSync( - join(__dirname, 'y-octo.win32-ia32-msvc.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.win32-ia32-msvc.node') - } else { - nativeBinding = require('@y-octo/node-win32-ia32-msvc') - } - } catch (e) { - loadError = e - } - break - case 'arm64': - localFileExisted = existsSync( - join(__dirname, 'y-octo.win32-arm64-msvc.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.win32-arm64-msvc.node') - } else { - nativeBinding = require('@y-octo/node-win32-arm64-msvc') - } - } catch (e) { - loadError = e - } - break - default: - throw new Error(`Unsupported architecture on Windows: ${arch}`) - } - break - case 'darwin': - localFileExisted = existsSync(join(__dirname, 'y-octo.darwin-universal.node')) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.darwin-universal.node') - } else { - nativeBinding = require('@y-octo/node-darwin-universal') - } - break - } catch {} - switch (arch) { - case 'x64': - localFileExisted = existsSync(join(__dirname, 'y-octo.darwin-x64.node')) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.darwin-x64.node') - } else { - nativeBinding = require('@y-octo/node-darwin-x64') - } - } catch (e) { - loadError = e - } - break - case 'arm64': - localFileExisted = existsSync( - join(__dirname, 'y-octo.darwin-arm64.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.darwin-arm64.node') - } else { - nativeBinding = require('@y-octo/node-darwin-arm64') - } - } catch (e) { - loadError = e - } - break - default: - throw new Error(`Unsupported architecture on macOS: ${arch}`) - } - break - case 'freebsd': - if (arch !== 'x64') { - throw new Error(`Unsupported architecture on FreeBSD: ${arch}`) - } - localFileExisted = existsSync(join(__dirname, 'y-octo.freebsd-x64.node')) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.freebsd-x64.node') - } else { - nativeBinding = require('@y-octo/node-freebsd-x64') - } - } catch (e) { - loadError = e - } - break - case 'linux': - switch (arch) { - case 'x64': - if (isMusl()) { - localFileExisted = existsSync( - join(__dirname, 'y-octo.linux-x64-musl.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.linux-x64-musl.node') - } else { - nativeBinding = require('@y-octo/node-linux-x64-musl') - } - } catch (e) { - loadError = e - } - } else { - localFileExisted = existsSync( - join(__dirname, 'y-octo.linux-x64-gnu.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.linux-x64-gnu.node') - } else { - nativeBinding = require('@y-octo/node-linux-x64-gnu') - } - } catch (e) { - loadError = e - } - } - break - case 'arm64': - if (isMusl()) { - localFileExisted = existsSync( - join(__dirname, 'y-octo.linux-arm64-musl.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.linux-arm64-musl.node') - } else { - nativeBinding = require('@y-octo/node-linux-arm64-musl') - } - } catch (e) { - loadError = e - } - } else { - localFileExisted = existsSync( - join(__dirname, 'y-octo.linux-arm64-gnu.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.linux-arm64-gnu.node') - } else { - nativeBinding = require('@y-octo/node-linux-arm64-gnu') - } - } catch (e) { - loadError = e - } - } - break - case 'arm': - localFileExisted = existsSync( - join(__dirname, 'y-octo.linux-arm-gnueabihf.node') - ) - try { - if (localFileExisted) { - nativeBinding = require('./y-octo.linux-arm-gnueabihf.node') - } else { - nativeBinding = require('@y-octo/node-linux-arm-gnueabihf') - } - } catch (e) { - loadError = e - } - break - default: - throw new Error(`Unsupported architecture on Linux: ${arch}`) - } - break - default: - throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`) -} - -if (!nativeBinding) { - if (loadError) { - throw loadError - } - throw new Error(`Failed to load native binding`) -} - -const { YArray, Doc, YMap, YText } = nativeBinding - -module.exports.YArray = YArray -module.exports.Doc = Doc -module.exports.YMap = YMap -module.exports.YText = YText diff --git a/y-octo-node/Cargo.toml b/y-octo-node/native/Cargo.toml similarity index 67% rename from y-octo-node/Cargo.toml rename to y-octo-node/native/Cargo.toml index 69ba858..c974cbf 100644 --- a/y-octo-node/Cargo.toml +++ b/y-octo-node/native/Cargo.toml @@ -11,10 +11,13 @@ version = "0.0.1" crate-type = ["cdylib"] [dependencies] -anyhow = "1" -napi = { version = "2", features = ["anyhow", "napi4"] } +anyhow = "1" +napi = { version = "2", features = ["anyhow", "napi4", "serde-json"] } napi-derive = "2" -y-octo = { workspace = true, features = ["large_refs"] } +serde_json = "1.0" +y-octo = { workspace = true, features = [ + "large_refs", +], default-features = false } [build-dependencies] napi-build = "2" diff --git a/y-octo-node/build.rs b/y-octo-node/native/build.rs similarity index 100% rename from y-octo-node/build.rs rename to y-octo-node/native/build.rs diff --git a/y-octo-node/native/src/array.rs b/y-octo-node/native/src/array.rs new file mode 100644 index 0000000..d7c4c87 --- /dev/null +++ b/y-octo-node/native/src/array.rs @@ -0,0 +1,255 @@ +use napi::{ + bindgen_prelude::{Array as JsArray, FromNapiValue, Function}, + iterator::Generator, + Env, JsFunction, JsUnknown, ValueType, +}; +use y_octo::{Any, Array}; + +use super::*; + +#[napi] +#[derive(Clone)] +pub struct YArray { + pub(crate) array: Array, +} + +#[napi] +impl YArray { + pub(crate) fn inner_new(array: Array) -> Self { + Self { array } + } + + #[napi(getter)] + pub fn length(&self) -> i64 { + self.array.len() as i64 + } + + #[napi(getter)] + pub fn is_empty(&self) -> bool { + self.array.is_empty() + } + + #[napi(getter)] + pub fn item_id(&self) -> Option { + self.array.id().map(|id| YId { id }) + } + + #[napi(ts_generic_types = "T = unknown", ts_return_type = "T")] + pub fn get(&self, env: Env, index: i64) -> Result { + let value = if let Some(value) = self.array.get(index as u64) { + get_mixed_y_type_from_value(env, value, false)? + } else { + MixedYType::D(env.get_undefined()?.into_unknown()) + }; + Ok(value) + } + + #[napi(ts_generic_types = "T = unknown", ts_return_type = "Array")] + pub fn slice(&self, env: Env, start: i64, end: Option) -> Result { + let mut js_array = env.create_array(0)?; + let end = end + .map(|end| { + if end.is_negative() { + self.length() + end + } else { + let end = end - start; + if end.is_negative() { + 0 + } else { + end + } + } + }) + .unwrap_or(self.length() - start) as usize; + for value in self.array.iter().skip(start as usize).take(end) { + js_array.insert(get_mixed_y_type_from_value(env, value, false)?)?; + } + Ok(js_array) + } + + #[napi( + ts_args_type = "value: YArray | YMap | YText | boolean | number | string | Record | null | \ + undefined", + ts_generic_types = "T = unknown", + ts_return_type = "Array" + )] + pub fn map(&self, env: Env, callback: Function) -> Result { + let mut js_array = env.create_array(0)?; + for value in self.array.iter() { + let value = get_mixed_y_type_from_value(env, value, false)?; + js_array.insert(callback.call(value)?)?; + } + Ok(js_array) + } + + #[napi( + ts_args_type = "index: number, value: YArray | YMap | YText | boolean | number | string | Record \ + | null | undefined" + )] + pub fn insert(&mut self, index: i64, value: MixedRefYType) -> Result<()> { + match value { + MixedRefYType::A(array) => self + .array + .insert(index as u64, array.array.clone()) + .map_err(anyhow::Error::from), + MixedRefYType::B(map) => self + .array + .insert(index as u64, map.map.clone()) + .map_err(anyhow::Error::from), + MixedRefYType::C(text) => self + .array + .insert(index as u64, text.text.clone()) + .map_err(anyhow::Error::from), + MixedRefYType::D(unknown) => match unknown.get_type() { + Ok(value_type) => match value_type { + ValueType::Undefined => self + .array + .insert(index as u64, Any::Undefined) + .map_err(anyhow::Error::from), + ValueType::Null => self.array.insert(index as u64, Any::Null).map_err(anyhow::Error::from), + ValueType::Boolean => match unknown.coerce_to_bool().and_then(|v| v.get_value()) { + Ok(boolean) => self.array.insert(index as u64, boolean).map_err(anyhow::Error::from), + Err(e) => Err(anyhow::Error::new(e).context("Failed to coerce value to boolean")), + }, + ValueType::Number => match unknown.coerce_to_number().and_then(|v| v.get_double()) { + Ok(number) => self.array.insert(index as u64, number).map_err(anyhow::Error::from), + Err(e) => Err(anyhow::Error::new(e).context("Failed to coerce value to number")), + }, + ValueType::String => { + match unknown + .coerce_to_string() + .and_then(|v| v.into_utf8()) + .and_then(|s| s.as_str().map(|s| s.to_string())) + { + Ok(string) => self.array.insert(index as u64, string).map_err(anyhow::Error::from), + Err(e) => Err(anyhow::Error::new(e).context("Failed to coerce value to string")), + } + } + ValueType::Object => match unknown + .coerce_to_object() + .and_then(|o| o.get_array_length().map(|l| (o, l))) + { + Ok((object, length)) => { + for i in 0..length { + if let Ok(unknown) = object.get_element::(i) { + self.insert(index + i as i64, MixedRefYType::from_unknown(unknown)?)?; + } + } + Ok(()) + } + Err(e) => Err(anyhow::Error::new(e).context("Failed to coerce value to object")), + }, + ValueType::Symbol => Err(anyhow::Error::msg("Symbol values are not supported")), + ValueType::Function => Err(anyhow::Error::msg("Function values are not supported")), + ValueType::External => Err(anyhow::Error::msg("External values are not supported")), + ValueType::Unknown => Err(anyhow::Error::msg("Unknown values are not supported")), + }, + Err(e) => Err(anyhow::Error::from(e)), + }, + } + } + + #[napi( + ts_args_type = "value: YArray | YMap | YText | boolean | number | string | Record | null | \ + undefined" + )] + pub fn push(&mut self, value: MixedRefYType) -> Result<()> { + self.insert(self.length(), value) + } + + #[napi( + ts_args_type = "value: YArray | YMap | YText | boolean | number | string | Record | null | \ + undefined" + )] + pub fn unshift(&mut self, value: MixedRefYType) -> Result<()> { + self.insert(0, value) + } + + #[napi] + pub fn delete(&mut self, index: i64, len: Option) -> Result<()> { + self.array + .remove(index as u64, len.unwrap_or(1) as u64) + .map_err(anyhow::Error::from) + } + + #[napi] + pub fn iter(&self, env: Env) -> YArrayIterator { + YArrayIterator { + array: self.clone(), + env, + current: 0, + } + } + + #[napi(ts_generic_types = "T = unknown", ts_return_type = "Array")] + pub fn to_array(&self, env: Env) -> Result { + let mut js_array = env.create_array(0)?; + for value in self.array.iter() { + js_array.insert(get_mixed_y_type_from_value(env, value, false)?)?; + } + Ok(js_array) + } + + #[napi(js_name = "toJSON", ts_generic_types = "T = unknown", ts_return_type = "Array")] + pub fn to_json(&self, env: Env) -> Result { + let mut js_array = env.create_array(0)?; + for value in self.array.iter() { + js_array.insert(get_mixed_y_type_from_value(env, value, true)?)?; + } + Ok(js_array) + } + + // TODO(@darkskygit): impl type based observe + #[napi] + pub fn observe(&mut self, _callback: JsFunction) -> Result<()> { + Ok(()) + } + + // TODO(@darkskygit): impl type based observe + #[napi] + pub fn observe_deep(&mut self, _callback: JsFunction) -> Result<()> { + Ok(()) + } +} + +#[napi(iterator)] +pub struct YArrayIterator { + array: YArray, + env: Env, + current: i64, +} + +#[napi] +impl Generator for YArrayIterator { + type Yield = MixedYType; + + type Next = Option; + + type Return = (); + + fn next(&mut self, value: Option) -> Option { + if self.array.length() <= self.current { + return None; + } + let ret = self.array.get(self.env, self.current).ok(); + self.current = if let Some(value) = value.and_then(|v| v) { + value + } else { + self.current + 1 + }; + ret + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_array_init() { + let doc = YDoc::new(None); + let array = doc.get_or_create_array("array".into()).unwrap(); + assert_eq!(array.length(), 0); + } +} diff --git a/y-octo-node/native/src/awareness.rs b/y-octo-node/native/src/awareness.rs new file mode 100644 index 0000000..bd5b195 --- /dev/null +++ b/y-octo-node/native/src/awareness.rs @@ -0,0 +1,37 @@ +use napi::{bindgen_prelude::Object as JsObject, Env}; +use y_octo::{prefer_small_random, Awareness}; + +use super::*; + +#[napi(js_name = "Awareness")] +pub struct YAwareness { + pub(crate) awareness: Awareness, +} + +#[napi] +impl YAwareness { + #[napi(constructor)] + pub fn new(client_id: Option) -> Self { + let client_id = client_id + .and_then(|c| c.try_into().ok()) + .unwrap_or_else(prefer_small_random); + Self { + awareness: Awareness::new(client_id), + } + } + + #[napi(getter)] + pub fn client_id(&self) -> i64 { + self.awareness.local_id() as i64 + } + + #[napi(getter, ts_return_type = "Record")] + pub fn states(&self, env: Env) -> Result { + let mut object = env.create_object()?; + for (k, v) in self.awareness.get_states() { + let value = env.to_js_value(&serde_json::from_str(v.content())?)?; + object.set_named_property(&k.to_string(), value)?; + } + Ok(object) + } +} diff --git a/y-octo-node/src/doc.rs b/y-octo-node/native/src/doc.rs similarity index 51% rename from y-octo-node/src/doc.rs rename to y-octo-node/native/src/doc.rs index e37ab80..75f8c2e 100644 --- a/y-octo-node/src/doc.rs +++ b/y-octo-node/native/src/doc.rs @@ -1,25 +1,26 @@ use napi::{ - bindgen_prelude::{Buffer as JsBuffer, JsFunction}, + bindgen_prelude::{Array as JsArray, Buffer as JsBuffer, JsFunction}, threadsafe_function::{ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode}, + Env, JsString, JsUnknown, }; -use y_octo::{CrdtRead, Doc as YDoc, History, RawDecoder, StateVector}; +use y_octo::{CrdtRead, Doc, History, RawDecoder, StateVector}; use super::*; -#[napi] -pub struct Doc { - doc: YDoc, +#[napi(js_name = "Doc")] +pub struct YDoc { + pub(crate) doc: Doc, } #[napi] -impl Doc { +impl YDoc { #[napi(constructor)] pub fn new(client_id: Option) -> Self { Self { doc: if let Some(client_id) = client_id { - YDoc::with_client(client_id as u64) + Doc::with_client(client_id as u64) } else { - YDoc::default() + Doc::default() }, } } @@ -29,11 +30,21 @@ impl Doc { self.doc.client() as i64 } + #[napi(setter)] + pub fn set_client_id(&mut self, client_id: i64) { + self.doc.set_client(client_id as u64); + } + #[napi(getter)] pub fn guid(&self) -> &str { self.doc.guid() } + #[napi(getter)] + pub fn store(&self) -> YStore { + YStore { doc: self.doc.clone() } + } + #[napi(getter)] pub fn keys(&self) -> Vec { self.doc.keys() @@ -72,37 +83,72 @@ impl Doc { } #[napi] - pub fn create_text(&self) -> Result { - self.doc - .create_text() - .map(YText::inner_new) - .map_err(anyhow::Error::from) - } + pub fn create_text(&self, text: Option) -> Result { + let mut ytext = self.doc.create_text().map(YText::inner_new)?; + if let Some(text) = text { + ytext.insert(0, text)?; + } + Ok(ytext) + } + + #[napi(ts_args_type = "entries?: Array<[string,any]> | Iterator<[string,any]>")] + pub fn create_map(&self, env: Env, entries: Option) -> Result { + let mut ymap = self.doc.create_map().map(YMap::inner_new)?; + if let Some(entries) = entries { + for i in 0..entries.len() { + if let Ok(Some(value)) = entries.get::(i) { + let key = value.get::(0)?; + let value = value.get::(1)?; + if let (Some(key), Some(value)) = (key, value) { + ymap.set(env, key.into_utf8()?.into_owned()?, MixedRefYType::D(value))?; + continue; + } + } + + return Err(anyhow::anyhow!("Invalid entry")); + } + } - #[napi] - pub fn create_map(&self) -> Result { - self.doc.create_map().map(YMap::inner_new).map_err(anyhow::Error::from) + Ok(ymap) } #[napi] pub fn apply_update(&mut self, update: JsBuffer) -> Result<()> { + let client = self.doc.client(); + let before_current_state = self.doc.get_state_vector().get(&client); + self.doc.apply_update_from_binary_v1(update)?; + // if update received from remote and current client state has been changed + // that means another client using same client id, we need to change the client + // id to avoid conflict + if self.doc.get_state_vector().get(&client) != before_current_state { + self.doc.renew_client(); + } + Ok(()) } #[napi] - pub fn encode_state_as_update_v1(&self, state: Option) -> Result { - let result = match state { - Some(state) => { - let mut decoder = RawDecoder::new(state.as_ref()); - let state = StateVector::read(&mut decoder)?; - self.doc.encode_state_as_update_v1(&state) - } - None => self.doc.encode_update_v1(), - }; + pub fn diff(&self, sv: Option) -> Result> { + if let Some(sv) = sv { + let mut decoder = RawDecoder::new(sv.as_ref()); + let state = StateVector::read(&mut decoder)?; + let update = self.doc.encode_state_as_update_v1(&state)?; + Ok(Some(update.into())) + } else { + Ok(None) + } + } - result.map(|v| v.into()).map_err(anyhow::Error::from) + #[napi] + pub fn encode_state_as_update_v1(&self, state: Option) -> Result { + if let Some(buffer) = self.diff(state)? { + Ok(buffer) + } else { + let buffer = self.doc.encode_update_v1()?; + Ok(buffer.into()) + } } #[napi] @@ -121,6 +167,19 @@ impl Doc { self.doc.subscribe(Box::new(callback)); Ok(()) } + + #[napi] + pub fn off_update(&mut self) -> Result<()> { + self.doc.unsubscribe_all(); + Ok(()) + } + + #[napi] + pub fn destroy(&mut self) { + if let Err(e) = self.off_update() { + eprintln!("Failed to unsubscribe at doc destroy: {:?}", e); + } + } } #[cfg(test)] @@ -130,33 +189,33 @@ mod tests { #[test] fn test_doc_client() { let client_id = 1; - let doc = Doc::new(Some(client_id)); + let doc = YDoc::new(Some(client_id)); assert_eq!(doc.client_id(), 1); } #[test] fn test_doc_guid() { - let doc = Doc::new(None); + let doc = YDoc::new(None); assert_eq!(doc.guid().len(), 21); } #[test] fn test_create_array() { - let doc = Doc::new(None); + let doc = YDoc::new(None); let array = doc.get_or_create_array("array".into()).unwrap(); assert_eq!(array.length(), 0); } #[test] fn test_create_text() { - let doc = Doc::new(None); + let doc = YDoc::new(None); let text = doc.get_or_create_text("text".into()).unwrap(); assert_eq!(text.len(), 0); } #[test] fn test_keys() { - let doc = Doc::new(None); + let doc = YDoc::new(None); doc.get_or_create_array("array".into()).unwrap(); doc.get_or_create_text("text".into()).unwrap(); doc.get_or_create_map("map".into()).unwrap(); diff --git a/y-octo-node/native/src/function.rs b/y-octo-node/native/src/function.rs new file mode 100644 index 0000000..4c1c7af --- /dev/null +++ b/y-octo-node/native/src/function.rs @@ -0,0 +1,77 @@ +use napi::bindgen_prelude::Buffer as JsBuffer; +use y_octo::{merge_updates_v1, CrdtWrite, RawEncoder}; + +use super::*; + +// state + +#[napi] +pub fn encode_state_as_update(doc: &YDoc, state: Option) -> Result { + doc.encode_state_as_update_v1(state) +} + +#[napi] +pub fn encode_state_vector(doc: &YDoc) -> Result { + let sv = doc.doc.get_state_vector(); + let mut encoder = RawEncoder::default(); + sv.write(&mut encoder)?; + Ok(encoder.into_inner().into()) +} + +#[napi] +pub fn compare_struct_stores(store: &YStore, other: &YStore) -> bool { + store.doc.store_compare(&other.doc) +} + +#[napi] +pub fn compare_ids(a: Option<&YId>, b: Option<&YId>) -> bool { + match (a, b) { + (Some(a), Some(b)) => a.id == b.id, + (None, None) => true, + _ => false, + } +} + +// delete set + +#[napi] +pub fn create_delete_set_from_struct_store(store: &YStore) -> YDeleteSet { + YDeleteSet { + ds: store.doc.get_delete_sets(), + } +} + +#[napi] +pub fn equal_delete_sets(a: &YDeleteSet, b: &YDeleteSet) -> bool { + a == b +} + +// snapshot + +#[napi] +pub fn snapshot(doc: &YDoc) -> YSnapshot { + YSnapshot::from_doc(doc) +} + +#[napi] +pub fn encode_snapshot(snapshot: &YSnapshot) -> Result { + Ok(snapshot.encode_v1()?.into()) +} + +// update + +#[napi] +pub fn apply_update(doc: &mut YDoc, update: JsBuffer) -> Result<()> { + doc.apply_update(update) +} + +#[napi] +pub fn merge_updates(updates: Vec) -> Result { + let updates = updates.iter().map(|u| u.as_ref()).collect::>(); + Ok(merge_updates_v1(updates)?.encode_v1()?.into()) +} + +#[napi(ts_args_type = "obj?: any")] +pub fn is_abstract_type(unknown: MixedRefYType) -> bool { + matches!(unknown, MixedRefYType::A(_) | MixedRefYType::B(_) | MixedRefYType::C(_)) +} diff --git a/y-octo-node/native/src/lib.rs b/y-octo-node/native/src/lib.rs new file mode 100644 index 0000000..6e4608a --- /dev/null +++ b/y-octo-node/native/src/lib.rs @@ -0,0 +1,22 @@ +use anyhow::Result; +use napi_derive::napi; + +mod array; +mod awareness; +mod doc; +mod function; +mod map; +mod protocol; +mod text; +mod types; +mod utils; + +pub use array::*; +pub use awareness::*; +pub use doc::*; +pub use function::*; +pub use map::*; +pub use protocol::*; +pub use text::*; +pub use types::*; +use utils::{get_any_from_js_object, get_js_unknown_from_any, get_mixed_y_type_from_value, MixedRefYType, MixedYType}; diff --git a/y-octo-node/native/src/map.rs b/y-octo-node/native/src/map.rs new file mode 100644 index 0000000..3305ded --- /dev/null +++ b/y-octo-node/native/src/map.rs @@ -0,0 +1,301 @@ +use napi::{bindgen_prelude::Array as JsArray, iterator::Generator, Env, JsFunction, JsObject, ValueType}; +use y_octo::{Any, Map, Value}; + +use super::*; + +#[napi] +#[derive(Clone)] +pub struct YMap { + pub(crate) map: Map, +} + +#[napi] +impl YMap { + pub(crate) fn inner_new(map: Map) -> Self { + Self { map } + } + + #[napi(getter)] + pub fn length(&self) -> i64 { + self.map.len() as i64 + } + + #[napi(getter)] + pub fn size(&self) -> i64 { + self.length() + } + + #[napi(getter)] + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + #[napi(getter)] + pub fn item_id(&self) -> Option { + self.map.id().map(|id| YId { id }) + } + + #[napi(ts_generic_types = "T = unknown", ts_return_type = "T")] + pub fn get(&self, env: Env, key: String) -> Result { + let value = if let Some(value) = self.map.get(&key) { + get_mixed_y_type_from_value(env, value, false)? + } else { + MixedYType::D(env.get_undefined()?.into_unknown()) + }; + + Ok(value) + } + + #[napi( + ts_generic_types = "T = YArray | YMap | YText | boolean | number | string | Record | null | \ + undefined", + ts_args_type = "key: string, value: T", + ts_return_type = "T" + )] + pub fn set(&mut self, env: Env, key: String, value: MixedRefYType) -> Result { + match value { + MixedRefYType::A(array) => { + self.map.insert(key, array.array.clone())?; + Ok(array.into()) + } + MixedRefYType::B(map) => { + self.map.insert(key, map.map.clone())?; + Ok(map.into()) + } + MixedRefYType::C(text) => { + self.map.insert(key, text.text.clone())?; + Ok(text.into()) + } + MixedRefYType::D(unknown) => match unknown.get_type() { + Ok(value_type) => match value_type { + ValueType::Undefined => { + self.map.insert(key, Any::Undefined)?; + Ok(MixedYType::D(env.get_undefined().map(|v| v.into_unknown())?)) + } + ValueType::Null => { + self.map.insert(key, Any::Null)?; + Ok(MixedYType::D(env.get_null().map(|v| v.into_unknown())?)) + } + ValueType::Boolean => match unknown.coerce_to_bool().and_then(|v| v.get_value()) { + Ok(boolean) => { + self.map.insert(key, boolean)?; + Ok(MixedYType::D(env.get_boolean(boolean).map(|v| v.into_unknown())?)) + } + Err(e) => Err(anyhow::Error::from(e).context("Failed to coerce value to boolean")), + }, + ValueType::Number => match unknown.coerce_to_number().and_then(|v| v.get_double()) { + Ok(number) => { + self.map.insert(key, number)?; + Ok(MixedYType::D(env.create_double(number).map(|v| v.into_unknown())?)) + } + Err(e) => Err(anyhow::Error::from(e).context("Failed to coerce value to number")), + }, + ValueType::String => { + match unknown + .coerce_to_string() + .and_then(|v| v.into_utf8()) + .and_then(|s| s.as_str().map(|s| s.to_string())) + { + Ok(string) => { + self.map.insert(key, string.clone())?; + Ok(MixedYType::D(env.create_string(&string).map(|v| v.into_unknown())?)) + } + Err(e) => Err(anyhow::Error::from(e).context("Failed to coerce value to string")), + } + } + ValueType::Object => match unknown.coerce_to_object().and_then(get_any_from_js_object) { + Ok(any) => { + self.map.insert(key, Value::Any(any.clone()))?; + Ok(MixedYType::D(get_js_unknown_from_any(env, any)?)) + } + Err(e) => Err(anyhow::Error::from(e).context("Failed to coerce value to object")), + }, + ValueType::Symbol => Err(anyhow::Error::msg("Symbol values are not supported")), + ValueType::Function => Err(anyhow::Error::msg("Function values are not supported")), + ValueType::External => Err(anyhow::Error::msg("External values are not supported")), + ValueType::Unknown => Err(anyhow::Error::msg("Unknown values are not supported")), + }, + Err(e) => Err(anyhow::Error::from(e)), + }, + } + } + + #[napi] + pub fn delete(&mut self, key: String) { + self.map.remove(&key); + } + + #[napi] + pub fn clear(&mut self) { + let keys = self.map.keys().map(ToOwned::to_owned).collect::>(); + for key in keys { + self.map.remove(&key); + } + } + + #[napi( + js_name = "toJSON", + ts_generic_types = "T = unknown", + ts_return_type = "Record" + )] + pub fn to_json(&self, env: Env) -> Result { + let mut js_object = env.create_object()?; + for (key, value) in self.map.iter() { + js_object.set(key, get_mixed_y_type_from_value(env, value, true))?; + } + Ok(js_object) + } + + #[napi] + pub fn entries(&self, env: Env) -> YMapEntriesIterator { + YMapEntriesIterator { + entries: self.map.iter().map(|(k, v)| (k.to_owned(), v)).collect(), + env, + current: 0, + } + } + + #[napi] + pub fn keys(&self) -> YMapKeyIterator { + YMapKeyIterator { + keys: self.map.keys().map(ToOwned::to_owned).collect(), + current: 0, + } + } + + #[napi] + pub fn values(&self, env: Env) -> YMapValuesIterator { + YMapValuesIterator { + entries: self.map.iter().map(|(_, v)| v).collect(), + env, + current: 0, + } + } + + // TODO(@darkskygit): impl type based observe + #[napi] + pub fn observe(&mut self, _callback: JsFunction) -> Result<()> { + Ok(()) + } + + // TODO(@darkskygit): impl type based observe + #[napi] + pub fn observe_deep(&mut self, _callback: JsFunction) -> Result<()> { + Ok(()) + } +} + +#[napi(iterator)] +pub struct YMapEntriesIterator { + entries: Vec<(String, Value)>, + env: Env, + current: i64, +} + +#[napi] +impl Generator for YMapEntriesIterator { + type Yield = JsArray; + + type Next = Option; + + type Return = (); + + fn next(&mut self, value: Option) -> Option { + let current = self.current as usize; + if self.entries.len() <= current { + return None; + } + let ret = if let Some((string, value)) = self.entries.get(current) { + let mut js_array = self.env.create_array(2).ok()?; + js_array.set(0, string).ok()?; + js_array + .set(1, get_mixed_y_type_from_value(self.env, value.clone(), false).ok()?) + .ok()?; + Some(js_array) + } else { + None + }; + self.current = if let Some(value) = value.and_then(|v| v) { + value + } else { + self.current + 1 + }; + ret + } +} + +#[napi(iterator)] +pub struct YMapKeyIterator { + keys: Vec, + current: i64, +} + +#[napi] +impl Generator for YMapKeyIterator { + type Yield = String; + + type Next = Option; + + type Return = (); + + fn next(&mut self, value: Option) -> Option { + let current = self.current as usize; + if self.keys.len() <= current { + return None; + } + let ret = self.keys.get(current).cloned(); + self.current = if let Some(value) = value.and_then(|v| v) { + value + } else { + self.current + 1 + }; + ret + } +} + +#[napi(iterator)] +pub struct YMapValuesIterator { + entries: Vec, + env: Env, + current: i64, +} + +#[napi] +impl Generator for YMapValuesIterator { + type Yield = MixedYType; + + type Next = Option; + + type Return = (); + + fn next(&mut self, value: Option) -> Option { + let current = self.current as usize; + if self.entries.len() <= current { + return None; + } + let ret = if let Some(value) = self.entries.get(current) { + get_mixed_y_type_from_value(self.env, value.clone(), false).ok() + } else { + None + }; + self.current = if let Some(value) = value.and_then(|v| v) { + value + } else { + self.current + 1 + }; + ret + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_map_init() { + let doc = YDoc::new(None); + let text = doc.get_or_create_map("map".into()).unwrap(); + assert_eq!(text.length(), 0); + } +} diff --git a/y-octo-node/native/src/protocol.rs b/y-octo-node/native/src/protocol.rs new file mode 100644 index 0000000..c8229fb --- /dev/null +++ b/y-octo-node/native/src/protocol.rs @@ -0,0 +1,75 @@ +use napi::bindgen_prelude::Buffer; +use y_octo::{ + read_doc_message, write_doc_message, CrdtRead, CrdtWrite, Doc, DocMessage, RawDecoder, RawEncoder, StateVector, +}; + +use super::*; + +#[napi] +pub struct YProtocol { + pub(crate) doc: Doc, +} + +#[napi] +impl YProtocol { + #[napi(constructor)] + pub fn new(doc: &YDoc) -> Self { + Self { doc: doc.doc.clone() } + } + + #[napi] + pub fn encode_sync_step(&self, step: u8, buffer: Option) -> Result { + match step { + 1 => { + let sv = self.doc.get_state_vector(); + let mut encoder = RawEncoder::default(); + sv.write(&mut encoder)?; + + let mut buffer = vec![]; + write_doc_message(&mut buffer, &DocMessage::Step1(encoder.into_inner()))?; + Ok(buffer.into()) + } + 2 => { + if let Some(sv) = buffer { + let sv = StateVector::read(&mut RawDecoder::new(&sv))?; + let update = self.doc.encode_state_as_update_v1(&sv)?; + let mut buffer = vec![]; + write_doc_message(&mut buffer, &DocMessage::Step2(update)).unwrap(); + Ok(buffer.into()) + } else { + Err(anyhow::Error::msg("State vector is required for sync step 2.")) + } + } + 3 => { + let update = if let Some(update) = buffer { + update.to_vec() + } else { + self.doc.encode_update_v1()? + }; + let mut buffer = vec![]; + write_doc_message(&mut buffer, &DocMessage::Update(update)).unwrap(); + Ok(buffer.into()) + } + _ => Err(anyhow::Error::msg("Invalid sync step. Must be 1, 2, or 3.")), + } + } + + #[napi] + pub fn apply_sync_step(&mut self, buffer: Buffer) -> Result> { + match read_doc_message(buffer.as_ref()) { + Ok((tail, message)) => { + if !tail.is_empty() { + return Err(anyhow::Error::msg("Invalid sync message buffer.")); + } + Ok(match message { + DocMessage::Step1(sv) => Some(self.encode_sync_step(2, Some(sv.into()))?), + DocMessage::Step2(binary) | DocMessage::Update(binary) => { + self.doc.apply_update_from_binary_v1(binary)?; + None + } + }) + } + Err(e) => Err(anyhow::Error::msg(format!("Invalid sync message buffer: {}", e))), + } + } +} diff --git a/y-octo-node/src/text.rs b/y-octo-node/native/src/text.rs similarity index 64% rename from y-octo-node/src/text.rs rename to y-octo-node/native/src/text.rs index cd4fadb..a6634e6 100644 --- a/y-octo-node/src/text.rs +++ b/y-octo-node/native/src/text.rs @@ -1,20 +1,16 @@ +use napi::{bindgen_prelude::Array as JsArray, Env, JsFunction}; use y_octo::Text; use super::*; #[napi] +#[derive(Clone)] pub struct YText { pub(crate) text: Text, } #[napi] impl YText { - #[allow(clippy::new_without_default)] - #[napi(constructor)] - pub fn new() -> Self { - unimplemented!() - } - pub(crate) fn inner_new(text: Text) -> Self { Self { text } } @@ -35,7 +31,7 @@ impl YText { } #[napi] - pub fn remove(&mut self, index: i64, len: i64) -> Result<()> { + pub fn delete(&mut self, index: i64, len: i64) -> Result<()> { self.text.remove(index as u64, len as u64).map_err(anyhow::Error::from) } @@ -44,11 +40,33 @@ impl YText { self.text.len() as i64 } + #[napi(ts_args_type = "delta: any[]")] + pub fn apply_delta(&mut self, _env: Env, _delta: JsArray) -> Result<()> { + unimplemented!() + } + + #[napi(ts_return_type = "any[]")] + pub fn to_delta(&self, _env: Env) -> Result { + unimplemented!() + } + #[allow(clippy::inherent_to_string)] #[napi] pub fn to_string(&self) -> String { self.text.to_string() } + + // TODO(@darkskygit): impl type based observe + #[napi] + pub fn observe(&mut self, _callback: JsFunction) -> Result<()> { + Ok(()) + } + + // TODO(@darkskygit): impl type based observe + #[napi] + pub fn observe_deep(&mut self, _callback: JsFunction) -> Result<()> { + Ok(()) + } } #[cfg(test)] @@ -57,20 +75,20 @@ mod tests { #[test] fn test_text_init() { - let doc = Doc::new(None); + let doc = YDoc::new(None); let text = doc.get_or_create_text("text".into()).unwrap(); assert_eq!(text.len(), 0); } #[test] fn test_text_edit() { - let doc = Doc::new(None); + let doc = YDoc::new(None); let mut text = doc.get_or_create_text("text".into()).unwrap(); text.insert(0, "hello".into()).unwrap(); assert_eq!(text.to_string(), "hello"); text.insert(5, " world".into()).unwrap(); assert_eq!(text.to_string(), "hello world"); - text.remove(5, 6).unwrap(); + text.delete(5, 6).unwrap(); assert_eq!(text.to_string(), "hello"); } } diff --git a/y-octo-node/native/src/types.rs b/y-octo-node/native/src/types.rs new file mode 100644 index 0000000..2abb710 --- /dev/null +++ b/y-octo-node/native/src/types.rs @@ -0,0 +1,41 @@ +use y_octo::{CrdtWrite, DeleteSet, Doc, Id, RawEncoder, StateVector}; + +use super::*; + +#[napi(js_name = "Id")] +pub struct YId { + pub(crate) id: Id, +} + +#[napi(js_name = "Store")] +pub struct YStore { + pub(crate) doc: Doc, +} + +#[napi(js_name = "DeleteSet")] +#[derive(PartialEq)] +pub struct YDeleteSet { + pub(crate) ds: DeleteSet, +} + +#[napi] +pub struct YSnapshot { + ds: DeleteSet, + sv: StateVector, +} + +impl YSnapshot { + pub fn from_doc(doc: &YDoc) -> Self { + Self { + ds: doc.doc.get_delete_sets(), + sv: doc.doc.get_state_vector(), + } + } + + pub fn encode_v1(&self) -> Result> { + let mut encoder = RawEncoder::default(); + self.ds.write(&mut encoder)?; + self.sv.write(&mut encoder)?; + Ok(encoder.into_inner()) + } +} diff --git a/y-octo-node/native/src/utils/from_js.rs b/y-octo-node/native/src/utils/from_js.rs new file mode 100644 index 0000000..18ab5e8 --- /dev/null +++ b/y-octo-node/native/src/utils/from_js.rs @@ -0,0 +1,57 @@ +use napi::{Error, JsObject, Status, ValueType}; +use y_octo::{AHashMap, Any, HashMapExt}; + +use super::*; + +pub fn get_any_from_js_object(object: JsObject) -> Result { + if let Ok(length) = object.get_array_length() { + let mut array = Vec::with_capacity(length as usize); + for i in 0..length { + if let Ok(value) = object.get_element::(i) { + array.push(get_any_from_js_unknown(value)?); + } + } + Ok(Any::Array(array)) + } else { + let mut map = AHashMap::new(); + let keys = object.get_property_names()?; + if let Ok(length) = keys.get_array_length() { + for i in 0..length { + if let Ok((obj, key)) = keys.get_element::(i).and_then(|o| { + o.coerce_to_string() + .and_then(|obj| obj.into_utf8().and_then(|s| s.as_str().map(|s| (obj, s.to_string())))) + }) { + if let Ok(value) = object.get_property::<_, JsUnknown>(obj) { + map.insert(key, get_any_from_js_unknown(value)?); + } + } + } + } + Ok(Any::Object(map)) + } +} + +pub fn get_any_from_js_unknown(js_unknown: JsUnknown) -> Result { + match js_unknown.get_type()? { + ValueType::Undefined => Ok(Any::Undefined), + ValueType::Null => Ok(Any::Null), + ValueType::Boolean => Ok(js_unknown.coerce_to_bool().and_then(|v| v.get_value())?.into()), + ValueType::Number => Ok(js_unknown + .coerce_to_number() + .and_then(|v| v.get_double()) + .map(|v| v.into())?), + ValueType::String => Ok(js_unknown + .coerce_to_string() + .and_then(|v| v.into_utf8()) + .and_then(|s| s.as_str().map(|s| s.to_string()))? + .into()), + ValueType::Object => { + if let Ok(object) = js_unknown.coerce_to_object() { + get_any_from_js_object(object) + } else { + Err(Error::new(Status::InvalidArg, "Failed to coerce value to object")) + } + } + _ => Err(Error::new(Status::InvalidArg, "Failed to coerce value to any")), + } +} diff --git a/y-octo-node/native/src/utils/mod.rs b/y-octo-node/native/src/utils/mod.rs new file mode 100644 index 0000000..f79cb1a --- /dev/null +++ b/y-octo-node/native/src/utils/mod.rs @@ -0,0 +1,10 @@ +mod from_js; +mod to_js; +mod ytype; + +pub use from_js::*; +use napi::{Env, JsUnknown, Result}; +pub use to_js::*; +pub use ytype::*; + +use super::*; diff --git a/y-octo-node/native/src/utils/to_js.rs b/y-octo-node/native/src/utils/to_js.rs new file mode 100644 index 0000000..7a954f3 --- /dev/null +++ b/y-octo-node/native/src/utils/to_js.rs @@ -0,0 +1,64 @@ +use y_octo::{Any, Value}; + +use super::*; + +pub fn get_js_unknown_from_any(env: Env, any: Any) -> Result { + match any { + Any::Undefined => env.get_undefined().map(|v| v.into_unknown()), + Any::Null => env.get_null().map(|v| v.into_unknown()), + Any::True => env.get_boolean(true).map(|v| v.into_unknown()), + Any::False => env.get_boolean(false).map(|v| v.into_unknown()), + Any::Integer(number) => env.create_int32(number).map(|v| v.into_unknown()), + Any::BigInt64(number) => env.create_int64(number).map(|v| v.into_unknown()), + Any::Float32(number) => env.create_double(number.0 as f64).map(|v| v.into_unknown()), + Any::Float64(number) => env.create_double(number.0).map(|v| v.into_unknown()), + Any::String(string) => env.create_string(string.as_str()).map(|v| v.into_unknown()), + Any::Array(array) => { + let mut js_array = env.create_array_with_length(array.len())?; + for (i, value) in array.into_iter().enumerate() { + js_array.set_element(i as u32, get_js_unknown_from_any(env, value)?)?; + } + Ok(js_array.into_unknown()) + } + Any::Object(object) => { + let mut js_object = env.create_object()?; + for (key, value) in object.into_iter() { + js_object.set_named_property(&key, get_js_unknown_from_any(env, value)?)?; + } + Ok(js_object.into_unknown()) + } + _ => env.get_undefined().map(|v| v.into_unknown()), + } +} + +pub fn get_mixed_y_type_from_value(env: Env, value: Value, cascading: bool) -> Result { + match value { + Value::Any(any) => get_js_unknown_from_any(env, any).map(MixedYType::D), + Value::Array(array) => { + if cascading { + let mut js_array = env.create_array_with_length(array.len() as usize)?; + for (i, value) in array.iter().enumerate() { + let value = get_mixed_y_type_from_value(env, value, cascading)?; + let instance = MixedClassYType::try_from((env, value))?; + js_array.set_element(i as u32, instance.into_inner())?; + } + Ok(MixedYType::D(js_array.into_unknown())) + } else { + Ok(YArray::inner_new(array).into()) + } + } + Value::Map(map) => { + if cascading { + let mut js_object = env.create_object()?; + for (key, value) in map.iter() { + js_object.set_named_property(key, get_mixed_y_type_from_value(env, value, cascading)?)?; + } + Ok(MixedYType::D(js_object.into_unknown())) + } else { + Ok(YMap::inner_new(map).into()) + } + } + Value::Text(text) => Ok(YText::inner_new(text).into()), + _ => env.get_undefined().map(|v| v.into_unknown()).map(MixedYType::D), + } +} diff --git a/y-octo-node/native/src/utils/ytype.rs b/y-octo-node/native/src/utils/ytype.rs new file mode 100644 index 0000000..396767e --- /dev/null +++ b/y-octo-node/native/src/utils/ytype.rs @@ -0,0 +1,50 @@ +use napi::bindgen_prelude::Either4; + +use super::*; + +pub type MixedRefYType<'a> = Either4<&'a YArray, &'a YMap, &'a YText, JsUnknown>; + +pub type MixedYType = Either4; + +//make a macro to generate the impl Into for each type + +macro_rules! impl_into_mixed_y_type { + ($type:ty, $enum:ident) => { + #[allow(clippy::from_over_into)] + impl Into for $type { + fn into(self) -> MixedYType { + MixedYType::$enum(self.clone()) + } + } + }; +} + +impl_into_mixed_y_type!(YArray, A); +impl_into_mixed_y_type!(&YArray, A); +impl_into_mixed_y_type!(YMap, B); +impl_into_mixed_y_type!(&YMap, B); +impl_into_mixed_y_type!(YText, C); +impl_into_mixed_y_type!(&YText, C); + +pub struct MixedClassYType(pub JsUnknown); + +impl TryFrom<(Env, MixedYType)> for MixedClassYType { + type Error = napi::Error; + + fn try_from(params: (Env, MixedYType)) -> Result { + let (env, instance) = params; + let ret = match instance { + Either4::A(i) => Either4::A(i.into_instance(env)?), + Either4::B(i) => Either4::B(i.into_instance(env)?), + Either4::C(i) => Either4::C(i.into_instance(env)?), + Either4::D(i) => Either4::D(i), + }; + Ok(Self(ret.as_unknown(env))) + } +} + +impl MixedClassYType { + pub fn into_inner(self) -> JsUnknown { + self.0 + } +} diff --git a/y-octo-node/package.json b/y-octo-node/package.json index 4b5c403..5ac019d 100644 --- a/y-octo-node/package.json +++ b/y-octo-node/package.json @@ -1,11 +1,13 @@ { "name": "@y-octo/node", "private": true, - "main": "index.js", - "types": "index.d.ts", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "exports": "./dist/index.js", "napi": { - "name": "y-octo", - "triples": { + "binaryName": "y-octo", + "target": { "additional": [ "aarch64-apple-darwin", "aarch64-pc-windows-msvc", @@ -20,33 +22,38 @@ }, "license": "MIT", "devDependencies": { - "@napi-rs/cli": "^2.16.2", - "@types/node": "^18.17.5", + "@napi-rs/cli": "^3.0.0-alpha.62", + "@types/node": "^20.16.4", "@types/prompts": "^2.4.4", - "c8": "^8.0.1", + "ava": "^6.1.3", + "c8": "^10.1.2", + "pkgroll": "^2.5.0", "prompts": "^2.4.2", - "ts-node": "^10.9.2", + "tsx": "^4.16.2", "typescript": "^5.1.6", - "yjs": "^13.6.8" + "yjs": "^13.6.18" }, "engines": { "node": ">= 10" }, "scripts": { "artifacts": "napi artifacts", - "build": "napi build --platform --release --no-const-enum", - "build:debug": "napi build --platform --no-const-enum", + "build": "yarn build:binding && yarn build:js", + "build:debug": "yarn build:binding:debug && yarn build:js", + "build:js": "pkgroll -- -", + "build:binding": "yarn build:binding:debug --release", + "build:binding:debug": "napi build --platform --no-const-enum --manifest-path native/Cargo.toml --dts ../src/yocto.d.ts --js ../src/yocto.js -o ./dist", "universal": "napi universal", - "test": "NODE_NO_WARNINGS=1 yarn exec ts-node-esm ./scripts/run-test.mts all", - "test:watch": "yarn exec ts-node-esm ./scripts/run-test.ts all --watch", - "test:coverage": "NODE_OPTIONS=\"--loader ts-node/esm\" c8 node ./scripts/run-test.mts all", + "test": "ava --concurrency 1 --serial --timeout 5s", + "test:watch": "yarn test --watch", + "test:coverage": "c8 ava --concurrency 1 --serial", "version": "napi version" }, "version": "0.0.1", "sharedConfig": { "nodeArgs": [ - "--loader", - "ts-node/esm", + "--import", + "tsx", "--es-module-specifier-resolution=node" ], "env": { @@ -56,6 +63,26 @@ "DEBUG": "napi:*" } }, + "ava": { + "timeout": "1m", + "extensions": { + "ts": "module" + }, + "workerThreads": false, + "nodeArguments": [ + "--trace-sigint", + "--import", + "tsx", + "--es-module-specifier-resolution=node" + ], + "files": [ + "tests/**/*.spec.ts" + ], + "environmentVariables": { + "TS_NODE_PROJECT": "./tests/tsconfig.json", + "NODE_ENV": "test" + } + }, "c8": { "reporter": [ "text", diff --git a/y-octo-node/scripts/run-test.mts b/y-octo-node/scripts/run-test.mts deleted file mode 100755 index 2ee63fe..0000000 --- a/y-octo-node/scripts/run-test.mts +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env ts-node-esm -import { resolve } from "node:path"; - -import prompts from "prompts"; -import { spawn } from "child_process"; -import { readdir } from "fs/promises"; -import * as process from "process"; -import { fileURLToPath } from "url"; - -import pkg from "../package.json" assert { type: "json" }; -const root = fileURLToPath(new URL("..", import.meta.url)); -const testDir = resolve(root, "tests"); -const files = await readdir(testDir); - -const watchMode = process.argv.includes("--watch"); - -const sharedArgs = [ - ...pkg.sharedConfig.nodeArgs, - "--test", - watchMode ? "--watch" : "", -]; - -const env = { - ...pkg.sharedConfig.env, - PATH: process.env.PATH, - NODE_ENV: "test", - NODE_NO_WARNINGS: "1", -}; - -if (process.argv[2] === "all") { - const cp = spawn( - "node", - [...sharedArgs, ...files.map((f) => resolve(testDir, f))], - { - cwd: root, - env, - stdio: "inherit", - shell: true, - }, - ); - cp.on("exit", (code) => { - process.exit(code ?? 0); - }); -} else { - const result = await prompts([ - { - type: "select", - name: "file", - message: "Select a file to run", - choices: files.map((file) => ({ - title: file, - value: file, - })), - initial: 1, - }, - ]); - - const target = resolve(testDir, result.file); - - const cp = spawn( - "node", - [ - ...sharedArgs, - "--test-reporter=spec", - "--test-reporter-destination=stdout", - target, - ], - { - cwd: root, - env, - stdio: "inherit", - shell: true, - }, - ); - cp.on("exit", (code) => { - process.exit(code ?? 0); - }); -} diff --git a/y-octo-node/src/array.rs b/y-octo-node/src/array.rs deleted file mode 100644 index 2a10396..0000000 --- a/y-octo-node/src/array.rs +++ /dev/null @@ -1,142 +0,0 @@ -use napi::{bindgen_prelude::Array as JsArray, Env, JsUnknown, ValueType}; -use y_octo::{Any, Array, Value}; - -use super::*; - -#[napi] -pub struct YArray { - pub(crate) array: Array, -} - -#[napi] -impl YArray { - #[allow(clippy::new_without_default)] - #[napi(constructor)] - pub fn new() -> Self { - unimplemented!() - } - - pub(crate) fn inner_new(array: Array) -> Self { - Self { array } - } - - #[napi(getter)] - pub fn length(&self) -> i64 { - self.array.len() as i64 - } - - #[napi(getter)] - pub fn is_empty(&self) -> bool { - self.array.is_empty() - } - - #[napi(ts_generic_types = "T = unknown", ts_return_type = "T")] - pub fn get(&self, env: Env, index: i64) -> Result { - if let Some(value) = self.array.get(index as u64) { - match value { - Value::Any(any) => get_js_unknown_from_any(env, any).map(MixedYType::D), - Value::Array(array) => Ok(MixedYType::A(YArray::inner_new(array))), - Value::Map(map) => Ok(MixedYType::B(YMap::inner_new(map))), - Value::Text(text) => Ok(MixedYType::C(YText::inner_new(text))), - _ => env.get_null().map(|v| v.into_unknown()).map(MixedYType::D), - } - .map_err(anyhow::Error::from) - } else { - Ok(MixedYType::D(env.get_null()?.into_unknown())) - } - } - - #[napi( - ts_args_type = "index: number, value: YArray | YMap | YText | boolean | number | string | Record \ - | null | undefined" - )] - pub fn insert(&mut self, index: i64, value: MixedRefYType) -> Result<()> { - match value { - MixedRefYType::A(array) => self - .array - .insert(index as u64, array.array.clone()) - .map_err(anyhow::Error::from), - MixedRefYType::B(map) => self - .array - .insert(index as u64, map.map.clone()) - .map_err(anyhow::Error::from), - MixedRefYType::C(text) => self - .array - .insert(index as u64, text.text.clone()) - .map_err(anyhow::Error::from), - MixedRefYType::D(unknown) => match unknown.get_type() { - Ok(value_type) => match value_type { - ValueType::Undefined | ValueType::Null => { - self.array.insert(index as u64, Any::Null).map_err(anyhow::Error::from) - } - ValueType::Boolean => match unknown.coerce_to_bool().and_then(|v| v.get_value()) { - Ok(boolean) => self.array.insert(index as u64, boolean).map_err(anyhow::Error::from), - Err(e) => Err(anyhow::Error::new(e).context("Failed to coerce value to boolean")), - }, - ValueType::Number => match unknown.coerce_to_number().and_then(|v| v.get_double()) { - Ok(number) => self.array.insert(index as u64, number).map_err(anyhow::Error::from), - Err(e) => Err(anyhow::Error::new(e).context("Failed to coerce value to number")), - }, - ValueType::String => { - match unknown - .coerce_to_string() - .and_then(|v| v.into_utf8()) - .and_then(|s| s.as_str().map(|s| s.to_string())) - { - Ok(string) => self.array.insert(index as u64, string).map_err(anyhow::Error::from), - Err(e) => Err(anyhow::Error::new(e).context("Failed to coerce value to string")), - } - } - ValueType::Object => match unknown - .coerce_to_object() - .and_then(|o| o.get_array_length().map(|l| (o, l))) - { - Ok((object, length)) => { - for i in 0..length { - if let Ok(any) = object.get_element::(i).and_then(get_any_from_js_unknown) { - self.array - .insert(index as u64 + i as u64, Value::Any(any)) - .map_err(anyhow::Error::from)?; - } - } - Ok(()) - } - Err(e) => Err(anyhow::Error::new(e).context("Failed to coerce value to object")), - }, - ValueType::Symbol => Err(anyhow::Error::msg("Symbol values are not supported")), - ValueType::Function => Err(anyhow::Error::msg("Function values are not supported")), - ValueType::External => Err(anyhow::Error::msg("External values are not supported")), - ValueType::Unknown => Err(anyhow::Error::msg("Unknown values are not supported")), - }, - Err(e) => Err(anyhow::Error::from(e)), - }, - } - } - - #[napi] - pub fn remove(&mut self, index: i64, len: i64) -> Result<()> { - self.array.remove(index as u64, len as u64).map_err(anyhow::Error::from) - } - - #[napi] - pub fn to_json(&self, env: Env) -> Result { - let mut js_array = env.create_array(0)?; - for value in self.array.iter() { - js_array.insert(get_js_unknown_from_value(env, value)?)?; - } - Ok(js_array) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - fn test_array_init() { - let doc = Doc::new(None); - let array = doc.get_or_create_array("array".into()).unwrap(); - assert_eq!(array.length(), 0); - } -} diff --git a/y-octo-node/src/array.ts b/y-octo-node/src/array.ts new file mode 100644 index 0000000..36fccb1 --- /dev/null +++ b/y-octo-node/src/array.ts @@ -0,0 +1,140 @@ +import * as Y from "./yocto"; +import { Doc } from "./doc"; +import { Map } from "./map"; +import type { ArrayType, ListItem } from "./types"; + +export class Array { + private ytype?: { doc: Doc; array: Y.YArray }; + private preliminary: any[] = []; + + get itemId() { + return this.ytype?.array.itemId; + } + + static from(items: T[]): Array { + return new Array(items); + } + + static from_ytype(ytype?: { doc: Doc; array: Y.YArray }) { + const array = new Array(); + array.ytype = ytype; + return array; + } + + constructor(items: ArrayType[] = [], ydoc?: Doc, yarray?: Y.YArray) { + this.preliminary = items; + if (ydoc) this.integrate(ydoc, yarray); + } + + integrate(ydoc: Doc, yarray?: Y.YArray): Y.YArray { + if (!this.ytype) { + this.ytype = { doc: ydoc, array: yarray || ydoc.createArray() }; + for (const item of this.preliminary) { + if (item instanceof Array) { + this.ytype.array.push(item.integrate(ydoc)); + } else { + this.ytype.array.push(item); + } + } + this.preliminary = []; + this.ytype.doc.triggerDiff(); + } + return this.ytype.array; + } + + get length(): number { + return this.ytype ? this.ytype.array.length : this.preliminary.length; + } + + get isEmpty(): boolean { + return this.ytype + ? this.ytype.array.isEmpty + : this.preliminary.length === 0; + } + + get(index: number): T { + return this.ytype ? this.ytype.array.get(index) : this.preliminary[index]; + } + + slice(start: number, end?: number): T[] { + return this.ytype + ? this.ytype.array.slice(start, end) + : this.preliminary.slice(start, end); + } + + map(callback: (...args: any[]) => any): T[] { + return this.ytype + ? this.ytype.array.map(callback) + : this.preliminary.map(callback); + } + + insert(index: number, value: ListItem): void { + if (this.ytype) { + if (value instanceof Array || value instanceof Map) { + this.ytype.array.insert(index, value.integrate(this.ytype.doc)); + } else { + this.ytype.array.insert(index, value); + } + this.ytype.doc.triggerDiff(); + } else { + this.preliminary.splice(index, 0, value); + } + } + + push(value?: ListItem): void { + if (this.ytype) { + this.ytype.array.push(value); + this.ytype.doc.triggerDiff(); + } else { + this.preliminary.push(value); + } + } + + unshift(value?: ListItem): void { + if (this.ytype) { + this.ytype.array.unshift(value); + this.ytype.doc.triggerDiff(); + } else { + this.preliminary.unshift(value); + } + } + + delete(index: number, len?: number): void { + if (this.ytype) { + this.ytype.array.delete(index, len); + this.ytype.doc.triggerDiff(); + } else { + this.preliminary.splice(index, len); + } + } + + iter(): Y.YArrayIterator { + return this.ytype + ? this.ytype.array.iter() + : this.preliminary[Symbol.iterator](); + } + + toArray(): any[] { + return this.ytype ? this.ytype.array.toArray() : this.preliminary; + } + + toJSON(): any[] { + return this.ytype ? this.ytype.array.toJSON() : this.preliminary; + } + + observe(callback: (...args: any[]) => any): void { + if (this.ytype) { + this.ytype.array.observe(callback); + } else { + throw new Error("Not implemented"); + } + } + + observeDeep(callback: (...args: any[]) => any): void { + if (this.ytype) { + this.ytype.array.observeDeep(callback); + } else { + throw new Error("Not implemented"); + } + } +} diff --git a/y-octo-node/src/doc.ts b/y-octo-node/src/doc.ts new file mode 100644 index 0000000..e35a02b --- /dev/null +++ b/y-octo-node/src/doc.ts @@ -0,0 +1,85 @@ +import * as Y from "./yocto"; +import { Array } from "./array"; +import { Map } from "./map"; +import type { Text } from "./text"; + +export class Doc extends Y.Doc { + private cachedArray: globalThis.Map = new globalThis.Map(); + private cachedMap: globalThis.Map = new globalThis.Map(); + private subscribers: Set<(result: Uint8Array, origin?: unknown) => void> = + new Set(); + private lastState: Buffer | null = null; + + getArray(key = ""): Array { + if (this.cachedArray.has(key)) { + return this.cachedArray.get(key)!; + } + const yarray = new Array([], this, this.getOrCreateArray(key)); + this.cachedArray.set(key, yarray); + return yarray; + } + + getMap(key = ""): Map { + if (this.cachedMap.has(key)) { + return this.cachedMap.get(key)!; + } + const ymap = new Map({}, this, this.getOrCreateMap(key)); + this.cachedMap.set(key, ymap); + return ymap; + } + + getText(key = ""): Text { + return this.getOrCreateText(key); + } + + triggerDiff(origin?: unknown): void { + let diff: Buffer | null = null; + if (this.lastState) { + diff = this.diff(this.lastState); + const state = this.encodeStateAsUpdateV1(); + if (!this.lastState.equals(state)) { + this.lastState = state; + } else { + return; + } + } else { + this.lastState = this.encodeStateAsUpdateV1(); + diff = this.diff(this.lastState); + } + + // skip empty diffs + if (!diff || diff.equals(new Uint8Array([0, 0]))) { + return; + } + + if (this.lastState?.length && diff?.length) { + this.subscribers.forEach((callback) => + callback(new Uint8Array(diff!), origin || this), + ); + } + } + + transact(callback: (...args: any[]) => any, origin?: unknown): void { + try { + callback(); + } finally { + this.triggerDiff(origin); + } + } + + override applyUpdate(update: Buffer): void { + this.transact(() => { + super.applyUpdate(update); + }); + } + + override onUpdate( + callback: (result: Uint8Array, origin?: unknown) => void, + ): void { + this.subscribers.add(callback); + } + + override offUpdate(): void { + this.subscribers.clear(); + } +} diff --git a/y-octo-node/src/index.ts b/y-octo-node/src/index.ts new file mode 100644 index 0000000..4d74670 --- /dev/null +++ b/y-octo-node/src/index.ts @@ -0,0 +1,6 @@ +export * from "./yocto"; +export { Doc } from "./doc"; +export { Array } from "./array"; +export { Map } from "./map"; +export { Text } from "./text"; +export { Protocol } from "./protocol"; diff --git a/y-octo-node/src/lib.rs b/y-octo-node/src/lib.rs deleted file mode 100644 index f014828..0000000 --- a/y-octo-node/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -use anyhow::Result; -use napi_derive::napi; - -mod array; -mod doc; -mod map; -mod text; -mod utils; - -pub use array::YArray; -pub use doc::Doc; -pub use map::YMap; -pub use text::YText; -use utils::{ - get_any_from_js_object, get_any_from_js_unknown, get_js_unknown_from_any, get_js_unknown_from_value, MixedRefYType, - MixedYType, -}; diff --git a/y-octo-node/src/map.rs b/y-octo-node/src/map.rs deleted file mode 100644 index 4d1fe08..0000000 --- a/y-octo-node/src/map.rs +++ /dev/null @@ -1,121 +0,0 @@ -use napi::{Env, JsObject, ValueType}; -use y_octo::{Any, Map, Value}; - -use super::*; - -#[napi] -pub struct YMap { - pub(crate) map: Map, -} - -#[napi] -impl YMap { - #[allow(clippy::new_without_default)] - #[napi(constructor)] - pub fn new() -> Self { - unimplemented!() - } - - pub(crate) fn inner_new(map: Map) -> Self { - Self { map } - } - - #[napi(getter)] - pub fn length(&self) -> i64 { - self.map.len() as i64 - } - - #[napi(getter)] - pub fn is_empty(&self) -> bool { - self.map.is_empty() - } - - #[napi(ts_generic_types = "T = unknown", ts_return_type = "T")] - pub fn get(&self, env: Env, key: String) -> Result { - if let Some(value) = self.map.get(&key) { - match value { - Value::Any(any) => get_js_unknown_from_any(env, any).map(MixedYType::D), - Value::Array(array) => Ok(MixedYType::A(YArray::inner_new(array))), - Value::Map(map) => Ok(MixedYType::B(YMap::inner_new(map))), - Value::Text(text) => Ok(MixedYType::C(YText::inner_new(text))), - _ => env.get_null().map(|v| v.into_unknown()).map(MixedYType::D), - } - .map_err(anyhow::Error::from) - } else { - Ok(MixedYType::D(env.get_null()?.into_unknown())) - } - } - - #[napi( - ts_args_type = "key: string, value: YArray | YMap | YText | boolean | number | string | Record | \ - null | undefined" - )] - pub fn set(&mut self, key: String, value: MixedRefYType) -> Result<()> { - match value { - MixedRefYType::A(array) => self.map.insert(key, array.array.clone()).map_err(anyhow::Error::from), - MixedRefYType::B(map) => self.map.insert(key, map.map.clone()).map_err(anyhow::Error::from), - MixedRefYType::C(text) => self.map.insert(key, text.text.clone()).map_err(anyhow::Error::from), - MixedRefYType::D(unknown) => match unknown.get_type() { - Ok(value_type) => match value_type { - ValueType::Undefined | ValueType::Null => { - self.map.insert(key, Any::Null).map_err(anyhow::Error::from) - } - ValueType::Boolean => match unknown.coerce_to_bool().and_then(|v| v.get_value()) { - Ok(boolean) => self.map.insert(key, boolean).map_err(anyhow::Error::from), - Err(e) => Err(anyhow::Error::from(e).context("Failed to coerce value to boolean")), - }, - ValueType::Number => match unknown.coerce_to_number().and_then(|v| v.get_double()) { - Ok(number) => self.map.insert(key, number).map_err(anyhow::Error::from), - Err(e) => Err(anyhow::Error::from(e).context("Failed to coerce value to number")), - }, - ValueType::String => { - match unknown - .coerce_to_string() - .and_then(|v| v.into_utf8()) - .and_then(|s| s.as_str().map(|s| s.to_string())) - { - Ok(string) => self.map.insert(key, string).map_err(anyhow::Error::from), - Err(e) => Err(anyhow::Error::from(e).context("Failed to coerce value to string")), - } - } - ValueType::Object => match unknown.coerce_to_object().and_then(get_any_from_js_object) { - Ok(any) => self.map.insert(key, Value::Any(any)).map_err(anyhow::Error::from), - Err(e) => Err(anyhow::Error::from(e).context("Failed to coerce value to object")), - }, - ValueType::Symbol => Err(anyhow::Error::msg("Symbol values are not supported")), - ValueType::Function => Err(anyhow::Error::msg("Function values are not supported")), - ValueType::External => Err(anyhow::Error::msg("External values are not supported")), - ValueType::Unknown => Err(anyhow::Error::msg("Unknown values are not supported")), - }, - Err(e) => Err(anyhow::Error::from(e)), - }, - } - } - - #[napi] - pub fn remove(&mut self, key: String) { - self.map.remove(&key); - } - - #[napi] - pub fn to_json(&self, env: Env) -> Result { - let mut js_object = env.create_object()?; - for (key, value) in self.map.iter() { - js_object.set(key, get_js_unknown_from_value(env, value))?; - } - Ok(js_object) - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - fn test_map_init() { - let doc = Doc::new(None); - let text = doc.get_or_create_map("map".into()).unwrap(); - assert_eq!(text.length(), 0); - } -} diff --git a/y-octo-node/src/map.ts b/y-octo-node/src/map.ts new file mode 100644 index 0000000..39ca2b1 --- /dev/null +++ b/y-octo-node/src/map.ts @@ -0,0 +1,140 @@ +import * as Y from "./yocto"; +import { Array } from "./array"; +import type { Doc } from "./doc"; +import type { ListItem } from "./types"; + +export class Map { + private ytype?: { doc: Doc; map: Y.YMap }; + private preliminary: Record = {}; + + static from_ytype(ytype?: { doc: Doc; map: Y.YMap }) { + const map = new Map(); + map.ytype = ytype; + return map; + } + + constructor(items: Record = {}, ydoc?: Doc, ymap?: Y.YMap) { + this.preliminary = items; + if (ydoc) this.integrate(ydoc, ymap); + } + + integrate(ydoc: Doc, ymap?: Y.YMap): Y.YMap { + if (!this.ytype) { + this.ytype = { doc: ydoc, map: ymap || ydoc.createMap() }; + for (const [key, val] of Object.entries(this.preliminary)) { + if (val instanceof Array) { + this.ytype.map.set(key, val.integrate(ydoc)); + } else { + this.ytype.map.set(key, val); + } + } + this.preliminary = {}; + this.ytype.doc.triggerDiff(); + } + return this.ytype.map; + } + + get length(): number { + return this.ytype + ? this.ytype.map.length + : Object.keys(this.preliminary).length; + } + + get size(): number { + return this.length; + } + + get isEmpty(): boolean { + return this.ytype ? this.ytype.map.isEmpty : this.length === 0; + } + + get itemId(): Y.YId | null { + return this.ytype?.map.itemId || null; + } + + get(key: string): T { + if (this.ytype) { + const ret = this.ytype.map.get(key); + if (ret) { + if (ret instanceof Y.YArray) { + return Array.from_ytype({ doc: this.ytype.doc, array: ret }) as T; + } else if (ret instanceof Y.YMap) { + return Map.from_ytype({ doc: this.ytype.doc, map: ret }) as T; + } + } + return ret as T; + } else { + return this.preliminary[key]; + } + } + + set(key: string, value: T) { + if (this.ytype) { + if (value instanceof Array || value instanceof Map) { + this.ytype.map.set(key, value.integrate(this.ytype.doc)); + } else { + this.ytype.map.set(key, value); + } + this.ytype.doc.triggerDiff(); + } else { + this.preliminary[key] = value; + } + return value; + } + + delete(key: string): void { + if (this.ytype) { + this.ytype.map.delete(key); + this.ytype.doc.triggerDiff(); + } else { + delete this.preliminary[key]; + } + } + + clear(): void { + if (this.ytype) { + this.ytype.map.clear(); + this.ytype.doc.triggerDiff(); + } else { + this.preliminary = {}; + } + } + + toJSON(): Record { + return this.ytype + ? this.ytype.map.toJSON() + : JSON.parse(JSON.stringify(this.preliminary)); + } + + entries(): Y.YMapEntriesIterator { + return this.ytype + ? this.ytype.map.entries() + : Object.entries(this.preliminary); + } + + keys(): Y.YMapKeyIterator { + return this.ytype ? this.ytype.map.keys() : Object.keys(this.preliminary); + } + + values(): Y.YMapValuesIterator { + return this.ytype + ? this.ytype.map.values() + : Object.values(this.preliminary); + } + + observe(callback: (...args: any[]) => any): void { + if (this.ytype) { + this.ytype.map.observe(callback); + } else { + throw new Error("Not implemented"); + } + } + + observeDeep(callback: (...args: any[]) => any): void { + if (this.ytype) { + this.ytype.map.observeDeep(callback); + } else { + throw new Error("Not implemented"); + } + } +} diff --git a/y-octo-node/src/protocol.ts b/y-octo-node/src/protocol.ts new file mode 100644 index 0000000..1865e46 --- /dev/null +++ b/y-octo-node/src/protocol.ts @@ -0,0 +1,16 @@ +import * as Y from "./yocto"; +import type { Doc } from "./doc"; + +export class Protocol extends Y.YProtocol { + constructor(private readonly doc: Doc) { + super(doc); + } + + override applySyncStep(buffer: Buffer): Buffer | null { + try { + return super.applySyncStep(buffer); + } finally { + this.doc.triggerDiff(this.doc); + } + } +} diff --git a/y-octo-node/src/text.ts b/y-octo-node/src/text.ts new file mode 100644 index 0000000..7a59c4e --- /dev/null +++ b/y-octo-node/src/text.ts @@ -0,0 +1,3 @@ +import * as Y from "./yocto"; + +export class Text extends Y.YText {} diff --git a/y-octo-node/src/types.ts b/y-octo-node/src/types.ts new file mode 100644 index 0000000..fe6321d --- /dev/null +++ b/y-octo-node/src/types.ts @@ -0,0 +1,19 @@ +import type { Array } from "./array"; +import type { Map } from "./map"; + +export type ArrayType = + | string + | number + | any[] + | Uint8Array + | { [x: string]: any } + | null; +export type ListItem = + | Array + | Map + | Text + | boolean + | number + | string + | Record + | null; diff --git a/y-octo-node/src/utils.rs b/y-octo-node/src/utils.rs deleted file mode 100644 index a32efc9..0000000 --- a/y-octo-node/src/utils.rs +++ /dev/null @@ -1,97 +0,0 @@ -use napi::{bindgen_prelude::Either4, Env, Error, JsObject, JsUnknown, Result, Status, ValueType}; -use y_octo::{AHashMap, Any, HashMapExt, Value}; - -use super::*; - -pub type MixedYType = Either4; -pub type MixedRefYType<'a> = Either4<&'a YArray, &'a YMap, &'a YText, JsUnknown>; - -pub fn get_js_unknown_from_any(env: Env, any: Any) -> Result { - match any { - Any::Null | Any::Undefined => env.get_null().map(|v| v.into_unknown()), - Any::True => env.get_boolean(true).map(|v| v.into_unknown()), - Any::False => env.get_boolean(false).map(|v| v.into_unknown()), - Any::Integer(number) => env.create_int32(number).map(|v| v.into_unknown()), - Any::BigInt64(number) => env.create_int64(number).map(|v| v.into_unknown()), - Any::Float32(number) => env.create_double(number.0 as f64).map(|v| v.into_unknown()), - Any::Float64(number) => env.create_double(number.0).map(|v| v.into_unknown()), - Any::String(string) => env.create_string(string.as_str()).map(|v| v.into_unknown()), - Any::Array(array) => { - let mut js_array = env.create_array_with_length(array.len())?; - for (i, value) in array.into_iter().enumerate() { - js_array.set_element(i as u32, get_js_unknown_from_any(env, value)?)?; - } - Ok(js_array.into_unknown()) - } - _ => env.get_null().map(|v| v.into_unknown()), - } -} - -pub fn get_js_unknown_from_value(env: Env, value: Value) -> Result { - match value { - Value::Any(any) => get_js_unknown_from_any(env, any), - Value::Array(array) => env - .create_external(YArray::inner_new(array), None) - .map(|o| o.into_unknown()), - Value::Map(map) => env - .create_external(YMap::inner_new(map), None) - .map(|o| o.into_unknown()), - Value::Text(text) => env - .create_external(YText::inner_new(text), None) - .map(|o| o.into_unknown()), - _ => env.get_null().map(|v| v.into_unknown()), - } -} - -pub fn get_any_from_js_object(object: JsObject) -> Result { - if let Ok(length) = object.get_array_length() { - let mut array = Vec::with_capacity(length as usize); - for i in 0..length { - if let Ok(value) = object.get_element::(i) { - array.push(get_any_from_js_unknown(value)?); - } - } - Ok(Any::Array(array)) - } else { - let mut map = AHashMap::new(); - let keys = object.get_property_names()?; - if let Ok(length) = keys.get_array_length() { - for i in 0..length { - if let Ok((obj, key)) = keys.get_element::(i).and_then(|o| { - o.coerce_to_string() - .and_then(|obj| obj.into_utf8().and_then(|s| s.as_str().map(|s| (obj, s.to_string())))) - }) { - if let Ok(value) = object.get_property::<_, JsUnknown>(obj) { - println!("key: {}", key); - map.insert(key, get_any_from_js_unknown(value)?); - } - } - } - } - Ok(Any::Object(map)) - } -} - -pub fn get_any_from_js_unknown(js_unknown: JsUnknown) -> Result { - match js_unknown.get_type()? { - ValueType::Undefined | ValueType::Null => Ok(Any::Null), - ValueType::Boolean => Ok(js_unknown.coerce_to_bool().and_then(|v| v.get_value())?.into()), - ValueType::Number => Ok(js_unknown - .coerce_to_number() - .and_then(|v| v.get_double()) - .map(|v| v.into())?), - ValueType::String => Ok(js_unknown - .coerce_to_string() - .and_then(|v| v.into_utf8()) - .and_then(|s| s.as_str().map(|s| s.to_string()))? - .into()), - ValueType::Object => { - if let Ok(object) = js_unknown.coerce_to_object() { - get_any_from_js_object(object) - } else { - Err(Error::new(Status::InvalidArg, "Failed to coerce value to object")) - } - } - _ => Err(Error::new(Status::InvalidArg, "Failed to coerce value to any")), - } -} diff --git a/y-octo-node/src/yjs.d.ts b/y-octo-node/src/yjs.d.ts new file mode 100644 index 0000000..b34cce3 --- /dev/null +++ b/y-octo-node/src/yjs.d.ts @@ -0,0 +1,2065 @@ +// Generated by dts-bundle v0.7.3 +// Dependencies for this module: +// lib0/observable +// lib0/decoding +// lib0/encoding + +import { ObservableV2 } from "lib0/observable"; +import * as decoding from "lib0/decoding"; +import * as encoding from "lib0/encoding"; + +declare module Y { + /** + * A Yjs instance handles the state of shared data. + */ + export class Doc extends ObservableV2 { + constructor(opts?: DocOpts); + gc: boolean; + gcFilter: (arg0: Struct.Item) => boolean; + clientID: number; + guid: string; + collectionid: string | null; + share: Map>>; + store: Struct.StructStore; + subdocs: Set; + shouldLoad: boolean; + autoLoad: boolean; + meta: any; + /** + * This is set to true when the persistence provider loaded the document from the database or when the `sync` event fires. + * Note that not all providers implement this feature. Provider authors are encouraged to fire the `load` event when the doc content is loaded from the database. + */ + isLoaded: boolean; + /** + * This is set to true when the connection provider has successfully synced with a backend. + * Note that when using peer-to-peer providers this event may not provide very useful. + * Also note that not all providers implement this feature. Provider authors are encouraged to fire + * the `sync` event when the doc has been synced (with `true` as a parameter) or if connection is + * lost (with false as a parameter). + */ + isSynced: boolean; + /** + * Promise that resolves once the document has been loaded from a presistence provider. + */ + whenLoaded: Promise; + whenSynced: Promise; + /** + * Notify the parent document that you request to load data into this subdocument (if it is a subdocument). + * + * `load()` might be used in the future to request any provider to load the most current data. + * + * It is safe to call `load()` multiple times. + */ + load(): void; + getSubdocs(): Set; + getSubdocGuids(): Set; + /** + * Changes that happen inside of a transaction are bundled. This means that + * the observer fires _after_ the transaction is finished and that all changes + * that happened inside of the transaction are sent as one message to the + * other peers. + * + * @param {function(Transaction):T} f The function that should be executed as a transaction + * @param {any} [origin] Origin of who started the transaction. Will be stored on transaction.origin + * + * @public + */ + transact(f: (arg0: Transaction) => T, origin?: any): T; + /** + * Define a shared data type. + * + * Multiple calls of `ydoc.get(name, TypeConstructor)` yield the same result + * and do not overwrite each other. I.e. + * `ydoc.get(name, Y.Array) === ydoc.get(name, Y.Array)` + * + * After this method is called, the type is also available on `ydoc.share.get(name)`. + * + * *Best Practices:* + * Define all types right after the Y.Doc instance is created and store them in a separate object. + * Also use the typed methods `getText(name)`, `getArray(name)`, .. + * + * @example + * const ydoc = new Y.Doc(..) + * const appState = { + * document: ydoc.getText('document') + * comments: ydoc.getArray('comments') + * } + * + * @param {Type} TypeConstructor The constructor of the type definition. E.g. Y.Text, Y.Array, Y.Map, ... + * @return {InstanceType} The created type. Constructed with TypeConstructor + */ + get }>( + name: string, + TypeConstructor?: Type, + ): InstanceType; + getArray(name?: string | undefined): Type.YArray; + getText(name?: string | undefined): Type.YText; + getMap(name?: string | undefined): Type.YMap; + getXmlElement(name?: string | undefined): Type.YXml.YXmlElement; + getXmlFragment(name?: string | undefined): Type.YXml.YXmlFragment; + /** + * Converts the entire document into a js object, recursively traversing each yjs type + * Doesn't log types that have not been defined (using ydoc.getType(..)). + * + * @deprecated Do not use this method and rather call toJSON directly on the shared types. + */ + toJSON(): { + [x: string]: any; + }; + } + type DocOpts = { + /** + * Disable garbage collection (default: gc=true) + */ + gc?: boolean | undefined; + /** + * Will be called before an Item is garbage collected. Return false to keep the Item. + */ + gcFilter?: ((arg0: Struct.Item) => boolean) | undefined; + /** + * Define a globally unique identifier for this document + */ + guid?: string | undefined; + /** + * Associate this document with a collection. This only plays a role if your provider has a concept of collection. + */ + collectionid?: string | null | undefined; + /** + * Any kind of meta information you want to associate with this document. If this is a subdocument, remote peers will store the meta information as well. + */ + meta?: any; + /** + * If a subdocument, automatically load document. If this is a subdocument, remote peers will load the document as well automatically. + */ + autoLoad?: boolean | undefined; + /** + * Whether the document should be synced by the provider now. This is toggled to true when you call ydoc.load() + */ + shouldLoad?: boolean | undefined; + }; + type DocEvents = { + destroy: (arg0: Doc) => void; + load: (arg0: Doc) => void; + sync: (arg0: boolean, arg1: Doc) => void; + update: (arg0: Uint8Array, arg1: any, arg2: Doc, arg3: Transaction) => void; + updateV2: ( + arg0: Uint8Array, + arg1: any, + arg2: Doc, + arg3: Transaction, + ) => void; + beforeAllTransactions: (arg0: Doc) => void; + beforeTransaction: (arg0: Transaction, arg1: Doc) => void; + beforeObserverCalls: (arg0: Transaction, arg1: Doc) => void; + afterTransaction: (arg0: Transaction, arg1: Doc) => void; + afterTransactionCleanup: (arg0: Transaction, arg1: Doc) => void; + afterAllTransactions: (arg0: Doc, arg1: Array) => void; + subdocs: ( + arg0: { + loaded: Set; + added: Set; + removed: Set; + }, + arg1: Doc, + arg2: Transaction, + ) => void; + }; + + /** + * A transaction is created for every change on the Yjs model. It is possible + * to bundle changes on the Yjs model in a single transaction to + * minimize the number on messages sent and the number of observer calls. + * If possible the user of this library should bundle as many changes as + * possible. Here is an example to illustrate the advantages of bundling: + * + * @example + * const ydoc = new Y.Doc() + * const map = ydoc.getMap('map') + * // Log content when change is triggered + * map.observe(() => { + * console.log('change triggered') + * }) + * // Each change on the map type triggers a log message: + * map.set('a', 0) // => "change triggered" + * map.set('b', 0) // => "change triggered" + * // When put in a transaction, it will trigger the log after the transaction: + * ydoc.transact(() => { + * map.set('a', 1) + * map.set('b', 1) + * }) // => "change triggered" + */ + export class Transaction { + constructor(doc: Doc, origin: any, local: boolean); + /** + * The Yjs instance. + */ + doc: Doc; + /** + * Describes the set of deleted items by ids + */ + deleteSet: Struct.DeleteSet; + /** + * Holds the state before the transaction started. + */ + beforeState: Map; + /** + * Holds the state after the transaction. + */ + afterState: Map; + /** + * All types that were directly modified (property added or child + * inserted/deleted). New types are not included in this Set. + * Maps from type to parentSubs (`item.parentSub = null` for YArray) + */ + changed: Map>, Set>; + /** + * Stores the events for the types that observe also child elements. + * It is mainly used by `observeDeep`. + */ + changedParentTypes: Map< + Type.AbstractType>, + Array> + >; + origin: any; + /** + * Stores meta information on the transaction + */ + meta: Map; + /** + * Whether this change originates from this doc. + */ + local: boolean; + subdocsAdded: Set; + subdocsRemoved: Set; + subdocsLoaded: Set; + } + + export function tryGc( + ds: Struct.DeleteSet, + store: Struct.StructStore, + gcFilter: (arg0: Struct.Item) => boolean, + ): void; + export function transact( + doc: Doc, + f: (arg0: Transaction) => T, + origin?: any, + local?: boolean, + ): T; + + module Struct { + class DeleteItem { + constructor(clock: number, len: number); + clock: number; + len: number; + } + /** + * We no longer maintain a DeleteStore. DeleteSet is a temporary object that is created when needed. + * - When created in a transaction, it must only be accessed after sorting, and merging + * - This DeleteSet is send to other clients + * - We do not create a DeleteSet when we send a sync message. The DeleteSet message is created directly from StructStore + * - We read a DeleteSet as part of a sync/update message. In this case the DeleteSet is already sorted and merged. + */ + class DeleteSet { + clients: Map>; + } + export function iterateDeletedStructs( + transaction: Transaction, + ds: DeleteSet, + f: (arg0: Struct.GC | Struct.Item) => void, + ): void; + export function isDeleted(ds: DeleteSet, id: Struct.ID): boolean; + export function mergeDeleteSets(dss: Array): DeleteSet; + export function createDeleteSet(): DeleteSet; + export function createDeleteSetFromStructStore( + ss: Struct.StructStore, + ): DeleteSet; + export function equalDeleteSets(ds1: DeleteSet, ds2: DeleteSet): boolean; + + export class ID { + /** + * @param {number} client client id + * @param {number} clock unique per client id, continuous number + */ + constructor(client: number, clock: number); + /** + * Client id + */ + client: number; + /** + * unique per client id, continuous number + */ + clock: number; + } + export function compareIDs(a: ID | null, b: ID | null): boolean; + export function createID(client: number, clock: number): ID; + export function findRootTypeKey(type: Type.AbstractType): string; + + export function isParentOf( + parent: Type.AbstractType, + child: Struct.Item | null, + ): boolean; + + export function logType(type: Type.AbstractType): void; + + export class StructStore { + clients: Map>; + pendingStructs: { + missing: Map; + update: Uint8Array; + } | null; + pendingDs: null | Uint8Array; + } + export function getState(store: StructStore, client: number): number; + export function findIndexSS( + structs: Array, + clock: number, + ): number; + export function getItem(arg0: StructStore, arg1: ID): Struct.Item; + + export class AbstractStruct { + constructor(id: Struct.ID, length: number); + id: Struct.ID; + length: number; + get deleted(): boolean; + /** + * Merge this struct with the item to the right. + * This method is already assuming that `this.id.clock + this.length === this.id.clock`. + * Also this method does *not* remove right from StructStore! + * @return {boolean} wether this merged with right + */ + mergeWith(right: AbstractStruct): boolean; + write( + encoder: Codec.UpdateEncoderV1 | Codec.UpdateEncoderV2, + offset: number, + encodingRef: number, + ): void; + integrate(transaction: Transaction, offset: number): void; + } + + export class GC extends AbstractStruct { + delete(): void; + mergeWith(right: GC): boolean; + write( + encoder: Codec.UpdateEncoderV1 | Codec.UpdateEncoderV2, + offset: number, + ): void; + getMissing( + transaction: Transaction, + store: Struct.StructStore, + ): null | number; + } + + /** + * Abstract class that represents any content. + */ + export class Item extends AbstractStruct { + /** + * @param {AbstractType|ID|null} parent Is a type if integrated, is null if it is possible to copy parent from left or right, is ID before integration to search for it. + */ + constructor( + id: Struct.ID, + left: Item | null, + origin: Struct.ID | null, + right: Item | null, + rightOrigin: Struct.ID | null, + parent: Type.AbstractType | Struct.ID | null, + parentSub: string | null, + content: AbstractContent, + ); + /** + * The item that was originally to the left of this item. + */ + origin: Struct.ID | null; + /** + * The item that is currently to the left of this item. + */ + left: Item | null; + /** + * The item that is currently to the right of this item. + */ + right: Item | null; + /** + * The item that was originally to the right of this item. + */ + rightOrigin: Struct.ID | null; + parent: Type.AbstractType | Struct.ID | null; + /** + * If the parent refers to this item with some kind of key (e.g. YMap, the + * key is specified here. The key is then used to refer to the list in which + * to insert this item. If `parentSub = null` type._start is the list in + * which to insert to. Otherwise it is `parent._map`. + */ + parentSub: string | null; + /** + * If this type's effect is redone this type refers to the type that undid + * this operation. + */ + redone: Struct.ID | null; + content: AbstractContent; + /** + * bit1: keep + * bit2: countable + * bit3: deleted + * bit4: mark - mark node as fast-search-marker + */ + info: number; + /** + * This is used to mark the item as an indexed fast-search marker + */ + set marker(arg: boolean); + get marker(): boolean; + set keep(arg: boolean); + /** + * If true, do not garbage collect this Item. + */ + get keep(): boolean; + get countable(): boolean; + set deleted(arg: boolean); + /** + * Whether this item was deleted or not. + */ + get deleted(): boolean; + markDeleted(): void; + /** + * Return the creator clientID of the missing op or define missing items and return null. + */ + getMissing( + transaction: Transaction, + store: Struct.StructStore, + ): null | number; + /** + * Returns the next non-deleted item + */ + get next(): Item | null; + /** + * Returns the previous non-deleted item + */ + get prev(): Item | null; + /** + * Computes the last content address of this Item. + */ + get lastId(): Struct.ID; + /** + * Try to merge two items + */ + mergeWith(right: Item): boolean; + /** + * Mark this Item as deleted. + */ + delete(transaction: Transaction): void; + gc(store: Struct.StructStore, parentGCd: boolean): void; + /** + * Transform the properties of this type to binary and write it to an + * BinaryEncoder. + * + * This is called when this Item is sent to a remote peer. + */ + write( + encoder: Codec.UpdateEncoderV1 | Codec.UpdateEncoderV2, + offset: number, + ): void; + } + + export class AbstractContent { + getLength(): number; + getContent(): Array; + /** + * Should return false if this Item is some kind of meta information + * (e.g. format information). + * + * * Whether this Item should be addressable via `yarray.get(i)` + * * Whether this Item should be counted when computing yarray.length + */ + isCountable(): boolean; + copy(): AbstractContent; + splice(_offset: number): AbstractContent; + mergeWith(_right: AbstractContent): boolean; + integrate(_transaction: Transaction, _item: Item): void; + delete(_transaction: Transaction): void; + gc(_store: Struct.StructStore): void; + write( + _encoder: Codec.UpdateEncoderV1 | Codec.UpdateEncoderV2, + _offset: number, + ): void; + getRef(): number; + } + + export class Skip extends AbstractStruct { + delete(): void; + mergeWith(right: Skip): boolean; + write( + encoder: Codec.UpdateEncoderV1 | Codec.UpdateEncoderV2, + offset: number, + ): void; + getMissing( + transaction: Transaction, + store: Struct.StructStore, + ): null | number; + } + } + + module Type { + module Event { + /** + * YEvent describes the changes on a YType. + */ + export class YEvent> { + /** + * @param {T} target The changed type. + * @param {Transaction} transaction + */ + constructor(target: T, transaction: Transaction); + /** + * The type on which this event was created on. + */ + target: T; + /** + * The current target on which the observe callback is called. + */ + currentTarget: AbstractType; + /** + * The transaction that triggered this event. + */ + transaction: Transaction; + /** + * Computes the path from `y` to the changed type. + * + * @todo v14 should standardize on path: Array<{parent, index}> because that is easier to work with. + * + * The following property holds: + * @example + * let type = y + * event.path.forEach(dir => { + * type = type.get(dir) + * }) + * type === event.target // => true + */ + get path(): (string | number)[]; + /** + * Check if a struct is deleted by this event. + * + * In contrast to change.deleted, this method also returns true if the struct was added and then deleted. + */ + deletes(struct: Struct.AbstractStruct): boolean; + get keys(): Map< + string, + { + action: "add" | "update" | "delete"; + oldValue: any; + newValue: any; + } + >; + /** + * This is a computed property. Note that this can only be safely computed during the + * event call. Computing this property after other changes happened might result in + * unexpected behavior (incorrect computation of deltas). A safe way to collect changes + * is to store the `changes` or the `delta` object. Avoid storing the `transaction` object. + */ + get delta(): { + insert?: string | object | any[] | AbstractType | undefined; + retain?: number | undefined; + delete?: number | undefined; + attributes?: + | { + [x: string]: any; + } + | undefined; + }[]; + /** + * Check if a struct is added by this event. + * + * In contrast to change.deleted, this method also returns true if the struct was added and then deleted. + */ + adds(struct: Struct.AbstractStruct): boolean; + /** + * This is a computed property. Note that this can only be safely computed during the + * event call. Computing this property after other changes happened might result in + * unexpected behavior (incorrect computation of deltas). A safe way to collect changes + * is to store the `changes` or the `delta` object. Avoid storing the `transaction` object. + */ + get changes(): { + added: Set; + deleted: Set; + keys: Map< + string, + { + action: "add" | "update" | "delete"; + oldValue: any; + } + >; + delta: Array<{ + insert?: Array | string; + delete?: number; + retain?: number; + }>; + }; + } + + /** + * Event that describes the changes on a YArray + */ + export class YArrayEvent extends YEvent> { + constructor(target: YArray, transaction: Transaction); + } + + /** + * Event that describes the changes on a YMap. + */ + export class YMapEvent extends YEvent> { + /** + * @param {YMap} ymap The YArray that changed. + * @param {Transaction} transaction + * @param {Set} subs The keys that changed. + */ + constructor(ymap: YMap, transaction: Transaction, subs: Set); + keysChanged: Set; + } + + /** + * Event that describes the changes on a YText type. + */ + export class YTextEvent extends YEvent { + /** + * @param {YText} ytext + * @param {Transaction} transaction + * @param {Set} subs The keys that changed + */ + constructor(ytext: YText, transaction: Transaction, subs: Set); + /** + * Set of all changed attributes. + */ + keysChanged: Set; + /** + * Compute the changes in the delta format. + * A {@link https://quilljs.com/docs/delta/|Quill Delta}) that represents the changes on the document. + */ + get delta(): { + insert?: string | object | AbstractType | undefined; + delete?: number | undefined; + retain?: number | undefined; + attributes?: + | { + [x: string]: any; + } + | undefined; + }[]; + } + } + + export function getTypeChildren(t: AbstractType): Array; + + /** + * Abstract Yjs Type class + */ + export class AbstractType { + doc: Doc | null; + get parent(): AbstractType | null; + + /** + * Makes a copy of this data type that can be included somewhere else. + * + * Note that the content is only readable _after_ it has been included somewhere in the Ydoc. + */ + clone(): AbstractType; + /** + * Observe all events that are created on this type. + */ + observe(f: (arg0: EventType, arg1: Transaction) => void): void; + /** + * Observe all events that are created by this type and its children. + */ + observeDeep( + f: (arg0: Array>, arg1: Transaction) => void, + ): void; + /** + * Unregister an observer function. + */ + unobserve(f: (arg0: EventType, arg1: Transaction) => void): void; + /** + * Unregister an observer function. + */ + unobserveDeep( + f: (arg0: Array>, arg1: Transaction) => void, + ): void; + toJSON(): any; + } + + /** + * A shared Array implementation. + */ + export class YArray + extends AbstractType> + implements Iterable + { + /** + * Construct a new YArray containing the specified items. + * @template {Object|Array|number|null|string|Uint8Array} T + * @param {Array} items + * @return {YArray} + */ + static from< + T extends + | string + | number + | any[] + | Uint8Array + | { + [x: string]: any; + } + | null, + >(items: T[]): YArray; + /** + * Makes a copy of this data type that can be included somewhere else. + * + * Note that the content is only readable _after_ it has been included somewhere in the Ydoc. + * + * @return {YArray} + */ + clone(): YArray; + get length(): number; + /** + * Inserts new content at an index. + * + * Important: This function expects an array of content. Not just a content + * object. The reason for this "weirdness" is that inserting several elements + * is very efficient when it is done as a single operation. + * + * @example + * // Insert character 'a' at position 0 + * yarray.insert(0, ['a']) + * // Insert numbers 1, 2 at position 1 + * yarray.insert(1, [1, 2]) + * + * @param {number} index The index to insert content at. + * @param {Array} content The array of content + */ + insert(index: number, content: Array): void; + /** + * Appends content to this YArray. + * + * @param {Array} content Array of content to append. + * + * @todo Use the following implementation in all types. + */ + push(content: Array): void; + /** + * Prepends content to this YArray. + * + * @param {Array} content Array of content to prepend. + */ + unshift(content: Array): void; + /** + * Deletes elements starting from an index. + * + * @param {number} index Index at which to start deleting elements + * @param {number} length The number of elements to remove. Defaults to 1. + */ + delete(index: number, length?: number): void; + /** + * Returns the i-th element from a YArray. + * + * @param {number} index The index of the element to return from the YArray + * @return {T} + */ + get(index: number): T; + /** + * Transforms this YArray to a JavaScript Array. + * + * @return {Array} + */ + toArray(): Array; + /** + * Returns a portion of this YArray into a JavaScript Array selected + * from start to end (end not included). + * + * @param {number} [start] + * @param {number} [end] + * @return {Array} + */ + slice(start?: number | undefined, end?: number | undefined): Array; + /** + * Transforms this Shared Type to a JSON object. + * + * @return {Array} + */ + toJSON(): Array; + /** + * Returns an Array with the result of calling a provided function on every + * element of this YArray. + * + * @template M + * @param {function(T,number,YArray):M} f Function that produces an element of the new Array + * @return {Array} A new array with each element being the result of the + * callback function + */ + map(f: (arg0: T, arg1: number, arg2: YArray) => M): M[]; + /** + * Executes a provided function once on every element of this YArray. + * + * @param {function(T,number,YArray):void} f A function to execute on every element of this YArray. + */ + forEach(f: (arg0: T, arg1: number, arg2: YArray) => void): void; + /** + * @return {IterableIterator} + */ + [Symbol.iterator](): IterableIterator; + } + + /** + * A shared Map implementation. + */ + export class YMap + extends AbstractType> + implements Iterable<[string, MapType]> + { + /** + * + * @param {Iterable=} entries - an optional iterable to initialize the YMap + */ + constructor(entries?: Iterable | undefined); + /** + * Makes a copy of this data type that can be included somewhere else. + * + * Note that the content is only readable _after_ it has been included somewhere in the Ydoc. + */ + clone(): YMap; + /** + * Transforms this Shared Type to a JSON object. + */ + toJSON(): { + [x: string]: any; + }; + /** + * Returns the size of the YMap (count of key/value pairs) + */ + get size(): number; + /** + * Returns the keys for each element in the YMap Type. + */ + keys(): IterableIterator; + /** + * Returns the values for each element in the YMap Type. + */ + values(): IterableIterator; + /** + * Returns an Iterator of [key, value] pairs + */ + entries(): IterableIterator<[string, MapType]>; + /** + * Executes a provided function on once on every key-value pair. + * + * @param {function(MapType,string,YMap):void} f A function to execute on every element of this YArray. + */ + forEach( + f: (arg0: MapType, arg1: string, arg2: YMap) => void, + ): void; + /** + * Remove a specified element from this YMap. + * + * @param {string} key The key of the element to remove. + */ + delete(key: string): void; + /** + * Adds or updates an element with a specified key and value. + * @template {MapType} VAL + * + * @param {string} key The key of the element to add to this YMap + * @param {VAL} value The value of the element to add + * @return {VAL} + */ + set(key: string, value: VAL): VAL; + /** + * Returns a specified element from this YMap. + * + * @param {string} key + * @return {MapType|undefined} + */ + get(key: string): MapType | undefined; + /** + * Returns a boolean indicating whether the specified key exists or not. + * + * @param {string} key The key to test. + * @return {boolean} + */ + has(key: string): boolean; + /** + * Removes all elements from this YMap. + */ + clear(): void; + /** + * Returns an Iterator of [key, value] pairs + * + * @return {IterableIterator<[string, MapType]>} + */ + [Symbol.iterator](): IterableIterator<[string, MapType]>; + } + + export function cleanupYTextFormatting(type: YText): number; + + /** + * Type that represents text with formatting information. + * + * This type replaces y-richtext as this implementation is able to handle + * block formats (format information on a paragraph), embeds (complex elements + * like pictures and videos), and text formats (**bold**, *italic*). + */ + export class YText extends AbstractType { + /** + * @param {String} [string] The initial value of the YText. + */ + constructor(string?: string | undefined); + /** + * Number of characters of this text type. + */ + get length(): number; + /** + * Makes a copy of this data type that can be included somewhere else. + * + * Note that the content is only readable _after_ it has been included somewhere in the Ydoc. + */ + clone(): YText; + /** + * Returns the unformatted string representation of this YText type. + */ + toJSON(): string; + /** + * Apply a {@link Delta} on this shared YText type. + * + * @param {any} delta The changes to apply on this element. + * @param {object} opts + * @param {boolean} [opts.sanitize] Sanitize input delta. Removes ending newlines if set to true. + */ + applyDelta(delta: any, opts?: { sanitize?: boolean | undefined }): void; + /** + * Returns the Delta representation of this YText type. + */ + toDelta( + snapshot?: Snapshot.Snapshot | undefined, + prevSnapshot?: Snapshot.Snapshot | undefined, + computeYChange?: + | ((arg0: "removed" | "added", arg1: Struct.ID) => any) + | undefined, + ): any; + /** + * Insert text at a given index. + * + * @param {number} index The index at which to start inserting. + * @param {String} text The text to insert at the specified position. + * @param {TextAttributes} [attributes] Optionally define some formatting + * information to apply on the inserted + * Text. + * @public + */ + insert( + index: number, + text: string, + attributes?: Object | undefined, + ): void; + /** + * Inserts an embed at a index. + * + * @param {number} index The index to insert the embed at. + * @param {Object | AbstractType} embed The Object that represents the embed. + * @param {TextAttributes} [attributes] Attribute information to apply on the + * embed + */ + insertEmbed( + index: number, + embed: Object | AbstractType, + attributes?: Object | undefined, + ): void; + /** + * Deletes text starting from an index. + * + * @param {number} index Index at which to start deleting. + * @param {number} length The number of characters to remove. Defaults to 1. + * + * @public + */ + delete(index: number, length: number): void; + /** + * Assigns properties to a range of text. + * + * @param {number} index The position where to start formatting. + * @param {number} length The amount of characters to assign properties to. + * @param {TextAttributes} attributes Attribute information to apply on the + * text. + */ + format(index: number, length: number, attributes: TextAttributes): void; + /** + * Removes an attribute. + * + * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks. + * + * @param {String} attributeName The attribute name that is to be removed. + */ + removeAttribute(attributeName: string): void; + /** + * Sets or updates an attribute. + * + * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks. + * + * @param {String} attributeName The attribute name that is to be set. + * @param {any} attributeValue The attribute value that is to be set. + */ + setAttribute(attributeName: string, attributeValue: any): void; + /** + * Returns an attribute value that belongs to the attribute name. + * + * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks. + * + * @param {String} attributeName The attribute name that identifies the + * queried value. + * @return {any} The queried attribute value. + */ + getAttribute(attributeName: string): any; + /** + * Returns all attribute name/value pairs in a JSON Object. + * + * @note Xml-Text nodes don't have attributes. You can use this feature to assign properties to complete text-blocks. + * + * @return {Object} A JSON Object that describes the attributes. + */ + getAttributes(): { + [x: string]: any; + }; + } + /** + * Attributes that can be assigned to a selection of text. + */ + export type TextAttributes = Object; + + module YXml { + /** + * Represents a subset of the nodes of a YXmlElement / YXmlFragment and a + * position within them. + * + * Can be created with {@link YXmlFragment#createTreeWalker} + */ + export class YXmlTreeWalker + implements Iterable + { + constructor( + root: YXmlFragment | YXmlElement, + f?: ((arg0: AbstractType) => boolean) | undefined, + ); + /** + * Get the next node. + */ + next(): IteratorResult; + [Symbol.iterator](): YXmlTreeWalker; + } + /** + * Represents a list of {@link YXmlElement}.and {@link YXmlText} types. + * A YxmlFragment is similar to a {@link YXmlElement}, but it does not have a + * nodeName and it does not have attributes. Though it can be bound to a DOM + * element - in this case the attributes and the nodeName are not shared. + */ + export class YXmlFragment extends AbstractType { + constructor(); + get firstChild(): + | YXmlElement<{ + [key: string]: string; + }> + | YXmlText + | null; + /** + * Makes a copy of this data type that can be included somewhere else. + * + * Note that the content is only readable _after_ it has been included somewhere in the Ydoc. + */ + clone(): YXmlFragment; + get length(): number; + /** + * Create a subtree of childNodes. + * + * @example + * const walker = elem.createTreeWalker(dom => dom.nodeName === 'div') + * for (let node in walker) { + * // `node` is a div node + * nop(node) + * } + * + * @param {function(AbstractType):boolean} filter Function that is called on each child element and + * returns a Boolean indicating whether the child + * is to be included in the subtree. + * @return {YXmlTreeWalker} A subtree and a position within it. + */ + createTreeWalker( + filter: (arg0: AbstractType) => boolean, + ): YXmlTreeWalker; + /** + * Returns the first YXmlElement that matches the query. + * Similar to DOM's {@link querySelector}. + * + * Query support: + * - tagname + * TODO: + * - id + * - attribute + * + * @param {CSS_Selector} query The query on the children. + * @return {YXmlElement|YXmlText|YXmlHook|null} The first element that matches the query or null. + */ + querySelector( + query: CSS_Selector, + ): YXmlElement | YXmlText | YXmlHook | null; + /** + * Returns all YXmlElements that match the query. + * Similar to Dom's {@link querySelectorAll}. + * + * @todo Does not yet support all queries. Currently only query by tagName. + * + * @param {CSS_Selector} query The query on the children + * @return {Array} The elements that match this query. + */ + querySelectorAll( + query: CSS_Selector, + ): Array; + toJSON(): string; + /** + * Creates a Dom Element that mirrors this YXmlElement. + * + * @param {Document} [_document=document] The document object (you must define + * this when calling this method in + * nodejs) + * @param {Object} [hooks={}] Optional property to customize how hooks + * are presented in the DOM + * @param {any} [binding] You should not set this property. This is + * used if DomBinding wants to create a + * association to the created DOM type. + * @return {Node} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element} + */ + toDOM( + _document?: Document | undefined, + hooks?: + | { + [x: string]: any; + } + | undefined, + binding?: any, + ): Node; + /** + * Inserts new content at an index. + * + * @example + * // Insert character 'a' at position 0 + * xml.insert(0, [new Y.XmlText('text')]) + * + * @param {number} index The index to insert content at + * @param {Array} content The array of content + */ + insert(index: number, content: Array): void; + /** + * Inserts new content at an index. + * + * @example + * // Insert character 'a' at position 0 + * xml.insert(0, [new Y.XmlText('text')]) + * + * @param {null|Item|YXmlElement|YXmlText} ref The index to insert content at + * @param {Array} content The array of content + */ + insertAfter( + ref: null | Struct.Item | YXmlElement | YXmlText, + content: Array, + ): void; + /** + * Deletes elements starting from an index. + * + * @param {number} index Index at which to start deleting elements + * @param {number} [length=1] The number of elements to remove. Defaults to 1. + */ + delete(index: number, length?: number | undefined): void; + /** + * Transforms this YArray to a JavaScript Array. + * + * @return {Array} + */ + toArray(): Array; + /** + * Appends content to this YArray. + * + * @param {Array} content Array of content to append. + */ + push(content: Array): void; + /** + * Prepends content to this YArray. + * + * @param {Array} content Array of content to prepend. + */ + unshift(content: Array): void; + /** + * Returns the i-th element from a YArray. + * + * @param {number} index The index of the element to return from the YArray + * @return {YXmlElement|YXmlText} + */ + get(index: number): YXmlElement | YXmlText; + /** + * Returns a portion of this YXmlFragment into a JavaScript Array selected + * from start to end (end not included). + * + * @param {number} [start] + * @param {number} [end] + * @return {Array} + */ + slice( + start?: number | undefined, + end?: number | undefined, + ): Array; + /** + * Executes a provided function on once on every child element. + * + * @param {function(YXmlElement|YXmlText,number, typeof self):void} f A function to execute on every element of this YArray. + */ + forEach( + f: ( + arg0: YXmlElement | YXmlText, + arg1: number, + arg2: typeof self, + ) => void, + ): void; + } + + /** + * Define the elements to which a set of CSS queries apply. + * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|CSS_Selectors} + */ + type CSS_Selector = string; + + /** + * An YXmlElement imitates the behavior of a + * https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element + * + * * An YXmlElement has attributes (key value pairs) + * * An YXmlElement has childElements that must inherit from YXmlElement + * + * @template {{ [key: string]: ValueTypes }} [KV={ [key: string]: string }] + */ + export class YXmlElement< + KV extends { + [key: string]: ValueTypes; + } = { + [key: string]: string; + }, + > extends YXmlFragment { + constructor(nodeName?: string); + nodeName: string; + get nextSibling(): + | YXmlElement<{ + [key: string]: string; + }> + | YXmlText + | null; + get prevSibling(): + | YXmlElement<{ + [key: string]: string; + }> + | YXmlText + | null; + /** + * Makes a copy of this data type that can be included somewhere else. + * + * Note that the content is only readable _after_ it has been included somewhere in the Ydoc. + */ + clone(): YXmlElement; + /** + * Removes an attribute from this YXmlElement. + * + * @param {string} attributeName The attribute name that is to be removed. + * + * @public + */ + removeAttribute(attributeName: string): void; + /** + * Sets or updates an attribute. + * + * @template {keyof KV & string} KEY + * + * @param {KEY} attributeName The attribute name that is to be set. + * @param {KV[KEY]} attributeValue The attribute value that is to be set. + */ + setAttribute( + attributeName: KEY, + attributeValue: KV[KEY], + ): void; + /** + * Returns an attribute value that belongs to the attribute name. + * + * @template {keyof KV & string} KEY + * + * @param {KEY} attributeName The attribute name that identifies the + * queried value. + * @return {KV[KEY]|undefined} The queried attribute value. + */ + getAttribute( + attributeName: KEY_1, + ): KV[KEY_1] | undefined; + /** + * Returns whether an attribute exists + * + * @param {string} attributeName The attribute name to check for existence. + * @return {boolean} whether the attribute exists. + */ + hasAttribute(attributeName: string): boolean; + /** + * Returns all attribute name/value pairs in a JSON Object. + * + * @param {Snapshot} [snapshot] + * @return {{ [Key in Extract]?: KV[Key]}} A JSON Object that describes the attributes. + */ + getAttributes(snapshot?: Snapshot.Snapshot | undefined): { + [Key in Extract]?: KV[Key] | undefined; + }; + } + + type ValueTypes = + | Object + | number + | null + | Array + | string + | Uint8Array + | AbstractType; + + /** + * An Event that describes changes on a YXml Element or Yxml Fragment + */ + export class YXmlEvent extends Event.YEvent< + | YXmlElement<{ + [key: string]: string; + }> + | YXmlFragment + | YXmlText + > { + /** + * @param {YXmlElement|YXmlText|YXmlFragment} target The target on which the event is created. + * @param {Set} subs The set of changed attributes. `null` is included if the + * child list changed. + * @param {Transaction} transaction The transaction instance with wich the + * change was created. + */ + constructor( + target: YXmlElement | YXmlText | YXmlFragment, + subs: Set, + transaction: Transaction, + ); + /** + * Set of all changed attributes. + * @type {Set} + */ + attributesChanged: Set; + } + + /** + * You can manage binding to a custom type with YXmlHook. + */ + export class YXmlHook extends YMap { + /** + * @param {string} hookName nodeName of the Dom Node. + */ + constructor(hookName: string); + hookName: string; + /** + * Makes a copy of this data type that can be included somewhere else. + * + * Note that the content is only readable _after_ it has been included somewhere in the Ydoc. + */ + clone(): YXmlHook; + /** + * Creates a Dom Element that mirrors this YXmlElement. + * + * @param {Document} [_document=document] The document object (you must define + * this when calling this method in + * nodejs) + * @param {Object.} [hooks] Optional property to customize how hooks + * are presented in the DOM + * @param {any} [binding] You should not set this property. This is + * used if DomBinding wants to create a + * association to the created DOM type + * @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element} + */ + toDOM( + _document?: Document | undefined, + hooks?: + | { + [x: string]: any; + } + | undefined, + binding?: any, + ): Element; + } + + /** + * Represents text in a Dom Element. In the future this type will also handle + * simple formatting information like bold and italic. + */ + export class YXmlText extends YText { + get nextSibling(): + | YXmlElement<{ + [key: string]: string; + }> + | YXmlText + | null; + get prevSibling(): + | YXmlElement<{ + [key: string]: string; + }> + | YXmlText + | null; + /** + * Makes a copy of this data type that can be included somewhere else. + * + * Note that the content is only readable _after_ it has been included somewhere in the Ydoc. + */ + clone(): YXmlText; + /** + * Creates a Dom Element that mirrors this YXmlText. + * + * @param {Document} [_document=document] The document object (you must define + * this when calling this method in + * nodejs) + * @param {Object} [hooks] Optional property to customize how hooks + * are presented in the DOM + * @param {any} [binding] You should not set this property. This is + * used if DomBinding wants to create a + * association to the created DOM type. + * @return {Text} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element} + */ + toDOM( + _document?: Document | undefined, + hooks?: + | { + [x: string]: any; + } + | undefined, + binding?: any, + ): Text; + toString(): any; + } + } + } + + module Codec { + export class DSDecoderV1 { + constructor(decoder: decoding.Decoder); + restDecoder: decoding.Decoder; + resetDsCurVal(): void; + readDsClock(): number; + readDsLen(): number; + } + export class UpdateDecoderV1 extends DSDecoderV1 { + readLeftID(): Struct.ID; + readRightID(): Struct.ID; + /** + * Read the next client id. + * Use this in favor of readID whenever possible to reduce the number of objects created. + */ + readClient(): number; + readInfo(): number; + readString(): string; + /** + * @return {boolean} isKey + */ + readParentInfo(): boolean; + readTypeRef(): number; + /** + * Write len of a struct - well suited for Opt RLE encoder. + */ + readLen(): number; + readAny(): any; + readBuf(): Uint8Array; + /** + * Legacy implementation uses JSON parse. We use any-decoding in v2. + */ + readJSON(): any; + readKey(): string; + } + export class DSDecoderV2 { + constructor(decoder: decoding.Decoder); + restDecoder: decoding.Decoder; + resetDsCurVal(): void; + readDsClock(): number; + readDsLen(): number; + } + export class UpdateDecoderV2 extends DSDecoderV2 { + /** + * List of cached keys. If the keys[id] does not exist, we read a new key + * from stringEncoder and push it to keys. + */ + keys: Array; + keyClockDecoder: decoding.IntDiffOptRleDecoder; + clientDecoder: decoding.UintOptRleDecoder; + leftClockDecoder: decoding.IntDiffOptRleDecoder; + rightClockDecoder: decoding.IntDiffOptRleDecoder; + infoDecoder: decoding.RleDecoder; + stringDecoder: decoding.StringDecoder; + parentInfoDecoder: decoding.RleDecoder; + typeRefDecoder: decoding.UintOptRleDecoder; + lenDecoder: decoding.UintOptRleDecoder; + readLeftID(): Struct.ID; + readRightID(): Struct.ID; + /** + * Read the next client id. + * Use this in favor of readID whenever possible to reduce the number of objects created. + */ + readClient(): number; + readInfo(): number; + readString(): string; + readParentInfo(): boolean; + readTypeRef(): number; + /** + * Write len of a struct - well suited for Opt RLE encoder. + */ + readLen(): number; + readAny(): any; + readBuf(): Uint8Array; + /** + * This is mainly here for legacy purposes. + * + * Initial we incoded objects using JSON. Now we use the much faster lib0/any-encoder. This method mainly exists for legacy purposes for the v1 encoder. + */ + readJSON(): any; + readKey(): string; + } + export class DSEncoderV1 { + restEncoder: encoding.Encoder; + toUint8Array(): Uint8Array; + resetDsCurVal(): void; + writeDsClock(clock: number): void; + writeDsLen(len: number): void; + } + export class UpdateEncoderV1 extends DSEncoderV1 { + writeLeftID(id: Struct.ID): void; + writeRightID(id: Struct.ID): void; + /** + * Use writeClient and writeClock instead of writeID if possible. + */ + writeClient(client: number): void; + writeInfo(info: number): void; + writeString(s: string): void; + writeParentInfo(isYKey: boolean): void; + writeTypeRef(info: number): void; + /** + * Write len of a struct - well suited for Opt RLE encoder. + */ + writeLen(len: number): void; + writeAny(any: any): void; + writeBuf(buf: Uint8Array): void; + writeJSON(embed: any): void; + writeKey(key: string): void; + } + export class DSEncoderV2 { + restEncoder: encoding.Encoder; + dsCurrVal: number; + toUint8Array(): Uint8Array; + resetDsCurVal(): void; + /** + * @param {number} clock + */ + writeDsClock(clock: number): void; + /** + * @param {number} len + */ + writeDsLen(len: number): void; + } + export class UpdateEncoderV2 extends DSEncoderV2 { + /** + * @type {Map} + */ + keyMap: Map; + /** + * Refers to the next uniqe key-identifier to me used. + * See writeKey method for more information. + * + * @type {number} + */ + keyClock: number; + keyClockEncoder: encoding.IntDiffOptRleEncoder; + clientEncoder: encoding.UintOptRleEncoder; + leftClockEncoder: encoding.IntDiffOptRleEncoder; + rightClockEncoder: encoding.IntDiffOptRleEncoder; + infoEncoder: encoding.RleEncoder; + stringEncoder: encoding.StringEncoder; + parentInfoEncoder: encoding.RleEncoder; + typeRefEncoder: encoding.UintOptRleEncoder; + lenEncoder: encoding.UintOptRleEncoder; + writeLeftID(id: Struct.ID): void; + writeRightID(id: Struct.ID): void; + writeClient(client: number): void; + writeInfo(info: number): void; + writeString(s: string): void; + writeParentInfo(isYKey: boolean): void; + writeTypeRef(info: number): void; + /** + * Write len of a struct - well suited for Opt RLE encoder. + */ + writeLen(len: number): void; + writeAny(any: any): void; + writeBuf(buf: Uint8Array): void; + /** + * This is mainly here for legacy purposes. + * + * Initial we incoded objects using JSON. Now we use the much faster lib0/any-encoder. This method mainly exists for legacy purposes for the v1 encoder. + */ + writeJSON(embed: any): void; + /** + * Property keys are often reused. For example, in y-prosemirror the key `bold` might + * occur very often. For a 3d application, the key `position` might occur very often. + * + * We cache these keys in a Map and refer to them via a unique number. + */ + writeKey(key: string): void; + } + } + + module Update { + export function readUpdateV2( + decoder: decoding.Decoder, + ydoc: Doc, + transactionOrigin?: any, + structDecoder?: Codec.UpdateDecoderV1 | Codec.UpdateDecoderV2 | undefined, + ): void; + export function readUpdate( + decoder: decoding.Decoder, + ydoc: Doc, + transactionOrigin?: any, + ): void; + export function applyUpdateV2( + ydoc: Doc, + update: Uint8Array, + transactionOrigin?: any, + YDecoder?: + | typeof Codec.UpdateDecoderV1 + | typeof Codec.UpdateDecoderV2 + | undefined, + ): void; + export function applyUpdate( + ydoc: Doc, + update: Uint8Array, + transactionOrigin?: any, + ): void; + export function encodeStateAsUpdateV2( + doc: Doc, + encodedTargetStateVector?: Uint8Array | undefined, + encoder?: Codec.UpdateEncoderV2 | Codec.UpdateEncoderV1 | undefined, + ): Uint8Array; + export function encodeStateAsUpdate( + doc: Doc, + encodedTargetStateVector?: Uint8Array | undefined, + ): Uint8Array; + export function decodeStateVector( + decodedState: Uint8Array, + ): Map; + export function encodeStateVectorV2( + doc: Doc | Map, + encoder?: Codec.DSEncoderV1 | Codec.DSEncoderV2 | undefined, + ): Uint8Array; + export function encodeStateVector( + doc: Doc | Map, + ): Uint8Array; + + export function logUpdate(update: Uint8Array): void; + export function logUpdateV2( + update: Uint8Array, + YDecoder?: + | typeof Codec.UpdateDecoderV1 + | typeof Codec.UpdateDecoderV2 + | undefined, + ): void; + export function decodeUpdate(update: Uint8Array): { + structs: (Struct.GC | Struct.Item | Struct.Skip)[]; + ds: Struct.DeleteSet; + }; + export function decodeUpdateV2( + update: Uint8Array, + YDecoder?: + | typeof Codec.UpdateDecoderV1 + | typeof Codec.UpdateDecoderV2 + | undefined, + ): { + structs: (Struct.GC | Struct.Item | Struct.Skip)[]; + ds: Struct.DeleteSet; + }; + + export function mergeUpdates(updates: Array): Uint8Array; + export function encodeStateVectorFromUpdateV2( + update: Uint8Array, + YEncoder?: typeof Codec.DSEncoderV1 | typeof Codec.DSEncoderV2, + YDecoder?: typeof Codec.UpdateDecoderV1 | typeof Codec.UpdateDecoderV2, + ): Uint8Array; + export function encodeStateVectorFromUpdate(update: Uint8Array): Uint8Array; + export function parseUpdateMetaV2( + update: Uint8Array, + YDecoder?: typeof Codec.UpdateDecoderV1 | typeof Codec.UpdateDecoderV2, + ): { + from: Map; + to: Map; + }; + export function parseUpdateMeta(update: Uint8Array): { + from: Map; + to: Map; + }; + export function mergeUpdatesV2( + updates: Array, + YDecoder?: + | typeof Codec.UpdateDecoderV1 + | typeof Codec.UpdateDecoderV2 + | undefined, + YEncoder?: + | typeof Codec.UpdateEncoderV2 + | typeof Codec.UpdateEncoderV1 + | undefined, + ): Uint8Array; + export function diffUpdateV2( + update: Uint8Array, + sv: Uint8Array, + YDecoder?: + | typeof Codec.UpdateDecoderV1 + | typeof Codec.UpdateDecoderV2 + | undefined, + YEncoder?: + | typeof Codec.UpdateEncoderV2 + | typeof Codec.UpdateEncoderV1 + | undefined, + ): Uint8Array; + export function diffUpdate(update: Uint8Array, sv: Uint8Array): Uint8Array; + export function obfuscateUpdate( + update: Uint8Array, + opts?: ObfuscatorOptions | undefined, + ): Uint8Array; + export function obfuscateUpdateV2( + update: Uint8Array, + opts?: ObfuscatorOptions | undefined, + ): Uint8Array; + export function convertUpdateFormatV1ToV2(update: Uint8Array): Uint8Array; + export function convertUpdateFormatV2ToV1(update: Uint8Array): Uint8Array; + type ObfuscatorOptions = { + formatting?: boolean | undefined; + subdocs?: boolean | undefined; + /** + * Whether to obfuscate nodeName / hookName + */ + yxml?: boolean | undefined; + }; + } +} + +declare module RelativePosition { + /** + * A relative position is based on the Yjs model and is not affected by document changes. + * E.g. If you place a relative position before a certain character, it will always point to this character. + * If you place a relative position at the end of a type, it will always point to the end of the type. + * + * A numeric position is often unsuited for user selections, because it does not change when content is inserted + * before or after. + * + * ```Insert(0, 'x')('a|bc') = 'xa|bc'``` Where | is the relative position. + * + * One of the properties must be defined. + * + * @example + * // Current cursor position is at position 10 + * const relativePosition = createRelativePositionFromIndex(yText, 10) + * // modify yText + * yText.insert(0, 'abc') + * yText.delete(3, 10) + * // Compute the cursor position + * const absolutePosition = createAbsolutePositionFromRelativePosition(y, relativePosition) + * absolutePosition.type === yText // => true + * console.log('cursor location is ' + absolutePosition.index) // => cursor location is 3 + * + */ + export class RelativePosition { + constructor( + type: Y.Struct.ID | null, + tname: string | null, + item: Y.Struct.ID | null, + assoc?: number, + ); + type: Y.Struct.ID | null; + tname: string | null; + item: Y.Struct.ID | null; + /** + * A relative position is associated to a specific character. By default + * assoc >= 0, the relative position is associated to the character + * after the meant position. + * I.e. position 1 in 'ab' is associated to character 'b'. + * + * If assoc < 0, then the relative position is associated to the caharacter + * before the meant position. + */ + assoc: number; + } + export function relativePositionToJSON(rpos: RelativePosition): any; + export function createRelativePositionFromJSON(json: any): RelativePosition; + export class AbsolutePosition { + constructor( + type: Y.Type.AbstractType, + index: number, + assoc?: number | undefined, + ); + type: Y.Type.AbstractType; + index: number; + assoc: number; + } + export function createAbsolutePosition( + type: Y.Type.AbstractType, + index: number, + assoc?: number | undefined, + ): AbsolutePosition; + export function createRelativePosition( + type: Y.Type.AbstractType, + item: Y.Struct.ID | null, + assoc?: number | undefined, + ): RelativePosition; + export function createRelativePositionFromTypeIndex( + type: Y.Type.AbstractType, + index: number, + assoc?: number | undefined, + ): RelativePosition; + export function encodeRelativePosition(rpos: RelativePosition): Uint8Array; + export function decodeRelativePosition( + uint8Array: Uint8Array, + ): RelativePosition; + export function createAbsolutePositionFromRelativePosition( + rpos: RelativePosition, + doc: Y.Doc, + followUndoneDeletions?: boolean, + ): AbsolutePosition | null; + export function compareRelativePositions( + a: RelativePosition | null, + b: RelativePosition | null, + ): boolean; +} +declare module Snapshot { + export class Snapshot { + constructor(ds: Y.Struct.DeleteSet, sv: Map); + ds: Y.Struct.DeleteSet; + /** + * State Map + */ + sv: Map; + } + export function equalSnapshots(snap1: Snapshot, snap2: Snapshot): boolean; + export function encodeSnapshotV2( + snapshot: Snapshot, + encoder?: Y.Codec.DSEncoderV1 | Y.Codec.DSEncoderV2 | undefined, + ): Uint8Array; + export function encodeSnapshot(snapshot: Snapshot): Uint8Array; + export function decodeSnapshotV2( + buf: Uint8Array, + decoder?: Y.Codec.DSDecoderV1 | Y.Codec.DSDecoderV2 | undefined, + ): Snapshot; + export function decodeSnapshot(buf: Uint8Array): Snapshot; + export function createSnapshot( + ds: Y.Struct.DeleteSet, + sm: Map, + ): Snapshot; + export const emptySnapshot: Snapshot; + export function snapshot(doc: Y.Doc): Snapshot; + export function createDocFromSnapshot( + originDoc: Y.Doc, + snapshot: Snapshot, + newDoc?: Y.Doc | undefined, + ): Y.Doc; + export function snapshotContainsUpdate( + snapshot: Snapshot, + update: Uint8Array, + ): boolean; + + export function typeListToArraySnapshot( + type: Y.Type.AbstractType, + snapshot: Snapshot, + ): Array; + export function typeMapGetSnapshot( + parent: Y.Type.AbstractType, + key: string, + snapshot: Snapshot, + ): + | { + [x: string]: any; + } + | number + | null + | Array + | string + | Uint8Array + | Y.Type.AbstractType + | undefined; + export function typeMapGetAllSnapshot( + parent: Y.Type.AbstractType, + snapshot: Snapshot, + ): { + [x: string]: + | { + [x: string]: any; + } + | number + | null + | Array + | string + | Uint8Array + | Y.Type.AbstractType + | undefined; + }; +} + +declare module Utils { + export class PermanentUserData { + constructor(doc: Y.Doc, storeType?: Y.Type.YMap | undefined); + yusers: Y.Type.YMap; + doc: Y.Doc; + /** + * Maps from clientid to userDescription + */ + clients: Map; + dss: Map; + setUserMapping( + doc: Y.Doc, + clientid: number, + userDescription: string, + conf?: { + filter?: + | ((arg0: Y.Transaction, arg1: Y.Struct.DeleteSet) => boolean) + | undefined; + }, + ): void; + getUserByClientId(clientid: number): any; + getUserByDeletedId(id: Y.Struct.ID): string | null; + } + + export class StackItem { + constructor(deletions: Y.Struct.DeleteSet, insertions: Y.Struct.DeleteSet); + insertions: Y.Struct.DeleteSet; + deletions: Y.Struct.DeleteSet; + /** + * Use this to save and restore metadata like selection range + */ + meta: Map; + } + /** + * Fires 'stack-item-added' event when a stack item was added to either the undo- or + * the redo-stack. You may store additional stack information via the + * metadata property on `event.stackItem.meta` (it is a `Map` of metadata properties). + * Fires 'stack-item-popped' event when a stack item was popped from either the + * undo- or the redo-stack. You may restore the saved stack information from `event.stackItem.meta`. + */ + export class UndoManager extends ObservableV2<{ + "stack-item-added": (arg0: StackItemEvent, arg1: UndoManager) => void; + "stack-item-popped": (arg0: StackItemEvent, arg1: UndoManager) => void; + "stack-cleared": (arg0: { + undoStackCleared: boolean; + redoStackCleared: boolean; + }) => void; + "stack-item-updated": (arg0: StackItemEvent, arg1: UndoManager) => void; + }> { + /** + * @param {AbstractType|Array>} typeScope Accepts either a single type, or an array of types + * @param {UndoManagerOptions} options + */ + constructor( + typeScope: Y.Type.AbstractType | Array>, + options?: UndoManagerOptions, + ); + /** + * @type {Array>} + */ + scope: Array>; + doc: Y.Doc; + deleteFilter: (arg0: Y.Struct.Item) => boolean; + trackedOrigins: Set; + captureTransaction: (arg0: Y.Transaction) => boolean; + undoStack: Array; + redoStack: Array; + /** + * Whether the client is currently undoing (calling UndoManager.undo) + */ + undoing: boolean; + redoing: boolean; + /** + * The currently popped stack item if UndoManager.undoing or UndoManager.redoing + */ + currStackItem: StackItem | null; + lastChange: number; + ignoreRemoteMapChanges: boolean; + captureTimeout: number; + afterTransactionHandler: (transaction: Y.Transaction) => void; + addToScope( + ytypes: Array> | Y.Type.AbstractType, + ): void; + addTrackedOrigin(origin: any): void; + removeTrackedOrigin(origin: any): void; + clear(clearUndoStack?: boolean, clearRedoStack?: boolean): void; + /** + * UndoManager merges Undo-StackItem if they are created within time-gap + * smaller than `options.captureTimeout`. Call `um.stopCapturing()` so that the next + * StackItem won't be merged. + * + * + * @example + * // without stopCapturing + * ytext.insert(0, 'a') + * ytext.insert(1, 'b') + * um.undo() + * ytext.toString() // => '' (note that 'ab' was removed) + * // with stopCapturing + * ytext.insert(0, 'a') + * um.stopCapturing() + * ytext.insert(0, 'b') + * um.undo() + * ytext.toString() // => 'a' (note that only 'b' was removed) + * + */ + stopCapturing(): void; + /** + * Undo last changes on type. + */ + undo(): StackItem | null; + /** + * Redo last undo operation. + */ + redo(): StackItem | null; + /** + * Are undo steps available? + */ + canUndo(): boolean; + /** + * Are redo steps available? + */ + canRedo(): boolean; + } + type UndoManagerOptions = { + captureTimeout?: number | undefined; + /** + * Do not capture changes of a Transaction if result false. + */ + captureTransaction?: ((arg0: Y.Transaction) => boolean) | undefined; + /** + * Sometimes + * it is necessary to filter what an Undo/Redo operation can delete. If this + * filter returns false, the type/item won't be deleted even it is in the + * undo/redo scope. + */ + deleteFilter?: ((arg0: Y.Struct.Item) => boolean) | undefined; + trackedOrigins?: Set | undefined; + /** + * Experimental. By default, the UndoManager will never overwrite remote changes. Enable this property to enable overwriting remote changes on key-value changes (Y.Map, properties on Y.Xml, etc..). + */ + ignoreRemoteMapChanges?: boolean | undefined; + /** + * The document that this UndoManager operates on. Only needed if typeScope is empty. + */ + doc?: Y.Doc | undefined; + }; + type StackItemEvent = { + stackItem: StackItem; + origin: any; + type: "undo" | "redo"; + changedParentTypes: Map< + Y.Type.AbstractType>, + Array> + >; + }; +} diff --git a/y-octo-node/src/yocto.d.ts b/y-octo-node/src/yocto.d.ts new file mode 100644 index 0000000..d686149 --- /dev/null +++ b/y-octo-node/src/yocto.d.ts @@ -0,0 +1,143 @@ +/* auto-generated by NAPI-RS */ +/* eslint-disable */ +export declare class Awareness { + constructor(clientId?: number | undefined | null) + get clientId(): number + get states(): Record +} +export type YAwareness = Awareness + +export declare class DeleteSet { + +} +export type YDeleteSet = DeleteSet + +export declare class Doc { + constructor(clientId?: number | undefined | null) + get clientId(): number + set clientId(clientId: number) + get guid(): string + get store(): YStore + get keys(): Array + getOrCreateArray(key: string): YArray + getOrCreateText(key: string): YText + getOrCreateMap(key: string): YMap + createArray(): YArray + createText(text?: string | undefined | null): YText + createMap(entries?: Array<[string,any]> | Iterator<[string,any]>): YMap + applyUpdate(update: Buffer): void + diff(sv?: Buffer | undefined | null): Buffer | null + encodeStateAsUpdateV1(state?: Buffer | undefined | null): Buffer + gc(): void + onUpdate(callback: (result: Uint8Array) => void): void + offUpdate(): void + destroy(): void +} +export type YDoc = Doc + +export declare class Id { + +} +export type YId = Id + +export declare class Store { + +} +export type YStore = Store + +export declare class YArray { + get length(): number + get isEmpty(): boolean + get itemId(): YId | null + get(index: number): T + slice(start: number, end?: number | undefined | null): Array + map(value: YArray | YMap | YText | boolean | number | string | Record | null | undefined): Array + insert(index: number, value: YArray | YMap | YText | boolean | number | string | Record | null | undefined): void + push(value: YArray | YMap | YText | boolean | number | string | Record | null | undefined): void + unshift(value: YArray | YMap | YText | boolean | number | string | Record | null | undefined): void + delete(index: number, len?: number | undefined | null): void + iter(): YArrayIterator + toArray(): Array + toJSON(): Array + observe(callback: (...args: any[]) => any): void + observeDeep(callback: (...args: any[]) => any): void +} + +export declare class YArrayIterator { + [Symbol.iterator](): Iterator +} + +export declare class YMap { + get length(): number + get size(): number + get isEmpty(): boolean + get itemId(): YId | null + get(key: string): T + set | null | undefined>(key: string, value: T): T + delete(key: string): void + clear(): void + toJSON(): Record + entries(): YMapEntriesIterator + keys(): YMapKeyIterator + values(): YMapValuesIterator + observe(callback: (...args: any[]) => any): void + observeDeep(callback: (...args: any[]) => any): void +} + +export declare class YMapEntriesIterator { + [Symbol.iterator](): Iterator +} + +export declare class YMapKeyIterator { + [Symbol.iterator](): Iterator +} + +export declare class YMapValuesIterator { + [Symbol.iterator](): Iterator +} + +export declare class YProtocol { + constructor(doc: Doc) + encodeSyncStep(step: number, buffer?: Buffer | undefined | null): Buffer + applySyncStep(buffer: Buffer): Buffer | null +} + +export declare class YSnapshot { + +} + +export declare class YText { + get len(): number + get isEmpty(): boolean + insert(index: number, str: string): void + delete(index: number, len: number): void + get length(): number + applyDelta(delta: any[]): void + toDelta(): any[] + toString(): string + observe(callback: (...args: any[]) => any): void + observeDeep(callback: (...args: any[]) => any): void +} + +export declare export declare function applyUpdate(doc: Doc, update: Buffer): void + +export declare export declare function compareIds(a?: YId | undefined | null, b?: YId | undefined | null): boolean + +export declare export declare function compareStructStores(store: YStore, other: YStore): boolean + +export declare export declare function createDeleteSetFromStructStore(store: YStore): YDeleteSet + +export declare export declare function encodeSnapshot(snapshot: YSnapshot): Buffer + +export declare export declare function encodeStateAsUpdate(doc: Doc, state?: Buffer | undefined | null): Buffer + +export declare export declare function encodeStateVector(doc: Doc): Buffer + +export declare export declare function equalDeleteSets(a: YDeleteSet, b: YDeleteSet): boolean + +export declare export declare function isAbstractType(obj?: any): boolean + +export declare export declare function mergeUpdates(updates: Array): Buffer + +export declare export declare function snapshot(doc: Doc): YSnapshot + diff --git a/y-octo-node/src/yocto.js b/y-octo-node/src/yocto.js new file mode 100644 index 0000000..c912ad2 --- /dev/null +++ b/y-octo-node/src/yocto.js @@ -0,0 +1,393 @@ +// prettier-ignore +/* eslint-disable */ +/* auto-generated by NAPI-RS */ + +const { readFileSync } = require('fs') + +let nativeBinding = null +const loadErrors = [] + +const isMusl = () => { + let musl = false + if (process.platform === 'linux') { + musl = isMuslFromFilesystem() + if (musl === null) { + musl = isMuslFromReport() + } + if (musl === null) { + musl = isMuslFromChildProcess() + } + } + return musl +} + +const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-') + +const isMuslFromFilesystem = () => { + try { + return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl') + } catch { + return null + } +} + +const isMuslFromReport = () => { + const report = typeof process.report.getReport === 'function' ? process.report.getReport() : null + if (!report) { + return null + } + if (report.header && report.header.glibcVersionRuntime) { + return false + } + if (Array.isArray(report.sharedObjects)) { + if (report.sharedObjects.some(isFileMusl)) { + return true + } + } + return false +} + +const isMuslFromChildProcess = () => { + try { + return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl') + } catch (e) { + // If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false + return false + } +} + +function requireNative() { + if (process.platform === 'android') { + if (process.arch === 'arm64') { + try { + return require('./y-octo.android-arm64.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-android-arm64') + } catch (e) { + loadErrors.push(e) + } + + } else if (process.arch === 'arm') { + try { + return require('./y-octo.android-arm-eabi.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-android-arm-eabi') + } catch (e) { + loadErrors.push(e) + } + + } else { + loadErrors.push(new Error(`Unsupported architecture on Android ${process.arch}`)) + } + } else if (process.platform === 'win32') { + if (process.arch === 'x64') { + try { + return require('./y-octo.win32-x64-msvc.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-win32-x64-msvc') + } catch (e) { + loadErrors.push(e) + } + + } else if (process.arch === 'ia32') { + try { + return require('./y-octo.win32-ia32-msvc.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-win32-ia32-msvc') + } catch (e) { + loadErrors.push(e) + } + + } else if (process.arch === 'arm64') { + try { + return require('./y-octo.win32-arm64-msvc.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-win32-arm64-msvc') + } catch (e) { + loadErrors.push(e) + } + + } else { + loadErrors.push(new Error(`Unsupported architecture on Windows: ${process.arch}`)) + } + } else if (process.platform === 'darwin') { + try { + return require('./y-octo.darwin-universal.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-darwin-universal') + } catch (e) { + loadErrors.push(e) + } + + if (process.arch === 'x64') { + try { + return require('./y-octo.darwin-x64.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-darwin-x64') + } catch (e) { + loadErrors.push(e) + } + + } else if (process.arch === 'arm64') { + try { + return require('./y-octo.darwin-arm64.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-darwin-arm64') + } catch (e) { + loadErrors.push(e) + } + + } else { + loadErrors.push(new Error(`Unsupported architecture on macOS: ${process.arch}`)) + } + } else if (process.platform === 'freebsd') { + if (process.arch === 'x64') { + try { + return require('./y-octo.freebsd-x64.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-freebsd-x64') + } catch (e) { + loadErrors.push(e) + } + + } else if (process.arch === 'arm64') { + try { + return require('./y-octo.freebsd-arm64.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-freebsd-arm64') + } catch (e) { + loadErrors.push(e) + } + + } else { + loadErrors.push(new Error(`Unsupported architecture on FreeBSD: ${process.arch}`)) + } + } else if (process.platform === 'linux') { + if (process.arch === 'x64') { + if (isMusl()) { + try { + return require('./y-octo.linux-x64-musl.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-linux-x64-musl') + } catch (e) { + loadErrors.push(e) + } + + } else { + try { + return require('./y-octo.linux-x64-gnu.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-linux-x64-gnu') + } catch (e) { + loadErrors.push(e) + } + + } + } else if (process.arch === 'arm64') { + if (isMusl()) { + try { + return require('./y-octo.linux-arm64-musl.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-linux-arm64-musl') + } catch (e) { + loadErrors.push(e) + } + + } else { + try { + return require('./y-octo.linux-arm64-gnu.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-linux-arm64-gnu') + } catch (e) { + loadErrors.push(e) + } + + } + } else if (process.arch === 'arm') { + if (isMusl()) { + try { + return require('./y-octo.linux-arm-musleabihf.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-linux-arm-musleabihf') + } catch (e) { + loadErrors.push(e) + } + + } else { + try { + return require('./y-octo.linux-arm-gnueabihf.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-linux-arm-gnueabihf') + } catch (e) { + loadErrors.push(e) + } + + } + } else if (process.arch === 'riscv64') { + if (isMusl()) { + try { + return require('./y-octo.linux-riscv64-musl.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-linux-riscv64-musl') + } catch (e) { + loadErrors.push(e) + } + + } else { + try { + return require('./y-octo.linux-riscv64-gnu.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-linux-riscv64-gnu') + } catch (e) { + loadErrors.push(e) + } + + } + } else if (process.arch === 'ppc64') { + try { + return require('./y-octo.linux-ppc64-gnu.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-linux-ppc64-gnu') + } catch (e) { + loadErrors.push(e) + } + + } else if (process.arch === 's390x') { + try { + return require('./y-octo.linux-s390x-gnu.node') + } catch (e) { + loadErrors.push(e) + } + try { + return require('@y-octo/node-linux-s390x-gnu') + } catch (e) { + loadErrors.push(e) + } + + } else { + loadErrors.push(new Error(`Unsupported architecture on Linux: ${process.arch}`)) + } + } else { + loadErrors.push(new Error(`Unsupported OS: ${process.platform}, architecture: ${process.arch}`)) + } +} + +nativeBinding = requireNative() + +if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { + try { + nativeBinding = require('./y-octo.wasi.cjs') + } catch (err) { + if (process.env.NAPI_RS_FORCE_WASI) { + loadErrors.push(err) + } + } + if (!nativeBinding) { + try { + nativeBinding = require('@y-octo/node-wasm32-wasi') + } catch (err) { + if (process.env.NAPI_RS_FORCE_WASI) { + loadErrors.push(err) + } + } + } +} + +if (!nativeBinding) { + if (loadErrors.length > 0) { + // TODO Link to documentation with potential fixes + // - The package owner could build/publish bindings for this arch + // - The user may need to bundle the correct files + // - The user may need to re-install node_modules to get new packages + throw new Error('Failed to load native binding', { cause: loadErrors }) + } + throw new Error(`Failed to load native binding`) +} + +module.exports.Awareness = nativeBinding.Awareness +module.exports.YAwareness = nativeBinding.YAwareness +module.exports.DeleteSet = nativeBinding.DeleteSet +module.exports.YDeleteSet = nativeBinding.YDeleteSet +module.exports.Doc = nativeBinding.Doc +module.exports.YDoc = nativeBinding.YDoc +module.exports.Id = nativeBinding.Id +module.exports.YId = nativeBinding.YId +module.exports.Store = nativeBinding.Store +module.exports.YStore = nativeBinding.YStore +module.exports.YArray = nativeBinding.YArray +module.exports.YArrayIterator = nativeBinding.YArrayIterator +module.exports.YMap = nativeBinding.YMap +module.exports.YMapEntriesIterator = nativeBinding.YMapEntriesIterator +module.exports.YMapKeyIterator = nativeBinding.YMapKeyIterator +module.exports.YMapValuesIterator = nativeBinding.YMapValuesIterator +module.exports.YProtocol = nativeBinding.YProtocol +module.exports.YSnapshot = nativeBinding.YSnapshot +module.exports.YText = nativeBinding.YText +module.exports.applyUpdate = nativeBinding.applyUpdate +module.exports.compareIds = nativeBinding.compareIds +module.exports.compareStructStores = nativeBinding.compareStructStores +module.exports.createDeleteSetFromStructStore = nativeBinding.createDeleteSetFromStructStore +module.exports.encodeSnapshot = nativeBinding.encodeSnapshot +module.exports.encodeStateAsUpdate = nativeBinding.encodeStateAsUpdate +module.exports.encodeStateVector = nativeBinding.encodeStateVector +module.exports.equalDeleteSets = nativeBinding.equalDeleteSets +module.exports.isAbstractType = nativeBinding.isAbstractType +module.exports.mergeUpdates = nativeBinding.mergeUpdates +module.exports.snapshot = nativeBinding.snapshot diff --git a/y-octo-node/tests/array.spec.mts b/y-octo-node/tests/array.spec.mts deleted file mode 100644 index 7475e81..0000000 --- a/y-octo-node/tests/array.spec.mts +++ /dev/null @@ -1,62 +0,0 @@ -import assert, { equal, deepEqual } from "node:assert"; -import { test } from "node:test"; - -import { Doc, YArray } from "../index"; - -test("array test", { concurrency: false }, async (t) => { - let client_id: number; - let doc: Doc; - t.beforeEach(async () => { - client_id = (Math.random() * 100000) | 0; - doc = new Doc(client_id); - }); - - t.afterEach(async () => { - client_id = -1; - // @ts-ignore - doc must not null in next range - doc = null; - }); - - await t.test("array should be created", () => { - let arr = doc.getOrCreateArray("arr"); - deepEqual(doc.keys, ["arr"]); - equal(arr.length, 0); - }); - - await t.test("array editing", () => { - let arr = doc.getOrCreateArray("arr"); - arr.insert(0, true); - arr.insert(1, false); - arr.insert(2, 1); - arr.insert(3, "hello world"); - equal(arr.length, 4); - equal(arr.get(0), true); - equal(arr.get(1), false); - equal(arr.get(2), 1); - equal(arr.get(3), "hello world"); - equal(arr.length, 4); - arr.remove(1, 1); - equal(arr.length, 3); - equal(arr.get(2), "hello world"); - }); - - await t.test("sub array should can edit", () => { - let map = doc.getOrCreateMap("map"); - let sub = doc.createArray(); - map.set("sub", sub); - - sub.insert(0, true); - sub.insert(1, false); - sub.insert(2, 1); - sub.insert(3, "hello world"); - equal(sub.length, 4); - - let sub2 = map.get("sub"); - assert(sub2); - equal(sub2.get(0), true); - equal(sub2.get(1), false); - equal(sub2.get(2), 1); - equal(sub2.get(3), "hello world"); - equal(sub2.length, 4); - }); -}); diff --git a/y-octo-node/tests/array.spec.ts b/y-octo-node/tests/array.spec.ts new file mode 100644 index 0000000..79ab9ac --- /dev/null +++ b/y-octo-node/tests/array.spec.ts @@ -0,0 +1,95 @@ +import test from "ava"; + +import * as YOcto from "@y-octo/node"; + +let client_id: number; +let doc: YOcto.Doc; +test.beforeEach(async () => { + client_id = (Math.random() * 100000) | 0; + doc = new YOcto.Doc(client_id); +}); + +test.afterEach(async () => { + client_id = -1; + // @ts-ignore - doc must not null in next range + doc = null; +}); + +test("array should be created", (t) => { + let arr = doc.getOrCreateArray("arr"); + t.deepEqual(doc.keys, ["arr"]); + t.is(arr.length, 0); +}); + +test("array editing", (t) => { + let arr = doc.getOrCreateArray("arr"); + arr.insert(0, true); + arr.insert(1, false); + arr.insert(2, 1); + arr.insert(3, "hello world"); + t.is(arr.length, 4); + t.is(arr.get(0), true); + t.is(arr.get(1), false); + t.is(arr.get(2), 1); + t.is(arr.get(3), "hello world"); + t.is(arr.length, 4); + arr.delete(1, 1); + t.is(arr.length, 3); + t.is(arr.get(2), "hello world"); + t.deepEqual(arr.slice(1, 3), [1, "hello world"]); + t.deepEqual( + arr.map((v) => v), + [true, 1, "hello world"], + ); +}); + +test("sub array should can edit", (t) => { + let map = doc.getOrCreateMap("map"); + let sub = doc.createArray(); + map.set("sub", sub); + + sub.insert(0, true); + sub.insert(1, false); + sub.insert(2, 1); + sub.insert(3, "hello world"); + t.is(sub.length, 4); + + let sub2 = map.get("sub"); + t.assert(sub2); + t.is(sub2.get(0), true); + t.is(sub2.get(1), false); + t.is(sub2.get(2), 1); + t.is(sub2.get(3), "hello world"); + t.is(sub2.length, 4); + t.deepEqual(sub2.slice(1, 3), [false, 1]); + t.deepEqual( + sub2.map((v) => v), + [true, false, 1, "hello world"], + ); +}); + +test("array should support iterator", (t) => { + let arr = doc.getOrCreateArray("arr"); + arr.insert(0, true); + arr.insert(1, false); + arr.insert(2, 1); + arr.insert(3, "hello world"); + let i = 0; + for (let v of arr.iter()) { + switch (i) { + case 0: + t.is(v, true); + break; + case 1: + t.is(v, false); + break; + case 2: + t.is(v, 1); + break; + case 3: + t.is(v, "hello world"); + break; + } + i++; + } +}); diff --git a/y-octo-node/tests/doc.spec.mts b/y-octo-node/tests/doc.spec.mts deleted file mode 100644 index d854746..0000000 --- a/y-octo-node/tests/doc.spec.mts +++ /dev/null @@ -1,99 +0,0 @@ -import assert, { equal } from "node:assert"; -import { test } from "node:test"; - -import { Doc } from "../index"; -import * as Y from "yjs"; - -test("doc test", { concurrency: false }, async (t) => { - let client_id: number; - let doc: Doc; - t.beforeEach(async () => { - client_id = (Math.random() * 100000) | 0; - doc = new Doc(client_id); - }); - - t.afterEach(async () => { - client_id = -1; - // @ts-ignore - doc must not null in next range - doc = null; - }); - - await t.test("doc id should be set", () => { - equal(doc.clientId, client_id); - }); - - await t.test("y-octo doc update should be apply", () => { - let array = doc.getOrCreateArray("array"); - let map = doc.getOrCreateMap("map"); - let text = doc.getOrCreateText("text"); - - array.insert(0, true); - array.insert(1, false); - array.insert(2, 1); - array.insert(3, "hello world"); - map.set("a", true); - map.set("b", false); - map.set("c", 1); - map.set("d", "hello world"); - text.insert(0, "a"); - text.insert(1, "b"); - text.insert(2, "c"); - - let doc2 = new Doc(client_id); - doc2.applyUpdate(doc.encodeStateAsUpdateV1()); - - let array2 = doc2.getOrCreateArray("array"); - let map2 = doc2.getOrCreateMap("map"); - let text2 = doc2.getOrCreateText("text"); - - equal(doc2.clientId, client_id); - equal(array2.length, 4); - equal(array2.get(0), true); - equal(array2.get(1), false); - equal(array2.get(2), 1); - equal(array2.get(3), "hello world"); - equal(map2.length, 4); - equal(map2.get("a"), true); - equal(map2.get("b"), false); - equal(map2.get("c"), 1); - equal(map2.get("d"), "hello world"); - equal(text2.toString(), "abc"); - }); - - await t.test("yjs doc update should be apply", () => { - let doc2 = new Y.Doc(); - let array2 = doc2.getArray("array"); - let map2 = doc2.getMap("map"); - let text2 = doc2.getText("text"); - - array2.insert(0, [true]); - array2.insert(1, [false]); - array2.insert(2, [1]); - array2.insert(3, ["hello world"]); - map2.set("a", true); - map2.set("b", false); - map2.set("c", 1); - map2.set("d", "hello world"); - text2.insert(0, "a"); - text2.insert(1, "b"); - text2.insert(2, "c"); - - doc.applyUpdate(Buffer.from(Y.encodeStateAsUpdate(doc2))); - - let array = doc.getOrCreateArray("array"); - let map = doc.getOrCreateMap("map"); - let text = doc.getOrCreateText("text"); - - equal(array.length, 4); - equal(array.get(0), true); - equal(array.get(1), false); - equal(array.get(2), 1); - equal(array.get(3), "hello world"); - equal(map.length, 4); - equal(map.get("a"), true); - equal(map.get("b"), false); - equal(map.get("c"), 1); - equal(map.get("d"), "hello world"); - equal(text.toString(), "abc"); - }); -}); diff --git a/y-octo-node/tests/doc.spec.ts b/y-octo-node/tests/doc.spec.ts new file mode 100644 index 0000000..83e657c --- /dev/null +++ b/y-octo-node/tests/doc.spec.ts @@ -0,0 +1,98 @@ +import test from "ava"; + +import * as YOcto from "@y-octo/node"; +import * as Y from "yjs"; + +let client_id: number; +let doc: YOcto.Doc; +test.beforeEach(async () => { + client_id = (Math.random() * 100000) | 0; + doc = new YOcto.Doc(client_id); +}); + +test.afterEach(async () => { + client_id = -1; + // @ts-ignore - doc must not null in next range + doc = null; +}); + +test("doc id should be set", (t) => { + t.is(doc.clientId, client_id); +}); + +test("y-octo doc update should be apply", (t) => { + let array = doc.getOrCreateArray("array"); + let map = doc.getOrCreateMap("map"); + let text = doc.getOrCreateText("text"); + + array.insert(0, true); + array.insert(1, false); + array.insert(2, 1); + array.insert(3, "hello world"); + map.set("a", true); + map.set("b", false); + map.set("c", 1); + map.set("d", "hello world"); + text.insert(0, "a"); + text.insert(1, "b"); + text.insert(2, "c"); + + let doc2 = new YOcto.Doc(client_id); + doc2.applyUpdate(doc.encodeStateAsUpdateV1()); + + let array2 = doc2.getOrCreateArray("array"); + let map2 = doc2.getOrCreateMap("map"); + let text2 = doc2.getOrCreateText("text"); + + // after apply update that include same client id's change + // the client id should be changed + t.not(doc2.clientId, client_id); + t.is(array2.length, 4); + t.is(array2.get(0), true); + t.is(array2.get(1), false); + t.is(array2.get(2), 1); + t.is(array2.get(3), "hello world"); + t.is(map2.length, 4); + t.is(map2.get("a"), true); + t.is(map2.get("b"), false); + t.is(map2.get("c"), 1); + t.is(map2.get("d"), "hello world"); + t.is(text2.toString(), "abc"); +}); + +test("yjs doc update should be apply", (t) => { + let doc2 = new Y.Doc(); + let array2 = doc2.getArray("array"); + let map2 = doc2.getMap("map"); + let text2 = doc2.getText("text"); + + array2.insert(0, [true]); + array2.insert(1, [false]); + array2.insert(2, [1]); + array2.insert(3, ["hello world"]); + map2.set("a", true); + map2.set("b", false); + map2.set("c", 1); + map2.set("d", "hello world"); + text2.insert(0, "a"); + text2.insert(1, "b"); + text2.insert(2, "c"); + + doc.applyUpdate(Buffer.from(Y.encodeStateAsUpdate(doc2))); + + let array = doc.getOrCreateArray("array"); + let map = doc.getOrCreateMap("map"); + let text = doc.getOrCreateText("text"); + + t.is(array.length, 4); + t.is(array.get(0), true); + t.is(array.get(1), false); + t.is(array.get(2), 1); + t.is(array.get(3), "hello world"); + t.is(map.length, 4); + t.is(map.get("a"), true); + t.is(map.get("b"), false); + t.is(map.get("c"), 1); + t.is(map.get("d"), "hello world"); + t.is(text.toString(), "abc"); +}); diff --git a/y-octo-node/tests/map.spec.mts b/y-octo-node/tests/map.spec.mts deleted file mode 100644 index f499766..0000000 --- a/y-octo-node/tests/map.spec.mts +++ /dev/null @@ -1,152 +0,0 @@ -import assert, { equal, deepEqual } from "node:assert"; -import { test } from "node:test"; - -import * as Y from "yjs"; -import { Doc, YArray, YMap, YText } from "../index"; - -test("map test", { concurrency: false }, async (t) => { - let client_id: number; - let doc: Doc; - t.beforeEach(async () => { - client_id = (Math.random() * 100000) | 0; - doc = new Doc(client_id); - }); - - t.afterEach(async () => { - client_id = -1; - // @ts-ignore - doc must not null in next range - doc = null; - }); - - await t.test("map should be created", () => { - let map = doc.getOrCreateMap("map"); - deepEqual(doc.keys, ["map"]); - equal(map.length, 0); - }); - - await t.test("map editing", () => { - let map = doc.getOrCreateMap("map"); - map.set("a", true); - map.set("b", false); - map.set("c", 1); - map.set("d", "hello world"); - equal(map.length, 4); - equal(map.get("a"), true); - equal(map.get("b"), false); - equal(map.get("c"), 1); - equal(map.get("d"), "hello world"); - equal(map.length, 4); - map.remove("b"); - equal(map.length, 3); - equal(map.get("d"), "hello world"); - }); - - await t.test("map should can be nested", () => { - let map = doc.getOrCreateMap("map"); - let sub = doc.createMap(); - map.set("sub", sub); - - sub.set("a", true); - sub.set("b", false); - sub.set("c", 1); - sub.set("d", "hello world"); - equal(sub.length, 4); - - let sub2 = map.get("sub"); - assert(sub2); - equal(sub2.get("a"), true); - equal(sub2.get("b"), false); - equal(sub2.get("c"), 1); - equal(sub2.get("d"), "hello world"); - equal(sub2.length, 4); - }); - - await t.test("y-octo to yjs compatibility test with nested type", () => { - let map = doc.getOrCreateMap("map"); - let sub_array = doc.createArray(); - let sub_map = doc.createMap(); - let sub_text = doc.createText(); - - map.set("array", sub_array); - map.set("map", sub_map); - map.set("text", sub_text); - - sub_array.insert(0, true); - sub_array.insert(1, false); - sub_array.insert(2, 1); - sub_array.insert(3, "hello world"); - sub_map.set("a", true); - sub_map.set("b", false); - sub_map.set("c", 1); - sub_map.set("d", "hello world"); - sub_text.insert(0, "a"); - sub_text.insert(1, "b"); - sub_text.insert(2, "c"); - - let doc2 = new Y.Doc(); - Y.applyUpdate(doc2, doc.encodeStateAsUpdateV1()); - - let map2 = doc2.getMap("map"); - let sub_array2 = map2.get("array") as Y.Array; - let sub_map2 = map2.get("map") as Y.Map; - let sub_text2 = map2.get("text") as Y.Text; - - assert(sub_array2); - equal(sub_array2.length, 4); - equal(sub_array2.get(0), true); - equal(sub_array2.get(1), false); - equal(sub_array2.get(2), 1); - equal(sub_array2.get(3), "hello world"); - assert(sub_map2); - equal(sub_map2.get("a"), true); - equal(sub_map2.get("b"), false); - equal(sub_map2.get("c"), 1); - equal(sub_map2.get("d"), "hello world"); - assert(sub_text2); - equal(sub_text2.toString(), "abc"); - }); - - await t.test("yjs to y-octo compatibility test with nested type", () => { - let doc2 = new Y.Doc(); - let map2 = doc2.getMap("map"); - let sub_array2 = new Y.Array(); - let sub_map2 = new Y.Map(); - let sub_text2 = new Y.Text(); - map2.set("array", sub_array2); - map2.set("map", sub_map2); - map2.set("text", sub_text2); - - sub_array2.insert(0, [true]); - sub_array2.insert(1, [false]); - sub_array2.insert(2, [1]); - sub_array2.insert(3, ["hello world"]); - sub_map2.set("a", true); - sub_map2.set("b", false); - sub_map2.set("c", 1); - sub_map2.set("d", "hello world"); - sub_text2.insert(0, "a"); - sub_text2.insert(1, "b"); - sub_text2.insert(2, "c"); - - doc.applyUpdate(Buffer.from(Y.encodeStateAsUpdate(doc2))); - - let map = doc.getOrCreateMap("map"); - let sub_array = map.get("array"); - let sub_map = map.get("map"); - let sub_text = map.get("text"); - - assert(sub_array); - equal(sub_array.length, 4); - equal(sub_array.get(0), true); - equal(sub_array.get(1), false); - equal(sub_array.get(2), 1); - equal(sub_array.get(3), "hello world"); - assert(sub_map); - equal(sub_map.get("a"), true); - equal(sub_map.get("b"), false); - equal(sub_map.get("c"), 1); - equal(sub_map.get("d"), "hello world"); - assert(sub_text); - equal(sub_text.toString(), "abc"); - }); -}); diff --git a/y-octo-node/tests/map.spec.ts b/y-octo-node/tests/map.spec.ts new file mode 100644 index 0000000..2034cc6 --- /dev/null +++ b/y-octo-node/tests/map.spec.ts @@ -0,0 +1,149 @@ +import test from "ava"; + +import * as Y from "yjs"; +import * as YOcto from "@y-octo/node"; + +let client_id: number; +let doc: YOcto.Doc; +test.beforeEach(async () => { + client_id = (Math.random() * 100000) | 0; + doc = new YOcto.Doc(client_id); +}); + +test.afterEach(async () => { + client_id = -1; + // @ts-ignore - doc must not null in next range + doc = null; +}); + +test("map should be created", (t) => { + let map = doc.getOrCreateMap("map"); + t.deepEqual(doc.keys, ["map"]); + t.is(map.length, 0); +}); + +test("map editing", (t) => { + let map = doc.getOrCreateMap("map"); + map.set("a", true); + map.set("b", false); + map.set("c", 1); + map.set("d", "hello world"); + t.is(map.length, 4); + t.is(map.get("a"), true); + t.is(map.get("b"), false); + t.is(map.get("c"), 1); + t.is(map.get("d"), "hello world"); + t.is(map.length, 4); + map.delete("b"); + t.is(map.length, 3); + t.is(map.get("d"), "hello world"); +}); + +test("map should can be nested", (t) => { + let map = doc.getOrCreateMap("map"); + let sub = doc.createMap(); + map.set("sub", sub); + + sub.set("a", true); + sub.set("b", false); + sub.set("c", 1); + sub.set("d", "hello world"); + t.is(sub.length, 4); + + let sub2 = map.get("sub"); + t.assert(sub2); + t.is(sub2.get("a"), true); + t.is(sub2.get("b"), false); + t.is(sub2.get("c"), 1); + t.is(sub2.get("d"), "hello world"); + t.is(sub2.length, 4); +}); + +test("y-octo to yjs compatibility test with nested type", (t) => { + let map = doc.getOrCreateMap("map"); + let sub_array = doc.createArray(); + let sub_map = doc.createMap(); + let sub_text = doc.createText(); + + map.set("array", sub_array); + map.set("map", sub_map); + map.set("text", sub_text); + + sub_array.insert(0, true); + sub_array.insert(1, false); + sub_array.insert(2, 1); + sub_array.insert(3, "hello world"); + sub_map.set("a", true); + sub_map.set("b", false); + sub_map.set("c", 1); + sub_map.set("d", "hello world"); + sub_text.insert(0, "a"); + sub_text.insert(1, "b"); + sub_text.insert(2, "c"); + + let doc2 = new Y.Doc(); + Y.applyUpdate(doc2, doc.encodeStateAsUpdateV1()); + + let map2 = doc2.getMap("map"); + let sub_array2 = map2.get("array") as Y.Array; + let sub_map2 = map2.get("map") as Y.Map; + let sub_text2 = map2.get("text") as Y.Text; + + t.assert(sub_array2); + t.is(sub_array2.length, 4); + t.is(sub_array2.get(0), true); + t.is(sub_array2.get(1), false); + t.is(sub_array2.get(2), 1); + t.is(sub_array2.get(3), "hello world"); + t.assert(sub_map2); + t.is(sub_map2.get("a"), true); + t.is(sub_map2.get("b"), false); + t.is(sub_map2.get("c"), 1); + t.is(sub_map2.get("d"), "hello world"); + t.assert(sub_text2); + t.is(sub_text2.toString(), "abc"); +}); + +test("yjs to y-octo compatibility test with nested type", (t) => { + let doc2 = new Y.Doc(); + let map2 = doc2.getMap("map"); + let sub_array2 = new Y.Array(); + let sub_map2 = new Y.Map(); + let sub_text2 = new Y.Text(); + map2.set("array", sub_array2); + map2.set("map", sub_map2); + map2.set("text", sub_text2); + + sub_array2.insert(0, [true]); + sub_array2.insert(1, [false]); + sub_array2.insert(2, [1]); + sub_array2.insert(3, ["hello world"]); + sub_map2.set("a", true); + sub_map2.set("b", false); + sub_map2.set("c", 1); + sub_map2.set("d", "hello world"); + sub_text2.insert(0, "a"); + sub_text2.insert(1, "b"); + sub_text2.insert(2, "c"); + + doc.applyUpdate(Buffer.from(Y.encodeStateAsUpdate(doc2))); + + let map = doc.getOrCreateMap("map"); + let sub_array = map.get("array"); + let sub_map = map.get("map"); + let sub_text = map.get("text"); + + t.assert(sub_array); + t.is(sub_array.length, 4); + t.is(sub_array.get(0), true); + t.is(sub_array.get(1), false); + t.is(sub_array.get(2), 1); + t.is(sub_array.get(3), "hello world"); + t.assert(sub_map); + t.is(sub_map.get("a"), true); + t.is(sub_map.get("b"), false); + t.is(sub_map.get("c"), 1); + t.is(sub_map.get("d"), "hello world"); + t.assert(sub_text); + t.is(sub_text.toString(), "abc"); +}); diff --git a/y-octo-node/tests/text.spec.mts b/y-octo-node/tests/text.spec.mts deleted file mode 100644 index 343d201..0000000 --- a/y-octo-node/tests/text.spec.mts +++ /dev/null @@ -1,54 +0,0 @@ -import assert, { equal, deepEqual } from "node:assert"; -import { test } from "node:test"; - -import { Doc, YText } from "../index"; - -test("text test", { concurrency: false }, async (t) => { - let client_id: number; - let doc: Doc; - t.beforeEach(async () => { - client_id = (Math.random() * 100000) | 0; - doc = new Doc(client_id); - }); - - t.afterEach(async () => { - client_id = -1; - // @ts-ignore - doc must not null in next range - doc = null; - }); - - await t.test("text should be created", () => { - let text = doc.getOrCreateText("text"); - deepEqual(doc.keys, ["text"]); - equal(text.len, 0); - }); - - await t.test("text editing", () => { - let text = doc.getOrCreateText("text"); - text.insert(0, "a"); - text.insert(1, "b"); - text.insert(2, "c"); - equal(text.toString(), "abc"); - text.remove(0, 1); - equal(text.toString(), "bc"); - text.remove(1, 1); - equal(text.toString(), "b"); - text.remove(0, 1); - equal(text.toString(), ""); - }); - - await t.test("sub text should can edit", () => { - let map = doc.getOrCreateMap("map"); - let sub = doc.createText(); - map.set("sub", sub); - - sub.insert(0, "a"); - sub.insert(1, "b"); - sub.insert(2, "c"); - equal(sub.toString(), "abc"); - - let sub2 = map.get("sub"); - assert(sub2); - equal(sub2.toString(), "abc"); - }); -}); diff --git a/y-octo-node/tests/text.spec.ts b/y-octo-node/tests/text.spec.ts new file mode 100644 index 0000000..10bbfbc --- /dev/null +++ b/y-octo-node/tests/text.spec.ts @@ -0,0 +1,51 @@ +import test from "ava"; + +import * as YOcto from "@y-octo/node"; + +let client_id: number; +let doc: YOcto.Doc; +test.beforeEach(async () => { + client_id = (Math.random() * 100000) | 0; + doc = new YOcto.Doc(client_id); +}); + +test.afterEach(async () => { + client_id = -1; + // @ts-ignore - doc must not null in next range + doc = null; +}); + +test("text should be created", (t) => { + let text = doc.getOrCreateText("text"); + t.deepEqual(doc.keys, ["text"]); + t.is(text.len, 0); +}); + +test("text editing", (t) => { + let text = doc.getOrCreateText("text"); + text.insert(0, "a"); + text.insert(1, "b"); + text.insert(2, "c"); + t.is(text.toString(), "abc"); + text.delete(0, 1); + t.is(text.toString(), "bc"); + text.delete(1, 1); + t.is(text.toString(), "b"); + text.delete(0, 1); + t.is(text.toString(), ""); +}); + +test("sub text should can edit", (t) => { + let map = doc.getOrCreateMap("map"); + let sub = doc.createText(); + map.set("sub", sub); + + sub.insert(0, "a"); + sub.insert(1, "b"); + sub.insert(2, "c"); + t.is(sub.toString(), "abc"); + + let sub2 = map.get("sub"); + t.assert(sub2); + t.is(sub2.toString(), "abc"); +}); diff --git a/y-octo-node/tests/yjs/doc.spec.ts b/y-octo-node/tests/yjs/doc.spec.ts new file mode 100644 index 0000000..dc8a74a --- /dev/null +++ b/y-octo-node/tests/yjs/doc.spec.ts @@ -0,0 +1,310 @@ +import test from "ava"; +import * as Y from "@y-octo/node"; + +test.skip("testAfterTransactionRecursion", (t) => { + const ydoc = new Y.Doc(); + const yxml = ydoc.getXmlFragment(""); + ydoc.on("afterTransaction", (tr) => { + if (tr.origin === "test") { + yxml.toJSON(); + } + }); + ydoc.transact((_tr) => { + for (let i = 0; i < 15000; i++) { + yxml.push([new Y.XmlText("a")]); + } + }, "test"); +}); + +test.skip("testOriginInTransaction", (t) => { + const doc = new Y.Doc(); + const ytext = doc.getText(); + /** + * @type {Array} + */ + const origins = []; + doc.on("afterTransaction", (tr) => { + origins.push(tr.origin); + if (origins.length <= 1) { + ytext.toDelta(Y.snapshot(doc)); // adding a snapshot forces toDelta to create a cleanup transaction + doc.transact(() => { + ytext.insert(0, "a"); + }, "nested"); + } + }); + doc.transact(() => { + ytext.insert(0, "0"); + }, "first"); + t.deepEqual(origins, ["first", "cleanup", "nested"]); +}); + +/** + * Client id should be changed when an instance receives updates from another client using the same client id. + */ +test("testClientIdDuplicateChange", (t) => { + const doc1 = new Y.Doc(0); + const doc2 = new Y.Doc(0); + t.assert(doc2.clientId === doc1.clientId); + doc1.getArray("a").insert(0, [1, 2]); + Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc1), false); + t.assert(doc2.clientId !== doc1.clientId); +}); + +test("testGetTypeEmptyId", (t) => { + const doc1 = new Y.Doc(); + doc1.getText("").insert(0, "h"); + doc1.getText().insert(1, "i"); + const doc2 = new Y.Doc(); + Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc1)); + t.assert(doc2.getText().toString() === "hi"); + t.assert(doc2.getText("").toString() === "hi"); +}); + +test.skip("testToJSON", (t) => { + const doc = new Y.Doc(); + t.deepEqual(doc.toJSON(), {}, "doc.toJSON yields empty object"); + + const arr = doc.getArray("array"); + arr.push(["test1"]); + + const map = doc.getMap("map"); + map.set("k1", "v1"); + const map2 = new Y.Map(); + map.set("k2", map2); + map2.set("m2k1", "m2v1"); + + t.deepEqual( + doc.toJSON(), + { + array: ["test1"], + map: { + k1: "v1", + k2: { + m2k1: "m2v1", + }, + }, + }, + "doc.toJSON has array and recursive map", + ); +}); + +test.skip("testSubdoc", (t) => { + const doc = new Y.Doc(); + doc.load(); // doesn't do anything + { + /** + * @type {Array|null} + */ + let event = /** @type {any} */ null; + doc.on("subdocs", (subdocs) => { + event = [ + Array.from(subdocs.added).map((x) => x.guid), + Array.from(subdocs.removed).map((x) => x.guid), + Array.from(subdocs.loaded).map((x) => x.guid), + ]; + }); + const subdocs = doc.getMap("mysubdocs"); + const docA = new Y.Doc({ guid: "a" }); + docA.load(); + subdocs.set("a", docA); + t.deepEqual(event, [["a"], [], ["a"]]); + + event = null; + subdocs.get("a").load(); + t.assert(event === null); + + event = null; + subdocs.get("a").destroy(); + t.deepEqual(event, [["a"], ["a"], []]); + subdocs.get("a").load(); + t.deepEqual(event, [[], [], ["a"]]); + + subdocs.set("b", new Y.Doc({ guid: "a", shouldLoad: false })); + t.deepEqual(event, [["a"], [], []]); + subdocs.get("b").load(); + t.deepEqual(event, [[], [], ["a"]]); + + const docC = new Y.Doc({ guid: "c" }); + docC.load(); + subdocs.set("c", docC); + t.deepEqual(event, [["c"], [], ["c"]]); + + t.deepEqual(Array.from(doc.getSubdocGuids()), ["a", "c"]); + } + + const doc2 = new Y.Doc(); + { + t.deepEqual(Array.from(doc2.getSubdocs()), []); + /** + * @type {Array|null} + */ + let event = /** @type {any} */ null; + doc2.on("subdocs", (subdocs) => { + event = [ + Array.from(subdocs.added).map((d) => d.guid), + Array.from(subdocs.removed).map((d) => d.guid), + Array.from(subdocs.loaded).map((d) => d.guid), + ]; + }); + Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc)); + t.deepEqual(event, [["a", "a", "c"], [], []]); + + doc2.getMap("mysubdocs").get("a").load(); + t.deepEqual(event, [[], [], ["a"]]); + + t.deepEqual(Array.from(doc2.getSubdocGuids()), ["a", "c"]); + + doc2.getMap("mysubdocs").delete("a"); + t.deepEqual(event, [[], ["a"], []]); + t.deepEqual(Array.from(doc2.getSubdocGuids()), ["a", "c"]); + } +}); + +test.skip("testSubdocLoadEdgeCases", (t) => { + const ydoc = new Y.Doc(); + const yarray = ydoc.getArray(); + const subdoc1 = new Y.Doc(); + /** + * @type {any} + */ + let lastEvent = null; + ydoc.on("subdocs", (event) => { + lastEvent = event; + }); + yarray.insert(0, [subdoc1]); + t.assert(subdoc1.shouldLoad); + t.assert(subdoc1.autoLoad === false); + t.assert(lastEvent !== null && lastEvent.loaded.has(subdoc1)); + t.assert(lastEvent !== null && lastEvent.added.has(subdoc1)); + // destroy and check whether lastEvent adds it again to added (it shouldn't) + subdoc1.destroy(); + const subdoc2 = yarray.get(0); + t.assert(subdoc1 !== subdoc2); + t.assert(lastEvent !== null && lastEvent.added.has(subdoc2)); + t.assert(lastEvent !== null && !lastEvent.loaded.has(subdoc2)); + // load + subdoc2.load(); + t.assert(lastEvent !== null && !lastEvent.added.has(subdoc2)); + t.assert(lastEvent !== null && lastEvent.loaded.has(subdoc2)); + // apply from remote + const ydoc2 = new Y.Doc(); + ydoc2.on("subdocs", (event) => { + lastEvent = event; + }); + Y.applyUpdate(ydoc2, Y.encodeStateAsUpdate(ydoc)); + const subdoc3 = ydoc2.getArray().get(0); + t.assert(subdoc3.shouldLoad === false); + t.assert(subdoc3.autoLoad === false); + t.assert(lastEvent !== null && lastEvent.added.has(subdoc3)); + t.assert(lastEvent !== null && !lastEvent.loaded.has(subdoc3)); + // load + subdoc3.load(); + t.assert(subdoc3.shouldLoad); + t.assert(lastEvent !== null && !lastEvent.added.has(subdoc3)); + t.assert(lastEvent !== null && lastEvent.loaded.has(subdoc3)); +}); + +test.skip("testSubdocLoadEdgeCasesAutoload", (t) => { + const ydoc = new Y.Doc(); + const yarray = ydoc.getArray(); + const subdoc1 = new Y.Doc({ autoLoad: true }); + /** + * @type {any} + */ + let lastEvent = null; + ydoc.on("subdocs", (event) => { + lastEvent = event; + }); + yarray.insert(0, [subdoc1]); + t.assert(subdoc1.shouldLoad); + t.assert(subdoc1.autoLoad); + t.assert(lastEvent !== null && lastEvent.loaded.has(subdoc1)); + t.assert(lastEvent !== null && lastEvent.added.has(subdoc1)); + // destroy and check whether lastEvent adds it again to added (it shouldn't) + subdoc1.destroy(); + const subdoc2 = yarray.get(0); + t.assert(subdoc1 !== subdoc2); + t.assert(lastEvent !== null && lastEvent.added.has(subdoc2)); + t.assert(lastEvent !== null && !lastEvent.loaded.has(subdoc2)); + // load + subdoc2.load(); + t.assert(lastEvent !== null && !lastEvent.added.has(subdoc2)); + t.assert(lastEvent !== null && lastEvent.loaded.has(subdoc2)); + // apply from remote + const ydoc2 = new Y.Doc(); + ydoc2.on("subdocs", (event) => { + lastEvent = event; + }); + Y.applyUpdate(ydoc2, Y.encodeStateAsUpdate(ydoc)); + const subdoc3 = ydoc2.getArray().get(0); + t.assert(subdoc1.shouldLoad); + t.assert(subdoc1.autoLoad); + t.assert(lastEvent !== null && lastEvent.added.has(subdoc3)); + t.assert(lastEvent !== null && lastEvent.loaded.has(subdoc3)); +}); + +test.skip("testSubdocsUndo", (t) => { + const ydoc = new Y.Doc(); + const elems = ydoc.getXmlFragment(); + const undoManager = new Y.UndoManager(elems); + const subdoc = new Y.Doc(); + // @ts-ignore + elems.insert(0, [subdoc]); + undoManager.undo(); + undoManager.redo(); + t.assert(elems.length === 1); +}); + +test.skip("testLoadDocsEvent", async (t) => { + const ydoc = new Y.Doc(); + t.assert(ydoc.isLoaded === false); + let loadedEvent = false; + ydoc.on("load", () => { + loadedEvent = true; + }); + ydoc.emit("load", [ydoc]); + await ydoc.whenLoaded; + t.assert(loadedEvent); + t.assert(ydoc.isLoaded); +}); + +test.skip("testSyncDocsEvent", async (t) => { + const ydoc = new Y.Doc(); + t.assert(ydoc.isLoaded === false); + t.assert(ydoc.isSynced === false); + let loadedEvent = false; + ydoc.once("load", () => { + loadedEvent = true; + }); + let syncedEvent = false; + ydoc.once( + "sync", + /** @param {any} isSynced */ (isSynced) => { + syncedEvent = true; + t.assert(isSynced); + }, + ); + ydoc.emit("sync", [true, ydoc]); + await ydoc.whenLoaded; + const oldWhenSynced = ydoc.whenSynced; + await ydoc.whenSynced; + t.assert(loadedEvent); + t.assert(syncedEvent); + t.assert(ydoc.isLoaded); + t.assert(ydoc.isSynced); + let loadedEvent2 = false; + ydoc.on("load", () => { + loadedEvent2 = true; + }); + let syncedEvent2 = false; + ydoc.on("sync", (isSynced) => { + syncedEvent2 = true; + t.assert(isSynced === false); + }); + ydoc.emit("sync", [false, ydoc]); + t.assert(!loadedEvent2); + t.assert(syncedEvent2); + t.assert(ydoc.isLoaded); + t.assert(!ydoc.isSynced); + t.assert(ydoc.whenSynced !== oldWhenSynced); +}); diff --git a/y-octo-node/tests/yjs/testHelper.ts b/y-octo-node/tests/yjs/testHelper.ts new file mode 100644 index 0000000..8000c2a --- /dev/null +++ b/y-octo-node/tests/yjs/testHelper.ts @@ -0,0 +1,386 @@ +import * as prng from "lib0/prng"; +import * as object from "lib0/object"; +import * as map from "lib0/map"; +import * as Y from "@y-octo/node"; +import { ExecutionContext } from "ava"; + +if (typeof window !== "undefined") { + // @ts-ignore + window.Y = Y; // eslint-disable-line +} + +/** + * @param {TestYInstance} y // publish message created by `y` to all other online clients + * @param {Uint8Array} m + */ +const broadcastMessage = (y: TestYOctoInstance, m: Uint8Array) => { + if (y.tc.onlineConns.has(y)) { + y.tc.onlineConns.forEach((remoteYInstance: TestYOctoInstance) => { + if (remoteYInstance !== y) { + remoteYInstance._receive(m, y); + } + }); + } +}; + +export class TestYOctoInstance extends Y.Doc { + protocol: Y.Protocol; + updates: Uint8Array[]; + receiving: Map; + tc: TestConnector; + constructor(testConnector: TestConnector, clientID: number) { + super(clientID); // overwriting clientID + + this.protocol = new Y.Protocol(this); + this.tc = testConnector; + this.receiving = new Map(); + testConnector.allConns.add(this); + this.updates = []; + // set up observe on local model + this.onUpdate((update, origin) => { + if (origin !== testConnector) { + broadcastMessage( + this, + this.protocol.encodeSyncStep(3, Buffer.from(update)), + ); + } + this.updates.push(update); + }); + this.connect(); + } + + /** + * Disconnect from TestConnector. + */ + disconnect() { + this.offUpdate(); + this.receiving = new Map(); + this.tc.onlineConns.delete(this); + } + + /** + * Append yourself to the list of known Y instances in testconnector. + * Also initiate sync with all clients. + */ + connect() { + if (!this.tc.onlineConns.has(this)) { + this.tc.onlineConns.add(this); + // publish SyncStep1 + broadcastMessage(this, this.protocol.encodeSyncStep(1)); + this.tc.onlineConns.forEach((remoteYInstance) => { + if (remoteYInstance !== this) { + // remote instance sends instance to this instance + this._receive( + remoteYInstance.protocol.encodeSyncStep(1), + remoteYInstance, + ); + } + }); + } + } + + /** + * Receive a message from another client. This message is only appended to the list of receiving messages. + * TestConnector decides when this client actually reads this message. + */ + _receive(message: Uint8Array, remoteClient: TestYOctoInstance) { + map + .setIfUndefined(this.receiving, remoteClient, () => [] as Uint8Array[]) + .push(message); + } +} + +/** + * Keeps track of TestYInstances. + * + * The TestYInstances add/remove themselves from the list of connections maiained in this object. + * I think it makes sense. Deal with it. + */ +export class TestConnector { + readonly allConns: Set = new Set(); + readonly onlineConns: Set = new Set(); + + constructor(readonly prng: prng.PRNG) {} + + createY(clientID: number) { + return new TestYOctoInstance(this, clientID); + } + + /** + * Choose random connection and flush a random message from a random sender. + * + * If this function was unable to flush a message, because there are no more messages to flush, it returns false. true otherwise. + */ + flushRandomMessage(): boolean { + const gen = this.prng; + const conns = Array.from(this.onlineConns).filter( + (conn) => conn.receiving.size > 0, + ); + if (conns.length > 0) { + const receiver = prng.oneOf(gen, conns); + const [sender, messages] = prng.oneOf( + gen, + Array.from(receiver.receiving), + ); + + const m = messages.shift(); + if (messages.length === 0) { + receiver.receiving.delete(sender); + } + if (m === undefined) { + return this.flushRandomMessage(); + } + + // do not publish data created when this function is executed (could be ss2 or update message) + const update = receiver.protocol.applySyncStep(Buffer.from(m)); + if (update) { + // send reply message + sender._receive(update, receiver); + } + return true; + } + return false; + } + + /** + * @return {boolean} True iff this function actually flushed something + */ + flushAllMessages(): boolean { + let didSomething = false; + while (this.flushRandomMessage()) { + didSomething = true; + } + return didSomething; + } + + reconnectAll() { + this.allConns.forEach((conn) => conn.connect()); + } + + disconnectAll() { + this.allConns.forEach((conn) => conn.disconnect()); + } + + syncAll() { + this.reconnectAll(); + this.flushAllMessages(); + } + + /** + * @return {boolean} Whether it was possible to disconnect a randon connection. + */ + disconnectRandom(): boolean { + if (this.onlineConns.size === 0) { + return false; + } + prng.oneOf(this.prng, Array.from(this.onlineConns)).disconnect(); + return true; + } + + /** + * @return {boolean} Whether it was possible to reconnect a random connection. + */ + reconnectRandom(): boolean { + const reconnectable: TestYOctoInstance[] = []; + this.allConns.forEach((conn: any) => { + if (!this.onlineConns.has(conn)) { + reconnectable.push(conn); + } + }); + if (reconnectable.length === 0) { + return false; + } + prng.oneOf(this.prng, reconnectable).connect(); + return true; + } +} + +type InitResult = { + testConnector: TestConnector; + users: Array; + testObjects: Array; + array0: Y.Array; + array1: Y.Array; + array2: Y.Array; + map0: Y.Map; + map1: Y.Map; + map2: Y.Map; + map3: Y.Map; + text0: Y.Text; + text1: Y.Text; + text2: Y.Text; + // xml0: Y.XmlElement; + // xml1: Y.XmlElement; + // xml2: Y.XmlElement; +}; +export const init = ( + gen: prng.PRNG, + { users = 5 }: { users?: number } = {}, + initTestObject?: any, +): InitResult => { + // @ts-expect-error expect + const result: InitResult = { + users: [], + testConnector: new TestConnector(gen), + }; + for (let i = 0; i < users; i++) { + const y = result.testConnector.createY(i); + y.clientId = i; + result.users.push(y); + result["array" + i] = y.getArray("array"); + result["map" + i] = y.getMap("map"); + // result["xml" + i] = y.get("xml", Y.XmlElement); + result["text" + i] = y.getText("text"); + } + result.testConnector.syncAll(); + result.testObjects = result.users.map(initTestObject || (() => null)); + return result; +}; + +/** + * 1. reconnect and flush all + * 2. user 0 gc + * 3. get type content + * 4. disconnect & reconnect all (so gc is propagated) + * 5. compare os, ds, ss + */ +export const compare = (t: ExecutionContext, users: TestYOctoInstance[]) => { + users.forEach((u) => u.connect()); + while (users[0].tc.flushAllMessages()) {} // eslint-disable-line + // For each document, merge all received document updates with Y.mergeUpdates and create a new document which will be added to the list of "users" + // This ensures that mergeUpdates works correctly + + // TODO(@darkskygit): enable this for test + // const mergedDocs = users.map((user: { updates: any }, i) => { + // const ydoc = new Y.Doc(); + // console.error(`Merging user ${i}'s updates: ${user.updates.join(", ")}`); + // ydoc.applyUpdate(Y.mergeUpdates(user.updates)); + // console.error("Merged user", ydoc.getArray("array").toJSON()); + // return ydoc; + // }); + // users.push(...mergedDocs); + const userArrayValues = users.map((u) => u.getArray("array").toJSON()); + const userMapValues = users.map((u) => u.getMap("map").toJSON()); + // const userXmlValues = users.map( + // (u: { + // get: ( + // arg0: string, + // arg1: any, + // ) => { (): any; new (): any; toString: { (): any; new (): any } }; + // }) => u.get("xml", Y.XmlElement).toString(), + // ); + // const userTextValues = users.map((u) => u.getText("text").toDelta()); + // for (const u of users) { + // t.assert(u.store.pendingDs === null); + // t.assert(u.store.pendingStructs === null); + // } + // Test Array iterator + t.deepEqual( + users[0].getArray("array").toArray(), + Array.from(users[0].getArray("array").iter()), + "Array iterator does not match", + ); + // Test Map iterator + const ymapkeys: any[] = Array.from(users[0].getMap("map").keys()); + t.is( + ymapkeys.length, + Object.keys(userMapValues[0]).length, + "Map keys do not match", + ); + ymapkeys.forEach((key) => + t.assert(object.hasProperty(userMapValues[0], key)), + ); + + const mapRes: Record = {}; + for (const [k, v] of users[0].getMap("map").entries()) { + mapRes[k] = Y.isAbstractType(v) ? v.toJSON() : v; + } + t.deepEqual(userMapValues[0], mapRes, "Map values do not match"); + // Compare all users + for (let i = 0; i < users.length - 1; i++) { + t.deepEqual( + userArrayValues[i].length, + users[i].getArray("array").length, + `array${i}.length !== array${i + 1}.length`, + ); + t.deepEqual( + userArrayValues[i], + userArrayValues[i + 1], + `array${i} !== array${i + 1}`, + ); + t.deepEqual( + userMapValues[i], + userMapValues[i + 1], + `map${i} !== map${i + 1}`, + ); + // deepEqual(userXmlValues[i], userXmlValues[i + 1]); + // deepEqual( + // userTextValues[i] + // .map( + // /** @param {any} a */ (a: { insert: any }) => + // typeof a.insert === "string" ? a.insert : " ", + // ) + // .join("").length, + // users[i].getText("text").length, + // ); + // deepEqual( + // userTextValues[i], + // userTextValues[i + 1], + // "", + // (_constructor, a, b) => { + // if (Y.isAbstractType(a)) { + // deepEqual(a.toJSON(), b.toJSON()); + // } else if (a !== b) { + // t.fail("Deltas dont match"); + // } + // return true; + // }, + // ); + t.deepEqual( + Y.encodeStateVector(users[i]), + Y.encodeStateVector(users[i + 1]), + ); + Y.equalDeleteSets( + Y.createDeleteSetFromStructStore(users[i].store), + Y.createDeleteSetFromStructStore(users[i + 1].store), + ); + Y.compareStructStores(users[i].store, users[i + 1].store); + t.deepEqual( + Y.encodeSnapshot(Y.snapshot(users[i])), + Y.encodeSnapshot(Y.snapshot(users[i + 1])), + ); + } + // users.map((u) => u.destroy()); +}; + +export const applyRandomTests = ( + t: ExecutionContext, + gen: prng.PRNG, + mods: unknown[], + iterations: number, + initTestObject?: any, +) => { + const result = init(gen, { users: 5 }, initTestObject); + const { testConnector, users } = result; + for (let i = 0; i < iterations; i++) { + if (prng.int32(gen, 0, 100) <= 2) { + // 2% chance to disconnect/reconnect a random user + if (prng.bool(gen)) { + testConnector.disconnectRandom(); + } else { + testConnector.reconnectRandom(); + } + } else if (prng.int32(gen, 0, 100) <= 1) { + // 1% chance to flush all + testConnector.flushAllMessages(); + } else if (prng.int32(gen, 0, 100) <= 50) { + // 50% chance to flush a random message + testConnector.flushRandomMessage(); + } + const user = prng.int32(gen, 0, users.length - 1); + const test: any = prng.oneOf(gen, mods); + test(users[user], gen, result.testObjects?.[user]); + } + compare(t, users); + return result; +}; diff --git a/y-octo-node/tests/yjs/y-array.spec.ts b/y-octo-node/tests/yjs/y-array.spec.ts new file mode 100644 index 0000000..4037a25 --- /dev/null +++ b/y-octo-node/tests/yjs/y-array.spec.ts @@ -0,0 +1,567 @@ +import { randomInt } from "node:crypto"; +import test, { ExecutionContext } from "ava"; +import * as prng from "lib0/prng"; +import * as math from "lib0/math"; + +import { init, compare, applyRandomTests } from "./testHelper"; +import * as Y from "@y-octo/node"; + +const production = false; + +let gen: prng.PRNG; +test.beforeEach(() => { + gen = prng.create(randomInt(0, 0xffffffff)); +}); + +test("testBasicUpdate", (t) => { + const doc1 = new Y.Doc(); + const doc2 = new Y.Doc(); + doc1.getOrCreateArray("array").insert(0, ["hi"]); + const update = Y.encodeStateAsUpdate(doc1); + Y.applyUpdate(doc2, update); + t.deepEqual(doc2.getOrCreateArray("array").toArray(), ["hi"]); +}); + +test("testSlice", (t) => { + const doc1 = new Y.Doc(); + const arr = doc1.getOrCreateArray("array"); + arr.insert(0, [1, 2, 3]); + t.deepEqual(arr.slice(0), [1, 2, 3]); + t.deepEqual(arr.slice(1), [2, 3]); + t.deepEqual(arr.slice(0, -1), [1, 2]); + arr.insert(0, [0]); + t.deepEqual(arr.slice(0), [0, 1, 2, 3]); + t.deepEqual(arr.slice(0, 2), [0, 1]); +}); + +test("testArrayFrom", (t) => { + const doc1 = new Y.Doc(); + const db1 = doc1.getOrCreateMap("root"); + const nestedArray1 = Y.Array.from([0, 1, 2]); + db1.set("array", nestedArray1); + t.deepEqual(nestedArray1.toArray(), [0, 1, 2]); +}); + +/** + * Debugging yjs#297 - a critical bug connected to the search-marker approach + */ +test("testLengthIssue", (t) => { + const doc1 = new Y.Doc(); + const arr = doc1.getOrCreateArray("array"); + arr.push([0, 1, 2, 3]); + arr.delete(0); + arr.insert(0, [0]); + t.is(arr.length, arr.toArray().length); + doc1.transact(() => { + arr.delete(1); + t.is(arr.length, arr.toArray().length); + arr.insert(1, [1]); + t.is(arr.length, arr.toArray().length); + arr.delete(2); + t.is(arr.length, arr.toArray().length); + arr.insert(2, [2]); + t.is(arr.length, arr.toArray().length); + }); + t.is(arr.length, arr.toArray().length); + arr.delete(1); + t.is(arr.length, arr.toArray().length); + arr.insert(1, [1]); + t.is(arr.length, arr.toArray().length); +}); + +/** + * Debugging yjs#314 + */ +test("testLengthIssue2", (t) => { + const doc = new Y.Doc(); + const next = doc.createArray(); + doc.transact(() => { + next.insert(0, ["group2"]); + }); + doc.transact(() => { + next.insert(1, ["rectangle3"]); + }); + doc.transact(() => { + next.delete(0); + next.insert(0, ["rectangle3"]); + }); + next.delete(1); + doc.transact(() => { + next.insert(1, ["ellipse4"]); + }); + doc.transact(() => { + next.insert(2, ["ellipse3"]); + }); + doc.transact(() => { + next.insert(3, ["ellipse2"]); + }); + doc.transact(() => { + doc.transact(() => { + t.throws(() => { + next.insert(5, ["rectangle2"]); + }); + next.insert(4, ["rectangle2"]); + }); + doc.transact(() => { + // this should not throw an error message + next.delete(4); + }); + }); + console.log(next.toArray()); +}); + +test("testDeleteInsert", (t) => { + const { users, array0 } = init(gen, { users: 2 }); + + array0.delete(0, 0); + t.notThrows(() => { + array0.delete(1, 1); + }, "Does not throw when deleting zero elements with position 0"); + array0.insert(0, ["A"]); + t.notThrows(() => { + array0.delete(1, 0); + }, "Does not throw when deleting zero elements with valid position 1"); + compare(t, users); +}); + +test("testInsertThreeElementsTryRegetProperty", (t) => { + const { testConnector, users, array0, array1 } = init(gen, { users: 2 }); + + array0.insert(0, [1, true, false]); + t.deepEqual(array0.toJSON(), [1, true, false], ".toJSON() works"); + testConnector.flushAllMessages(); + t.deepEqual(array1.toJSON(), [1, true, false], ".toJSON() works after sync"); + compare(t, users); +}); + +test("testConcurrentInsertWithThreeConflicts", (t) => { + const { users, array0, array1, array2 } = init(gen, { users: 3 }); + + array0.insert(0, [0]); + array1.insert(0, [1]); + array2.insert(0, [2]); + compare(t, users); +}); + +test("testConcurrentInsertDeleteWithThreeConflicts", (t) => { + const { testConnector, users, array0, array1, array2 } = init(gen, { + users: 3, + }); + + array0.insert(0, ["x", "y", "z"]); + testConnector.flushAllMessages(); + array0.insert(1, [0]); + array1.delete(0); + array1.delete(1, 1); + array2.insert(1, [2]); + compare(t, users); +}); + +test("testInsertionsInLateSync", (t) => { + const { testConnector, users, array0, array1, array2 } = init(gen, { + users: 3, + }); + + array0.insert(0, ["x", "y"]); + testConnector.flushAllMessages(); + users[1].disconnect(); + users[2].disconnect(); + array0.insert(1, ["user0"]); + array1.insert(1, ["user1"]); + array2.insert(1, ["user2"]); + users[1].connect(); + users[2].connect(); + testConnector.flushAllMessages(); + compare(t, users); +}); + +test("testDisconnectReallyPreventsSendingMessages", (t) => { + const { testConnector, users, array0, array1 } = init(gen, { users: 3 }); + + array0.insert(0, ["x", "y"]); + testConnector.flushAllMessages(); + users[1].disconnect(); + users[2].disconnect(); + array0.insert(1, ["user0"]); + array1.insert(1, ["user1"]); + t.deepEqual(array0.toJSON(), ["x", "user0", "y"]); + t.deepEqual(array1.toJSON(), ["x", "user1", "y"]); + users[1].connect(); + users[2].connect(); + compare(t, users); +}); + +test("testDeletionsInLateSync", (t) => { + const { testConnector, users, array0, array1 } = init(gen, { users: 2 }); + + array0.insert(0, ["x", "y"]); + testConnector.flushAllMessages(); + users[1].disconnect(); + array1.delete(1, 1); + array0.delete(0, 2); + users[1].connect(); + compare(t, users); +}); + +test.skip("testInsertThenMergeDeleteOnSync", (t) => { + const { testConnector, users, array0, array1 } = init(gen, { users: 2 }); + + array0.insert(0, ["x", "y", "z"]); + testConnector.flushAllMessages(); + users[0].disconnect(); + array1.delete(0, 3); + users[0].connect(); + compare(t, users); +}); + +test.skip("testInsertAndDeleteEvents", (t) => { + const { array0, users } = init(gen, { users: 2 }); + + let event: Record | null = null; + array0.observe((e) => { + event = e; + }); + array0.insert(0, [0, 1, 2]); + t.assert(event !== null); + event = null; + array0.delete(0); + t.assert(event !== null); + event = null; + array0.delete(0, 2); + t.assert(event !== null); + event = null; + compare(t, users); +}); + +test.skip("testNestedObserverEvents", (t) => { + const { array0, users } = init(gen, { users: 2 }); + + const vals: number[] = []; + array0.observe((e) => { + if (array0.length === 1) { + // inserting, will call this observer again + // we expect that this observer is called after this event handler finishedn + array0.insert(1, [1]); + vals.push(0); + } else { + // this should be called the second time an element is inserted (above case) + vals.push(1); + } + }); + array0.insert(0, [0]); + t.deepEqual(vals, [0, 1]); + t.deepEqual(array0.toArray(), [0, 1]); + compare(t, users); +}); + +test.skip("testInsertAndDeleteEventsForTypes", (t) => { + const { array0, users } = init(gen, { users: 2 }); + + let event: Record | null = null; + array0.observe((e) => { + event = e; + }); + array0.insert(0, [new Y.Array()]); + t.assert(event !== null); + event = null; + array0.delete(0); + t.assert(event !== null); + event = null; + compare(t, users); +}); + +/** + * This issue has been reported in https://discuss.yjs.dev/t/order-in-which-events-yielded-by-observedeep-should-be-applied/261/2 + * + * Deep observers generate multiple events. When an array added at item at, say, position 0, + * and item 1 changed then the array-add event should fire first so that the change event + * path is correct. A array binding might lead to an inconsistent state otherwise. + */ +test.skip("testObserveDeepEventOrder", (t) => { + const { array0, users } = init(gen, { users: 2 }); + + let events: any[] = []; + array0.observeDeep((e) => { + events = e; + }); + array0.insert(0, [new Y.Map()]); + users[0].transact(() => { + array0.get(0).set("a", "a"); + array0.insert(0, [0]); + }); + for (let i = 1; i < events.length; i++) { + t.assert( + events[i - 1].path.length <= events[i].path.length, + "path size increases, fire top-level events first", + ); + } +}); + +/** + * Correct index when computing event.path in observeDeep - https://github.com/yjs/yjs/issues/457 + */ +test.skip("testObservedeepIndexes", (t) => { + const doc = new Y.Doc(); + const map = doc.createMap(); + // Create a field with the array as value + map.set("my-array", new Y.Array()); + // Fill the array with some strings and our Map + map.get("my-array").push(["a", "b", "c", new Y.Map()]); + let eventPath: any[] = []; + map.observeDeep((events) => { + eventPath = events[0].path; + }); + // set a value on the map inside of our array + map.get("my-array").get(3).set("hello", "world"); + console.log(eventPath); + t.deepEqual(eventPath, ["my-array", 3]); +}); + +test.skip("testChangeEvent", (t) => { + const { array0, users } = init(gen, { users: 2 }); + + let changes: any = null; + array0.observe((e) => { + changes = e.changes; + }); + const newArr = new Y.Array(); + array0.insert(0, [newArr, 4, "dtrn"]); + t.assert( + changes !== null && changes.added.size === 2 && changes.deleted.size === 0, + ); + t.deepEqual(changes.delta, [{ insert: [newArr, 4, "dtrn"] }]); + changes = null; + array0.delete(0, 2); + t.assert( + changes !== null && changes.added.size === 0 && changes.deleted.size === 2, + ); + t.deepEqual(changes.delta, [{ delete: 2 }]); + changes = null; + array0.insert(1, [0.1]); + t.assert( + changes !== null && changes.added.size === 1 && changes.deleted.size === 0, + ); + t.deepEqual(changes.delta, [{ retain: 1 }, { insert: [0.1] }]); + compare(t, users); +}); + +test.skip("testInsertAndDeleteEventsForTypes2", (t) => { + const { array0, users } = init(gen, { users: 2 }); + + const events: Record[] = []; + array0.observe((e) => { + events.push(e); + }); + array0.insert(0, ["hi", new Y.Map()]); + t.is( + events.length, + 1, + "Event is triggered exactly once for insertion of two elements", + ); + array0.delete(1); + t.is(events.length, 2, "Event is triggered exactly once for deletion"); + compare(t, users); +}); + +/** + * This issue has been reported here https://github.com/yjs/yjs/issues/155 + */ +test.skip("testNewChildDoesNotEmitEventInTransaction", (t) => { + const { array0, users } = init(gen, { users: 2 }); + + let fired = false; + users[0].transact(() => { + const newMap = new Y.Map(); + newMap.observe(() => { + fired = true; + }); + array0.insert(0, [newMap]); + newMap.set("tst", 42); + }); + t.assert(!fired, "Event does not trigger"); +}); + +test.skip("testGarbageCollector", (t) => { + const { testConnector, users, array0 } = init(gen, { users: 3 }); + + array0.insert(0, ["x", "y", "z"]); + testConnector.flushAllMessages(); + users[0].disconnect(); + array0.delete(0, 3); + users[0].connect(); + testConnector.flushAllMessages(); + compare(t, users); +}); + +test.skip("testEventTargetIsSetCorrectlyOnLocal", (t) => { + const { array0, users } = init(gen, { users: 3 }); + + let event: any; + array0.observe((e) => { + event = e; + }); + array0.insert(0, ["stuff"]); + t.assert(event.target === array0, '"target" property is set correctly'); + compare(t, users); +}); + +test.skip("testEventTargetIsSetCorrectlyOnRemote", (t) => { + const { testConnector, array0, array1, users } = init(gen, { users: 3 }); + + let event: any; + array0.observe((e) => { + event = e; + }); + array1.insert(0, ["stuff"]); + testConnector.flushAllMessages(); + t.assert(event.target === array0, '"target" property is set correctly'); + compare(t, users); +}); + +test("testIteratingArrayContainingTypes", (t) => { + const y = new Y.Doc(); + const arr = y.getOrCreateArray("arr"); + const numItems = 10; + for (let i = 0; i < numItems; i++) { + const map = y.createMap(); + map.set("value", i); + arr.push([map]); + } + t.is(arr.length, numItems, "array length mot correct"); + let cnt = 0; + for (const item of arr.iter()) { + t.is(item.get("value"), cnt++, "value is correct"); + } + y.destroy(); +}); + +let _uniqueNumber = 0; +const getUniqueNumber = () => _uniqueNumber++; + +const arrayTransactions: Array< + (t: ExecutionContext, arg0: Y.Doc, arg1: prng.PRNG, arg2: any) => void +> = [ + function insert(t, user, gen) { + const yarray = user.getOrCreateArray("array"); + const uniqueNumber = getUniqueNumber(); + const content: number[] = []; + const len = prng.int32(gen, 1, 4); + for (let i = 0; i < len; i++) { + content.push(uniqueNumber); + } + const pos = prng.int32(gen, 0, yarray.length); + const oldContent = yarray.toArray(); + yarray.insert(pos, content); + oldContent.splice(pos, 0, ...content); + t.deepEqual(yarray.toArray(), oldContent); // we want to make sure that fastSearch markers insert at the correct position + }, + function insertTypeArray(t, user, gen) { + const yarray = user.getOrCreateArray("array"); + const pos = prng.int32(gen, 0, yarray.length); + yarray.insert(pos, [user.createArray()]); + const array2 = yarray.get(pos); + array2.insert(0, [1, 2, 3, 4]); + }, + function insertTypeMap(t, user, gen) { + const yarray = user.getOrCreateArray("array"); + const pos = prng.int32(gen, 0, yarray.length); + yarray.insert(pos, [user.createMap()]); + const map = yarray.get(pos); + map.set("someprop", 42); + map.set("someprop", 43); + map.set("someprop", 44); + }, + function insertTypeNull(t, user, gen) { + const yarray = user.getOrCreateArray("array"); + const pos = prng.int32(gen, 0, yarray.length); + yarray.insert(pos, [null]); + }, + function _delete(t, user, gen) { + const yarray = user.getOrCreateArray("array"); + const length = yarray.length; + if (length > 0) { + let somePos = prng.int32(gen, 0, length - 1); + let delLength = prng.int32(gen, 1, math.min(2, length - somePos)); + if (prng.bool(gen)) { + const type = yarray.get(somePos); + if (type instanceof Y.Array && type.length > 0) { + somePos = prng.int32(gen, 0, type.length - 1); + delLength = prng.int32(gen, 0, math.min(2, type.length - somePos)); + type.delete(somePos, delLength); + } + } else { + const oldContent = yarray.toArray(); + yarray.delete(somePos, delLength); + oldContent.splice(somePos, delLength); + t.deepEqual(yarray.toArray(), oldContent); + } + } + }, +]; + +test.skip("testRepeatGeneratingYarrayTests6", (t) => { + applyRandomTests(t, gen, arrayTransactions, 6); +}); + +test.skip("testRepeatGeneratingYarrayTests40", (t) => { + applyRandomTests(t, gen, arrayTransactions, 40); +}); + +test.skip("testRepeatGeneratingYarrayTests42", (t) => { + applyRandomTests(t, gen, arrayTransactions, 42); +}); + +test.skip("testRepeatGeneratingYarrayTests43", (t) => { + applyRandomTests(t, gen, arrayTransactions, 43); +}); + +test.skip("testRepeatGeneratingYarrayTests44", (t) => { + applyRandomTests(t, gen, arrayTransactions, 44); +}); + +test.skip("testRepeatGeneratingYarrayTests45", (t) => { + applyRandomTests(t, gen, arrayTransactions, 45); +}); + +test.skip("testRepeatGeneratingYarrayTests46", (t) => { + applyRandomTests(t, gen, arrayTransactions, 46); +}); + +test.skip("testRepeatGeneratingYarrayTests300", (t) => { + applyRandomTests(t, gen, arrayTransactions, 300); +}); + +test.skip("testRepeatGeneratingYarrayTests400", (t) => { + applyRandomTests(t, gen, arrayTransactions, 400); +}); + +test.skip("testRepeatGeneratingYarrayTests500", (t) => { + applyRandomTests(t, gen, arrayTransactions, 500); +}); + +test.skip("testRepeatGeneratingYarrayTests600", (t) => { + applyRandomTests(t, gen, arrayTransactions, 600); +}); + +test.skip("testRepeatGeneratingYarrayTests1000", (t) => { + applyRandomTests(t, gen, arrayTransactions, 1000); +}); + +test.skip("testRepeatGeneratingYarrayTests1800", (t) => { + applyRandomTests(t, gen, arrayTransactions, 1800); +}); + +test.skip("testRepeatGeneratingYarrayTests3000", (t) => { + if (!production) return; + applyRandomTests(t, gen, arrayTransactions, 3000); +}); + +test.skip("testRepeatGeneratingYarrayTests5000", (t) => { + if (!production) return; + applyRandomTests(t, gen, arrayTransactions, 5000); +}); + +test.skip("testRepeatGeneratingYarrayTests30000", (t) => { + if (!production) return; + applyRandomTests(t, gen, arrayTransactions, 30000); +}); diff --git a/y-octo-node/tests/yjs/y-map.spec.ts b/y-octo-node/tests/yjs/y-map.spec.ts new file mode 100644 index 0000000..71ce403 --- /dev/null +++ b/y-octo-node/tests/yjs/y-map.spec.ts @@ -0,0 +1,725 @@ +import { randomInt } from "node:crypto"; +import test, { ExecutionContext } from "ava"; + +import { init, compare, applyRandomTests } from "./testHelper.js"; + +import * as Y from "@y-octo/node"; +import * as prng from "lib0/prng"; + +const production = false; + +let gen: prng.PRNG; +test.beforeEach(() => { + gen = prng.create(randomInt(0, 0xffffffff)); +}); + +test("testIterators", (t) => { + const ydoc = new Y.Doc(); + const ymap = ydoc.createMap(); + // we are only checking if the type assumptions are correct + const vals = Array.from(ymap.values()); + const entries = Array.from(ymap.entries()); + const keys = Array.from(ymap.keys()); + t.is(vals.length, 0); + t.is(entries.length, 0); + t.is(keys.length, 0); +}); + +/** + * Computing event changes after transaction should result in an error. See yjs#539 + */ +test.skip("testMapEventError", (t) => { + const doc = new Y.Doc(); + const ymap = doc.createMap(); + + let event: any = null; + ymap.observe((e) => { + event = e; + }); + t.throws(() => { + console.info(event.keys); + }); + t.throws(() => { + console.info(event.keys); + }); +}); + +test("testMapHavingIterableAsConstructorParamTests", (t) => { + const { users, map0, testConnector } = init(gen, { users: 1 }); + + const m1 = users[0].createMap(Object.entries({ number: 1, string: "hello" })); + map0.set("m1", m1); + t.assert(m1.get("number") === 1); + t.assert(m1.get("string") === "hello"); + + const m2 = users[0].createMap([ + ["object", { x: 1 }], + ["boolean", true], + ]); + map0.set("m2", m2); + t.assert(m2.get("object").x === 1); + t.assert(m2.get("boolean") === true); + + const m3 = users[0].createMap([...m1.entries(), ...m2.entries()]); + map0.set("m3", m3); + t.assert(m3.get("number") === 1); + t.assert(m3.get("string") === "hello"); + t.assert(m3.get("object").x === 1); + t.assert(m3.get("boolean") === true); + testConnector.disconnectAll(); +}); + +test("testBasicMapTests", (t) => { + const { testConnector, users, map0, map1, map2 } = init(gen, { users: 3 }); + + users[2].disconnect(); + + map0.set("null", null); + map0.set("number", 1); + map0.set("string", "hello Y"); + map0.set("object", { key: { key2: "value" } }); + map0.set("y-map", new Y.Map()); + map0.set("boolean1", true); + map0.set("boolean0", false); + const map = map0.get("y-map"); + map.set("y-array", new Y.Array()); + const array = map.get("y-array"); + array.insert(0, [0]); + array.insert(0, [-1]); + + t.assert(map0.get("null") === null, "client 0 computed the change (null)"); + t.assert(map0.get("number") === 1, "client 0 computed the change (number)"); + t.assert( + map0.get("string") === "hello Y", + "client 0 computed the change (string)", + ); + t.assert( + map0.get("boolean0") === false, + "client 0 computed the change (boolean)", + ); + t.assert( + map0.get("boolean1") === true, + "client 0 computed the change (boolean)", + ); + t.deepEqual( + map0.get("object"), + { key: { key2: "value" } }, + "client 0 computed the change (object)", + ); + t.assert( + map0.get("y-map").get("y-array").get(0) === -1, + "client 0 computed the change (type)", + ); + t.assert(map0.size === 7, "client 0 map has correct size"); + + users[2].connect(); + testConnector.flushAllMessages(); + + t.assert(map1.get("null") === null, "client 1 received the update (null)"); + t.assert(map1.get("number") === 1, "client 1 received the update (number)"); + t.assert( + map1.get("string") === "hello Y", + "client 1 received the update (string)", + ); + t.assert( + map1.get("boolean0") === false, + "client 1 computed the change (boolean)", + ); + t.assert( + map1.get("boolean1") === true, + "client 1 computed the change (boolean)", + ); + t.deepEqual( + map1.get("object"), + { key: { key2: "value" } }, + "client 1 received the update (object)", + ); + t.assert( + map1.get("y-map").get("y-array").get(0) === -1, + "client 1 received the update (type)", + ); + t.assert(map1.size === 7, "client 1 map has correct size"); + + // compare disconnected user + t.assert( + map2.get("null") === null, + "client 2 received the update (null) - was disconnected", + ); + t.assert( + map2.get("number") === 1, + "client 2 received the update (number) - was disconnected", + ); + t.assert( + map2.get("string") === "hello Y", + "client 2 received the update (string) - was disconnected", + ); + t.assert( + map2.get("boolean0") === false, + "client 2 computed the change (boolean)", + ); + t.assert( + map2.get("boolean1") === true, + "client 2 computed the change (boolean)", + ); + t.deepEqual( + map2.get("object"), + { key: { key2: "value" } }, + "client 2 received the update (object) - was disconnected", + ); + t.assert( + map2.get("y-map").get("y-array").get(0) === -1, + "client 2 received the update (type) - was disconnected", + ); + compare(t, users); +}); + +test("testGetAndSetOfMapProperty", (t) => { + const { testConnector, users, map0 } = init(gen, { users: 2 }); + + map0.set("stuff", "stuffy"); + map0.set("undefined", undefined); + map0.set("null", null); + t.deepEqual(map0.get("stuff"), "stuffy"); + + testConnector.flushAllMessages(); + + for (const user of users) { + const u = user.getOrCreateMap("map"); + t.deepEqual(u.get("stuff"), "stuffy"); + t.is(u.get("undefined"), undefined, "undefined"); + t.deepEqual(u.get("null"), null, "null"); + } + compare(t, users); +}); + +test("testYmapSetsYmap", (t) => { + const { users, map0 } = init(gen, { users: 2 }); + + const map = map0.set("Map", users[0].createMap()); + t.assert(Y.compareIds(map0.get("Map").itemId, map.itemId)); + map.set("one", 1); + t.deepEqual(map.get("one"), 1); + compare(t, users); +}); + +test("testYmapSetsYarray", (t) => { + const { users, map0 } = init(gen, { users: 2 }); + + const array = map0.set("Array", new Y.Array()); + t.assert(Y.compareIds(array.itemId, map0.get("Array").itemId)); + array.insert(0, [1, 2, 3]); + // @ts-ignore + t.deepEqual(map0.toJSON(), { Array: [1, 2, 3] }); + compare(t, users); +}); + +test("testGetAndSetOfMapPropertySyncs", (t) => { + const { testConnector, users, map0 } = init(gen, { users: 2 }); + + map0.set("stuff", "stuffy"); + t.deepEqual(map0.get("stuff"), "stuffy"); + testConnector.flushAllMessages(); + for (const user of users) { + const u = user.getOrCreateMap("map"); + t.deepEqual(u.get("stuff"), "stuffy"); + } + compare(t, users); +}); + +test.skip("testGetAndSetOfMapPropertyWithConflict", (t) => { + const { testConnector, users, map0, map1 } = init(gen, { users: 3 }); + + map0.set("stuff", "c0"); + map1.set("stuff", "c1"); + testConnector.flushAllMessages(); + for (const user of users) { + const u = user.getOrCreateMap("map"); + t.deepEqual(u.get("stuff"), "c1"); + } + compare(t, users); +}); + +test("testSizeAndDeleteOfMapProperty", (t) => { + const { map0, testConnector } = init(gen, { users: 1 }); + + map0.set("stuff", "c0"); + map0.set("otherstuff", "c1"); + t.assert(map0.size === 2, `map size is ${map0.size} expected 2`); + map0.delete("stuff"); + t.assert( + map0.size === 1, + `map size after delete is ${map0.size}, expected 1`, + ); + map0.delete("otherstuff"); + t.assert( + map0.size === 0, + `map size after delete is ${map0.size}, expected 0`, + ); + testConnector.disconnectAll(); +}); + +test("testGetAndSetAndDeleteOfMapProperty", (t) => { + const { testConnector, users, map0, map1 } = init(gen, { users: 3 }); + + map0.set("stuff", "c0"); + map1.set("stuff", "c1"); + map1.delete("stuff"); + testConnector.flushAllMessages(); + for (const user of users) { + const u = user.getOrCreateMap("map"); + t.is(u.get("stuff"), undefined); + } + compare(t, users); +}); + +test("testSetAndClearOfMapProperties", (t) => { + const { testConnector, users, map0 } = init(gen, { users: 1 }); + + map0.set("stuff", "c0"); + map0.set("otherstuff", "c1"); + map0.clear(); + testConnector.flushAllMessages(); + for (const user of users) { + const u = user.getOrCreateMap("map"); + t.is(u.get("stuff"), undefined); + t.is(u.get("otherstuff"), undefined); + t.is(u.size, 0, `map size after clear is ${u.size}, expected 0`); + } + compare(t, users); +}); + +test.skip("testSetAndClearOfMapPropertiesWithConflicts", (t) => { + const { testConnector, users, map0, map1, map2, map3 } = init(gen, { + users: 4, + }); + + map0.set("stuff", "c0"); + map1.set("stuff", "c1"); + map1.set("stuff", "c2"); + map2.set("stuff", "c3"); + testConnector.flushAllMessages(); + map0.set("otherstuff", "c0"); + map1.set("otherstuff", "c1"); + map2.set("otherstuff", "c2"); + map3.set("otherstuff", "c3"); + map3.clear(); + testConnector.flushAllMessages(); + for (const user of users) { + const u = user.getOrCreateMap("map"); + t.assert(u.get("stuff") === undefined); + t.assert(u.get("otherstuff") === undefined); + t.assert(u.size === 0, `map size after clear is ${u.size}, expected 0`); + } + compare(t, users); +}); + +test.skip("testGetAndSetOfMapPropertyWithThreeConflicts", (t) => { + const { testConnector, users, map0, map1, map2 } = init(gen, { users: 3 }); + + map0.set("stuff", "c0"); + map1.set("stuff", "c1"); + map1.set("stuff", "c2"); + map2.set("stuff", "c3"); + testConnector.flushAllMessages(); + for (const user of users) { + const u = user.getOrCreateMap("map"); + t.deepEqual(u.get("stuff"), "c3"); + } + compare(t, users); +}); + +test.skip("testGetAndSetAndDeleteOfMapPropertyWithThreeConflicts", (t) => { + const { testConnector, users, map0, map1, map2, map3 } = init(gen, { + users: 4, + }); + + map0.set("stuff", "c0"); + map1.set("stuff", "c1"); + map1.set("stuff", "c2"); + map2.set("stuff", "c3"); + testConnector.flushAllMessages(); + map0.set("stuff", "deleteme"); + map1.set("stuff", "c1"); + map2.set("stuff", "c2"); + map3.set("stuff", "c3"); + map3.delete("stuff"); + testConnector.flushAllMessages(); + for (const user of users) { + const u = user.getOrCreateMap("map"); + t.assert(u.get("stuff") === undefined); + } + compare(t, users); +}); + +test.skip("testObserveDeepProperties", (t) => { + const { testConnector, users, map1, map2, map3 } = init(gen, { users: 4 }); + + const _map1 = map1.set("map", users[0].createMap()); + let calls = 0; + let dmapid; + map1.observeDeep((events) => { + events.forEach((event) => { + calls++; + // @ts-ignore + t.assert(event.keysChanged.has("deepmap")); + t.assert(event.path.length === 1); + t.assert(event.path[0] === "map"); + // @ts-ignore + dmapid = event.target.get("deepmap")._item.id; + }); + }); + testConnector.flushAllMessages(); + const _map3 = map3.get("map"); + _map3.set("deepmap", new Y.Map()); + testConnector.flushAllMessages(); + const _map2 = map2.get("map"); + _map2.set("deepmap", new Y.Map()); + testConnector.flushAllMessages(); + const dmap1 = _map1.get("deepmap"); + const dmap2 = _map2.get("deepmap"); + const dmap3 = _map3.get("deepmap"); + t.assert(calls > 0); + t.assert(Y.compareIds(dmap1.itemId, dmap2.itemId)); + t.assert(Y.compareIds(dmap1.itemId, dmap3.itemId)); + // @ts-ignore we want the possibility of dmapid being undefined + t.assert(compareIDs(dmap1._item.id, dmapid)); + compare(t, users); +}); + +test.skip("testObserversUsingObservedeep", (t) => { + const { users, map0 } = init(gen, { users: 2 }); + + const pathes: Array> = []; + let calls = 0; + map0.observeDeep((events) => { + events.forEach((event) => { + pathes.push(event.path); + }); + calls++; + }); + map0.set("map", new Y.Map()); + map0.get("map").set("array", new Y.Array()); + map0.get("map").get("array").insert(0, ["content"]); + t.assert(calls === 3); + t.deepEqual(pathes, [[], ["map"], ["map", "array"]]); + compare(t, users); +}); + +test.skip("testPathsOfSiblingEvents", (t) => { + const { users, map0 } = init(gen, { users: 2 }); + + const pathes: Array> = []; + let calls = 0; + const doc = users[0]; + map0.set("map", users[0].createMap()); + map0.get("map").set("text1", users[0].createText("initial")); + map0.observeDeep((events) => { + events.forEach((event) => { + pathes.push(event.path); + }); + calls++; + }); + doc.transact(() => { + map0.get("map").get("text1").insert(0, "post-"); + map0.get("map").set("text2", users[0].createText("new")); + }); + t.assert(calls === 1); + t.deepEqual(pathes, [["map"], ["map", "text1"]]); + compare(t, users); +}); + +// TODO: Test events in Y.Map +/** + * @param {Object} is + * @param {Object} should + */ +const compareEvent = ( + t: ExecutionContext, + is: { [s: string]: any }, + should: { [s: string]: any }, +) => { + for (const key in should) { + t.deepEqual(should[key], is[key]); + } +}; + +test.skip("testThrowsAddAndUpdateAndDeleteEvents", (t) => { + const { users, map0 } = init(gen, { users: 2 }); + /** + * @type {Object} + */ + let event: { [s: string]: any } = {}; + map0.observe((e) => { + event = e; // just put it on event, should be thrown synchronously anyway + }); + map0.set("stuff", 4); + compareEvent(t, event, { + target: map0, + keysChanged: new Set(["stuff"]), + }); + // update, oldValue is in contents + map0.set("stuff", new Y.Array()); + compareEvent(t, event, { + target: map0, + keysChanged: new Set(["stuff"]), + }); + // update, oldValue is in opContents + map0.set("stuff", 5); + // delete + map0.delete("stuff"); + compareEvent(t, event, { + keysChanged: new Set(["stuff"]), + target: map0, + }); + compare(t, users); +}); + +test.skip("testThrowsDeleteEventsOnClear", (t) => { + const { users, map0 } = init(gen, { users: 2 }); + /** + * @type {Object} + */ + let event: { [s: string]: any } = {}; + map0.observe((e) => { + event = e; // just put it on event, should be thrown synchronously anyway + }); + // set values + map0.set("stuff", 4); + map0.set("otherstuff", new Y.Array()); + // clear + map0.clear(); + compareEvent(t, event, { + keysChanged: new Set(["stuff", "otherstuff"]), + target: map0, + }); + compare(t, users); +}); + +test.skip("testChangeEvent", (t) => { + const { map0, users } = init(gen, { users: 2 }); + /** + * @type {any} + */ + let changes: any = null; + /** + * @type {any} + */ + let keyChange: any = null; + map0.observe((e) => { + changes = e.changes; + }); + map0.set("a", 1); + keyChange = changes.keys.get("a"); + t.assert( + changes !== null && + keyChange.action === "add" && + keyChange.oldValue === undefined, + ); + map0.set("a", 2); + keyChange = changes.keys.get("a"); + t.assert( + changes !== null && + keyChange.action === "update" && + keyChange.oldValue === 1, + ); + users[0].transact(() => { + map0.set("a", 3); + map0.set("a", 4); + }); + keyChange = changes.keys.get("a"); + t.assert( + changes !== null && + keyChange.action === "update" && + keyChange.oldValue === 2, + ); + users[0].transact(() => { + map0.set("b", 1); + map0.set("b", 2); + }); + keyChange = changes.keys.get("b"); + t.assert( + changes !== null && + keyChange.action === "add" && + keyChange.oldValue === undefined, + ); + users[0].transact(() => { + map0.set("c", 1); + map0.delete("c"); + }); + t.assert(changes !== null && changes.keys.size === 0); + users[0].transact(() => { + map0.set("d", 1); + map0.set("d", 2); + }); + keyChange = changes.keys.get("d"); + t.assert( + changes !== null && + keyChange.action === "add" && + keyChange.oldValue === undefined, + ); + compare(t, users); +}); + +test.skip("testYmapEventExceptionsShouldCompleteTransaction", (t) => { + const doc = new Y.Doc(); + const map = doc.getOrCreateMap("map"); + + let updateCalled = false; + let throwingObserverCalled = false; + let throwingDeepObserverCalled = false; + doc.onUpdate(() => { + updateCalled = true; + }); + + const throwingObserver = () => { + throwingObserverCalled = true; + throw new Error("Failure"); + }; + + const throwingDeepObserver = () => { + throwingDeepObserverCalled = true; + throw new Error("Failure"); + }; + + map.observe(throwingObserver); + map.observeDeep(throwingDeepObserver); + + t.throws(() => { + map.set("y", "2"); + }); + + t.assert(updateCalled); + t.assert(throwingObserverCalled); + t.assert(throwingDeepObserverCalled); + + // check if it works again + updateCalled = false; + throwingObserverCalled = false; + throwingDeepObserverCalled = false; + t.throws(() => { + map.set("z", "3"); + }); + + t.assert(updateCalled); + t.assert(throwingObserverCalled); + t.assert(throwingDeepObserverCalled); + + t.assert(map.get("z") === "3"); +}); + +test.skip("testYmapEventHasCorrectValueWhenSettingAPrimitive", (t) => { + const { users, map0 } = init(gen, { users: 3 }); + + /** + * @type {Object} + */ + let event: { [s: string]: any } = {}; + map0.observe((e) => { + event = e; + }); + map0.set("stuff", 2); + t.deepEqual(event.value, event.target.get(event.name)); + compare(t, users); +}); + +test.skip("testYmapEventHasCorrectValueWhenSettingAPrimitiveFromOtherUser", (t) => { + const { users, map0, map1, testConnector } = init(gen, { users: 3 }); + + let event: Record = {}; + map0.observe((e) => { + event = e; + }); + map1.set("stuff", 2); + testConnector.flushAllMessages(); + t.deepEqual(event.value, event.target.get(event.name)); + compare(t, users); +}); + +const mapTransactions: Array<(arg0: Y.Doc, arg1: prng.PRNG) => void> = [ + function set(user, gen) { + const key = prng.oneOf(gen, ["one", "two"]); + const value = prng.utf16String(gen); + user.getOrCreateMap("map").set(key, value); + }, + function setType(user, gen) { + const key = prng.oneOf(gen, ["one", "two"]); + const type = prng.oneOf(gen, [new Y.Array(), new Y.Map()]); + user.getOrCreateMap("map").set(key, type); + if (type instanceof Y.Array) { + type.insert(0, [1, 2, 3, 4]); + } else { + type.set("deepkey", "deepvalue"); + } + }, + function _delete(user, gen) { + const key = prng.oneOf(gen, ["one", "two"]); + user.getOrCreateMap("map").delete(key); + }, +]; + +test.skip("testRepeatGeneratingYmapTests10", (t) => { + applyRandomTests(t, gen, mapTransactions, 3); +}); + +test.skip("testRepeatGeneratingYmapTests40", (t) => { + applyRandomTests(t, gen, mapTransactions, 40); +}); + +test.skip("testRepeatGeneratingYmapTests42", (t) => { + applyRandomTests(t, gen, mapTransactions, 42); +}); + +test.skip("testRepeatGeneratingYmapTests43", (t) => { + applyRandomTests(t, gen, mapTransactions, 43); +}); + +test.skip("testRepeatGeneratingYmapTests44", (t) => { + applyRandomTests(t, gen, mapTransactions, 44); +}); + +test.skip("testRepeatGeneratingYmapTests45", (t) => { + applyRandomTests(t, gen, mapTransactions, 45); +}); + +test.skip("testRepeatGeneratingYmapTests46", (t) => { + applyRandomTests(t, gen, mapTransactions, 46); +}); + +test.skip("testRepeatGeneratingYmapTests300", (t) => { + applyRandomTests(t, gen, mapTransactions, 300); +}); + +test.skip("testRepeatGeneratingYmapTests400", (t) => { + applyRandomTests(t, gen, mapTransactions, 400); +}); + +test.skip("testRepeatGeneratingYmapTests500", (t) => { + applyRandomTests(t, gen, mapTransactions, 500); +}); + +test.skip("testRepeatGeneratingYmapTests600", (t) => { + applyRandomTests(t, gen, mapTransactions, 600); +}); + +test.skip("testRepeatGeneratingYmapTests1000", (t) => { + applyRandomTests(t, gen, mapTransactions, 1000); +}); + +test.skip("testRepeatGeneratingYmapTests1800", (t) => { + applyRandomTests(t, gen, mapTransactions, 1800); +}); + +test.skip("testRepeatGeneratingYmapTests5000", (t) => { + if (!production) return; + applyRandomTests(t, gen, mapTransactions, 5000); +}); + +test.skip("testRepeatGeneratingYmapTests10000", (t) => { + if (!production) return; + applyRandomTests(t, gen, mapTransactions, 10000); +}); + +test.skip("testRepeatGeneratingYmapTests100000", (t) => { + if (!production) return; + applyRandomTests(t, gen, mapTransactions, 100000); +}); diff --git a/y-octo-node/tests/yjs/y-text.spec.ts b/y-octo-node/tests/yjs/y-text.spec.ts new file mode 100644 index 0000000..a1e13de --- /dev/null +++ b/y-octo-node/tests/yjs/y-text.spec.ts @@ -0,0 +1,2605 @@ +import { randomInt } from "node:crypto"; +import test, { ExecutionContext } from "ava"; + +import * as prng from "lib0/prng"; +import * as math from "lib0/math"; + +import * as Y from "@y-octo/node"; +import { applyRandomTests, compare, init } from "./testHelper"; + +let gen: prng.PRNG; +test.beforeEach(() => { + gen = prng.create(randomInt(0, 0xffffffff)); +}); + +/** + * https://github.com/yjs/yjs/issues/474 + * @todo Remove debug: 127.0.0.1:8080/test.html?filter=\[88/ + */ +test.skip("testDeltaBug", (t) => { + const initialDelta = [ + { + attributes: { + "block-id": "block-28eea923-9cbb-4b6f-a950-cf7fd82bc087", + }, + insert: "\n", + }, + { + attributes: { + "table-col": { + width: "150", + }, + }, + insert: "\n\n\n", + }, + { + attributes: { + "block-id": "block-9144be72-e528-4f91-b0b2-82d20408e9ea", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-6kv2ls", + cell: "cell-apba4k", + }, + row: "row-6kv2ls", + cell: "cell-apba4k", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-639adacb-1516-43ed-b272-937c55669a1c", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-6kv2ls", + cell: "cell-a8qf0r", + }, + row: "row-6kv2ls", + cell: "cell-a8qf0r", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-6302ca4a-73a3-4c25-8c1e-b542f048f1c6", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-6kv2ls", + cell: "cell-oi9ikb", + }, + row: "row-6kv2ls", + cell: "cell-oi9ikb", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-ceeddd05-330e-4f86-8017-4a3a060c4627", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-d1sv2g", + cell: "cell-dt6ks2", + }, + row: "row-d1sv2g", + cell: "cell-dt6ks2", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-37b19322-cb57-4e6f-8fad-0d1401cae53f", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-d1sv2g", + cell: "cell-qah2ay", + }, + row: "row-d1sv2g", + cell: "cell-qah2ay", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-468a69b5-9332-450b-9107-381d593de249", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-d1sv2g", + cell: "cell-fpcz5a", + }, + row: "row-d1sv2g", + cell: "cell-fpcz5a", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-26b1d252-9b2e-4808-9b29-04e76696aa3c", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-pflz90", + cell: "cell-zrhylp", + }, + row: "row-pflz90", + cell: "cell-zrhylp", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-6af97ba7-8cf9-497a-9365-7075b938837b", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-pflz90", + cell: "cell-s1q9nt", + }, + row: "row-pflz90", + cell: "cell-s1q9nt", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-107e273e-86bc-44fd-b0d7-41ab55aca484", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-pflz90", + cell: "cell-20b0j9", + }, + row: "row-pflz90", + cell: "cell-20b0j9", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-38161f9c-6f6d-44c5-b086-54cc6490f1e3", + }, + insert: "\n", + }, + { + insert: "Content after table", + }, + { + attributes: { + "block-id": "block-15630542-ef45-412d-9415-88f0052238ce", + }, + insert: "\n", + }, + ]; + const ydoc1 = new Y.Doc(); + const ytext = ydoc1.createText(); + ytext.applyDelta(initialDelta); + const addingDash = [ + { + retain: 12, + }, + { + insert: "-", + }, + ]; + ytext.applyDelta(addingDash); + const addingSpace = [ + { + retain: 13, + }, + { + insert: " ", + }, + ]; + ytext.applyDelta(addingSpace); + const addingList = [ + { + retain: 12, + }, + { + delete: 2, + }, + { + retain: 1, + attributes: { + // Clear table line attribute + "table-cell-line": null, + // Add list attribute in place of table-cell-line + list: { + rowspan: "1", + colspan: "1", + row: "row-pflz90", + cell: "cell-20b0j9", + list: "bullet", + }, + }, + }, + ]; + ytext.applyDelta(addingList); + const result = ytext.toDelta(); + const expectedResult = [ + { + attributes: { + "block-id": "block-28eea923-9cbb-4b6f-a950-cf7fd82bc087", + }, + insert: "\n", + }, + { + attributes: { + "table-col": { + width: "150", + }, + }, + insert: "\n\n\n", + }, + { + attributes: { + "block-id": "block-9144be72-e528-4f91-b0b2-82d20408e9ea", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-6kv2ls", + cell: "cell-apba4k", + }, + row: "row-6kv2ls", + cell: "cell-apba4k", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-639adacb-1516-43ed-b272-937c55669a1c", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-6kv2ls", + cell: "cell-a8qf0r", + }, + row: "row-6kv2ls", + cell: "cell-a8qf0r", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-6302ca4a-73a3-4c25-8c1e-b542f048f1c6", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-6kv2ls", + cell: "cell-oi9ikb", + }, + row: "row-6kv2ls", + cell: "cell-oi9ikb", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-ceeddd05-330e-4f86-8017-4a3a060c4627", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-d1sv2g", + cell: "cell-dt6ks2", + }, + row: "row-d1sv2g", + cell: "cell-dt6ks2", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-37b19322-cb57-4e6f-8fad-0d1401cae53f", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-d1sv2g", + cell: "cell-qah2ay", + }, + row: "row-d1sv2g", + cell: "cell-qah2ay", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-468a69b5-9332-450b-9107-381d593de249", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-d1sv2g", + cell: "cell-fpcz5a", + }, + row: "row-d1sv2g", + cell: "cell-fpcz5a", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-26b1d252-9b2e-4808-9b29-04e76696aa3c", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-pflz90", + cell: "cell-zrhylp", + }, + row: "row-pflz90", + cell: "cell-zrhylp", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + attributes: { + "block-id": "block-6af97ba7-8cf9-497a-9365-7075b938837b", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-pflz90", + cell: "cell-s1q9nt", + }, + row: "row-pflz90", + cell: "cell-s1q9nt", + rowspan: "1", + colspan: "1", + }, + insert: "\n", + }, + { + insert: "\n", + // This attibutes has only list and no table-cell-line + attributes: { + list: { + rowspan: "1", + colspan: "1", + row: "row-pflz90", + cell: "cell-20b0j9", + list: "bullet", + }, + "block-id": "block-107e273e-86bc-44fd-b0d7-41ab55aca484", + row: "row-pflz90", + cell: "cell-20b0j9", + rowspan: "1", + colspan: "1", + }, + }, + // No table-cell-line below here + { + attributes: { + "block-id": "block-38161f9c-6f6d-44c5-b086-54cc6490f1e3", + }, + insert: "\n", + }, + { + insert: "Content after table", + }, + { + attributes: { + "block-id": "block-15630542-ef45-412d-9415-88f0052238ce", + }, + insert: "\n", + }, + ]; + t.deepEqual(result, expectedResult); +}); + +/** + * https://github.com/yjs/yjs/issues/503 + */ +test.skip("testDeltaBug2", (t) => { + const initialContent = [ + { insert: "Thomas' section" }, + { + insert: "\n", + attributes: { "block-id": "block-61ae80ac-a469-4eae-bac9-3b6a2c380118" }, + }, + { + insert: "\n", + attributes: { "block-id": "block-d265d93f-1cc7-40ee-bb58-8270fca2619f" }, + }, + { insert: "123" }, + { + insert: "\n", + attributes: { + "block-id": "block-592a7bee-76a3-4e28-9c25-7a84344f8813", + list: { list: "toggled", "toggle-id": "list-66xfft" }, + }, + }, + { insert: "456" }, + { + insert: "\n", + attributes: { + indent: 1, + "block-id": "block-3ee2bd70-b97f-45b2-9115-f1e8910235b1", + list: { list: "toggled", "toggle-id": "list-6vh0t0" }, + }, + }, + { insert: "789" }, + { + insert: "\n", + attributes: { + indent: 1, + "block-id": "block-78150cf3-9bb5-4dea-a6f5-0ce1d2a98b9c", + list: { list: "toggled", "toggle-id": "list-7jr0l2" }, + }, + }, + { insert: "901" }, + { + insert: "\n", + attributes: { + indent: 1, + "block-id": "block-13c6416f-f522-41d5-9fd4-ce4eb1cde5ba", + list: { list: "toggled", "toggle-id": "list-7uk8qu" }, + }, + }, + { + insert: { + slash_command: { + id: "doc_94zq-2436", + sessionId: "nkwc70p2j", + replace: "/", + }, + }, + }, + { + insert: "\n", + attributes: { "block-id": "block-8a1d2bb6-23c2-4bcf-af3c-3919ffea1697" }, + }, + { insert: "\n\n", attributes: { "table-col": { width: "150" } } }, + { + insert: "\n", + attributes: { "table-col": { width: "150" } }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-84ec3ea4-da6a-4e03-b430-0e5f432936a9", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-blmd4s", + cell: "cell-m0u5za", + }, + row: "row-blmd4s", + cell: "cell-m0u5za", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-83144ca8-aace-401e-8aa5-c05928a8ccf0", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-blmd4s", + cell: "cell-1v8s8t", + }, + row: "row-blmd4s", + cell: "cell-1v8s8t", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-9a493387-d27f-4b58-b2f7-731dfafda32a", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-blmd4s", + cell: "cell-126947", + }, + row: "row-blmd4s", + cell: "cell-126947", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-3484f86e-ae42-440f-8de6-857f0d8011ea", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-hmmljo", + cell: "cell-wvutl9", + }, + row: "row-hmmljo", + cell: "cell-wvutl9", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-d4e0b741-9dea-47a5-85e1-4ded0efbc89d", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-hmmljo", + cell: "cell-nkablr", + }, + row: "row-hmmljo", + cell: "cell-nkablr", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-352f0d5a-d1b9-422f-b136-4bacefd00b1a", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-hmmljo", + cell: "cell-n8xtd0", + }, + row: "row-hmmljo", + cell: "cell-n8xtd0", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-95823e57-f29c-44cf-a69d-2b4494b7144b", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-ev4xwq", + cell: "cell-ua9bvu", + }, + row: "row-ev4xwq", + cell: "cell-ua9bvu", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-cde5c027-15d3-4780-9e76-1e1a9d97a8e8", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-ev4xwq", + cell: "cell-7bwuvk", + }, + row: "row-ev4xwq", + cell: "cell-7bwuvk", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-11a23ed4-b04d-4e45-8065-8120889cd4a4", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-ev4xwq", + cell: "cell-aouka5", + }, + row: "row-ev4xwq", + cell: "cell-aouka5", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { "block-id": "block-15b4483c-da98-4ded-91d3-c3d6ebc82582" }, + }, + { insert: { divider: true } }, + { + insert: "\n", + attributes: { "block-id": "block-68552c8e-b57b-4f4a-9f36-6cc1ef6b3461" }, + }, + { insert: "jklasjdf" }, + { + insert: "\n", + attributes: { + "block-id": "block-c8b2df7d-8ec5-4dd4-81f1-8d8efc40b1b4", + list: { list: "toggled", "toggle-id": "list-9ss39s" }, + }, + }, + { insert: "asdf" }, + { + insert: "\n", + attributes: { + "block-id": "block-4f252ceb-14da-49ae-8cbd-69a701d18e2a", + list: { list: "toggled", "toggle-id": "list-uvo013" }, + }, + }, + { insert: "adg" }, + { + insert: "\n", + attributes: { + "block-id": "block-ccb9b72e-b94d-45a0-aae4-9b0a1961c533", + list: { list: "toggled", "toggle-id": "list-k53iwe" }, + }, + }, + { insert: "asdfasdfasdf" }, + { + insert: "\n", + attributes: { + "block-id": "block-ccb9b72e-b94d-45a0-aae4-9b0a1961c533", + list: { list: "none" }, + indent: 1, + }, + }, + { insert: "asdf" }, + { + insert: "\n", + attributes: { + "block-id": "block-f406f76d-f338-4261-abe7-5c9131f7f1ad", + list: { list: "toggled", "toggle-id": "list-en86ur" }, + }, + }, + { + insert: "\n", + attributes: { "block-id": "block-be18141c-9b6b-434e-8fd0-2c214437d560" }, + }, + { + insert: "\n", + attributes: { "block-id": "block-36922db3-4af5-48a1-9ea4-0788b3b5d7cf" }, + }, + { insert: { table_content: true } }, + { insert: " " }, + { + insert: { + slash_command: { + id: "doc_94zq-2436", + sessionId: "hiyrt6fny", + replace: "/", + }, + }, + }, + { + insert: "\n", + attributes: { "block-id": "block-9d6566a1-be55-4e20-999a-b990bc15e143" }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-4b545085-114d-4d07-844c-789710ec3aab", + layout: + "12d887e1-d1a2-4814-a1a3-0c904e950b46_1185cd29-ef1b-45d5-8fda-51a70b704e64", + "layout-width": "0.25", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-4d3f2321-33d1-470e-9b7c-d5a683570148", + layout: + "12d887e1-d1a2-4814-a1a3-0c904e950b46_75523ea3-c67f-4f5f-a85f-ac7c8fc0a992", + "layout-width": "0.5", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-4c7ae1e6-758e-470f-8d7c-ae0325e4ee8a", + layout: + "12d887e1-d1a2-4814-a1a3-0c904e950b46_54c740ef-fd7b-48c6-85aa-c14e1bfc9297", + "layout-width": "0.25", + }, + }, + { + insert: "\n", + attributes: { "block-id": "block-2d6ff0f4-ff00-42b7-a8e2-b816463d8fb5" }, + }, + { insert: { divider: true } }, + { + insert: "\n", + attributes: { "table-col": { width: "150" } }, + }, + { insert: "\n", attributes: { "table-col": { width: "154" } } }, + { + insert: "\n", + attributes: { "table-col": { width: "150" } }, + }, + + { + insert: "\n", + attributes: { + "block-id": "block-38545d56-224b-464c-b779-51fcec24dbbf", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-q0qfck", + cell: "cell-hmapv4", + }, + row: "row-q0qfck", + cell: "cell-hmapv4", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-d413a094-5f52-4fd4-a4aa-00774f6fdb44", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-q0qfck", + cell: "cell-c0czb2", + }, + row: "row-q0qfck", + cell: "cell-c0czb2", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-ff855cbc-8871-4e0a-9ba7-de0c1c2aa585", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-q0qfck", + cell: "cell-hcpqmm", + }, + row: "row-q0qfck", + cell: "cell-hcpqmm", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-4841e6ee-fef8-4473-bf04-f5ba62db17f0", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-etopyl", + cell: "cell-0io73v", + }, + row: "row-etopyl", + cell: "cell-0io73v", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-adeec631-d4fe-4f38-9d5e-e67ba068bd24", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-etopyl", + cell: "cell-gt2waa", + }, + row: "row-etopyl", + cell: "cell-gt2waa", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-d38a7308-c858-4ce0-b1f3-0f9092384961", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-etopyl", + cell: "cell-os9ksy", + }, + row: "row-etopyl", + cell: "cell-os9ksy", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-a9df6568-1838-40d1-9d16-3c073b6ce169", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-hbx9ri", + }, + row: "row-0jwjg3", + cell: "cell-hbx9ri", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-e26a0cf2-fe62-44a5-a4ca-8678a56d62f1", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-yg5m2w", + }, + row: "row-0jwjg3", + cell: "cell-yg5m2w", + rowspan: "1", + colspan: "1", + }, + }, + { insert: "a" }, + { + insert: "\n", + attributes: { + "block-id": "block-bfbc5ac2-7417-44b9-9aa5-8e36e4095627", + list: { + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + list: "ordered", + }, + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + }, + }, + { insert: "b" }, + { + insert: "\n", + attributes: { + "block-id": "block-f011c089-6389-47c0-8396-7477a29aa56f", + list: { + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + list: "ordered", + }, + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + }, + }, + { insert: "c" }, + { + insert: "\n", + attributes: { + "block-id": "block-4497788d-1e02-4fd5-a80a-48b61a6185cb", + list: { + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + list: "ordered", + }, + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + }, + }, + { insert: "d" }, + { + insert: "\n", + attributes: { + "block-id": "block-5d73a2c7-f98b-47c7-a3f5-0d8527962b02", + list: { + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + list: "ordered", + }, + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + }, + }, + { insert: "e" }, + { + insert: "\n", + attributes: { + "block-id": "block-bfda76ee-ffdd-45db-a22e-a6707e11cf68", + list: { + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + list: "ordered", + }, + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + }, + }, + { insert: "d" }, + { + insert: "\n", + attributes: { + "block-id": "block-35242e64-a69d-4cdb-bd85-2a93766bfab4", + list: { + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + list: "ordered", + }, + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + }, + }, + { insert: "f" }, + { + insert: "\n", + attributes: { + "block-id": "block-8baa22c8-491b-4f1b-9502-44179d5ae744", + list: { + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + list: "ordered", + }, + rowspan: "1", + colspan: "1", + row: "row-0jwjg3", + cell: "cell-1azhl2", + }, + }, + { + insert: "\n", + attributes: { "block-id": "block-7fa64af0-6974-4205-8cee-529f8bd46852" }, + }, + { insert: { divider: true } }, + { insert: "Brandon's Section" }, + { + insert: "\n", + attributes: { + header: 2, + "block-id": "block-cf49462c-2370-48ff-969d-576cb32c39a1", + }, + }, + { + insert: "\n", + attributes: { "block-id": "block-30ef8361-0dd6-4eee-b4eb-c9012d0e9070" }, + }, + { + insert: { + slash_command: { + id: "doc_94zq-2436", + sessionId: "x9x08o916", + replace: "/", + }, + }, + }, + { + insert: "\n", + attributes: { "block-id": "block-166ed856-cf8c-486a-9365-f499b21d91b3" }, + }, + { insert: { divider: true } }, + { + insert: "\n", + attributes: { + row: "row-kssn15", + rowspan: "1", + colspan: "1", + "block-id": "block-e8079594-4559-4259-98bb-da5280e2a692", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-kssn15", + cell: "cell-qxbksf", + }, + cell: "cell-qxbksf", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-70132663-14cc-4701-b5c5-eb99e875e2bd", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-kssn15", + cell: "cell-lsohbx", + }, + cell: "cell-lsohbx", + row: "row-kssn15", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-47a3899c-e3c5-4a7a-a8c4-46e0ae73a4fa", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-kssn15", + cell: "cell-hner9k", + }, + cell: "cell-hner9k", + row: "row-kssn15", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-0f9e650a-7841-412e-b4f2-5571b6d352c2", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-juxwc0", + cell: "cell-ei4yqp", + }, + cell: "cell-ei4yqp", + row: "row-juxwc0", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-53a158a9-8c82-4c82-9d4e-f5298257ca43", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-juxwc0", + cell: "cell-25pf5x", + }, + cell: "cell-25pf5x", + row: "row-juxwc0", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-da8ba35e-ce6e-4518-8605-c51d781eb07a", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-juxwc0", + cell: "cell-m8reor", + }, + cell: "cell-m8reor", + row: "row-juxwc0", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-2dce37c7-2978-4127-bed0-9549781babcb", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-ot4wy5", + cell: "cell-dinh0i", + }, + cell: "cell-dinh0i", + row: "row-ot4wy5", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-7b593f8c-4ea3-44b4-8ad9-4a0abffe759b", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-ot4wy5", + cell: "cell-d115b2", + }, + cell: "cell-d115b2", + row: "row-ot4wy5", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-272c28e6-2bde-4477-9d99-ce35b3045895", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-ot4wy5", + cell: "cell-fuapvo", + }, + cell: "cell-fuapvo", + row: "row-ot4wy5", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { "block-id": "block-fbf23cab-1ce9-4ede-9953-f2f8250004cf" }, + }, + { + insert: "\n", + attributes: { "block-id": "block-c3fbb8c9-495c-40b0-b0dd-f6e33dd64b1b" }, + }, + { + insert: "\n", + attributes: { "block-id": "block-3417ad09-92a3-4a43-b5db-6dbcb0f16db4" }, + }, + { + insert: "\n", + attributes: { "block-id": "block-b9eacdce-4ba3-4e66-8b69-3eace5656057" }, + }, + { insert: "Dan Gornstein" }, + { + insert: "\n", + attributes: { + "block-id": "block-d7c6ae0d-a17c-433e-85fd-5efc52b587fb", + header: 1, + }, + }, + { + insert: "\n", + attributes: { "block-id": "block-814521bd-0e14-4fbf-b332-799c6452a624" }, + }, + { insert: "aaa" }, + { + insert: "\n", + attributes: { + "block-id": "block-6aaf4dcf-dc21-45c6-b723-afb25fe0f498", + list: { list: "toggled", "toggle-id": "list-idl93b" }, + }, + }, + { insert: "bb" }, + { + insert: "\n", + attributes: { + indent: 1, + "block-id": "block-3dd75392-fa50-4bfb-ba6b-3b7d6bd3f1a1", + list: { list: "toggled", "toggle-id": "list-mrq7j2" }, + }, + }, + { insert: "ccc" }, + { + insert: "\n", + attributes: { + "block-id": "block-2528578b-ecda-4f74-9fd7-8741d72dc8b3", + indent: 2, + list: { list: "toggled", "toggle-id": "list-liu7dl" }, + }, + }, + { + insert: "\n", + attributes: { "block-id": "block-18bf68c3-9ef3-4874-929c-9b6bb1a00325" }, + }, + { + insert: "\n", + attributes: { "table-col": { width: "150" } }, + }, + { insert: "\n", attributes: { "table-col": { width: "150" } } }, + { + insert: "\n", + attributes: { "table-col": { width: "150" } }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-d44e74b4-b37f-48e0-b319-6327a6295a57", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-si1nah", + cell: "cell-cpybie", + }, + row: "row-si1nah", + cell: "cell-cpybie", + rowspan: "1", + colspan: "1", + }, + }, + { insert: "aaa" }, + { + insert: "\n", + attributes: { + "block-id": "block-3e545ee9-0c9a-42d7-a4d0-833edb8087f3", + list: { + rowspan: "1", + colspan: "1", + row: "row-si1nah", + cell: "cell-cpybie", + list: "toggled", + "toggle-id": "list-kjl2ik", + }, + rowspan: "1", + colspan: "1", + row: "row-si1nah", + cell: "cell-cpybie", + }, + }, + { insert: "bb" }, + { + insert: "\n", + attributes: { + indent: 1, + "block-id": "block-5f1225ad-370f-46ab-8f1e-18b277b5095f", + list: { + rowspan: "1", + colspan: "1", + row: "row-si1nah", + cell: "cell-cpybie", + list: "toggled", + "toggle-id": "list-eei1x5", + }, + rowspan: "1", + colspan: "1", + row: "row-si1nah", + cell: "cell-cpybie", + }, + }, + { insert: "ccc" }, + { + insert: "\n", + attributes: { + indent: 2, + "block-id": "block-a77fdc11-ad24-431b-9ca2-09e32db94ac2", + list: { + rowspan: "1", + colspan: "1", + row: "row-si1nah", + cell: "cell-cpybie", + list: "toggled", + "toggle-id": "list-30us3c", + }, + rowspan: "1", + colspan: "1", + row: "row-si1nah", + cell: "cell-cpybie", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-d44e74b4-b37f-48e0-b319-6327a6295a57", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-si1nah", + cell: "cell-cpybie", + }, + row: "row-si1nah", + cell: "cell-cpybie", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-2c274c8a-757d-4892-8db8-1a7999f7ab51", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-si1nah", + cell: "cell-al1z64", + }, + row: "row-si1nah", + cell: "cell-al1z64", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-85931afe-1879-471c-bb4b-89e7bd517fe9", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-si1nah", + cell: "cell-q186pb", + }, + row: "row-si1nah", + cell: "cell-q186pb", + rowspan: "1", + colspan: "1", + }, + }, + { insert: "asdfasdfasdf" }, + { + insert: "\n", + attributes: { + "block-id": "block-6e0522e8-c1eb-4c07-98df-2b07c533a139", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-7x2d1o", + cell: "cell-6eid2t", + }, + row: "row-7x2d1o", + cell: "cell-6eid2t", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-4b3d0bd0-9175-45e9-955c-e8164f4b5376", + row: "row-7x2d1o", + cell: "cell-m1alad", + rowspan: "1", + colspan: "1", + list: { + rowspan: "1", + colspan: "1", + row: "row-7x2d1o", + cell: "cell-m1alad", + list: "ordered", + }, + }, + }, + { insert: "asdfasdfasdf" }, + { + insert: "\n", + attributes: { + "block-id": "block-08610089-cb05-4366-bb1e-a0787d5b11bf", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-7x2d1o", + cell: "cell-dm1l2p", + }, + row: "row-7x2d1o", + cell: "cell-dm1l2p", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-c22b5125-8df3-432f-bd55-5ff456e41b4e", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-o0ujua", + cell: "cell-82g0ca", + }, + row: "row-o0ujua", + cell: "cell-82g0ca", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-7c6320e4-acaf-4ab4-8355-c9b00408c9c1", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-o0ujua", + cell: "cell-wv6ozp", + }, + row: "row-o0ujua", + cell: "cell-wv6ozp", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-d1bb7bed-e69e-4807-8d20-2d28fef8d08f", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-o0ujua", + cell: "cell-ldt53x", + }, + row: "row-o0ujua", + cell: "cell-ldt53x", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { "block-id": "block-28f28cb8-51a2-4156-acf9-2380e1349745" }, + }, + { insert: { divider: true } }, + { + insert: "\n", + attributes: { "block-id": "block-a1193252-c0c8-47fe-b9f6-32c8b01a1619" }, + }, + { insert: "\n", attributes: { "table-col": { width: "150" } } }, + { + insert: "\n\n", + attributes: { "table-col": { width: "150" } }, + }, + { insert: "/This is a test." }, + { + insert: "\n", + attributes: { + "block-id": "block-14188df0-a63f-4317-9a6d-91b96a7ac9fe", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-5ixdvv", + cell: "cell-9tgyed", + }, + row: "row-5ixdvv", + cell: "cell-9tgyed", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-7e5ba2af-9903-457d-adf4-2a79be81d823", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-5ixdvv", + cell: "cell-xc56e9", + }, + row: "row-5ixdvv", + cell: "cell-xc56e9", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-eb6cad93-caf7-4848-8adf-415255139268", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-5ixdvv", + cell: "cell-xrze3u", + }, + row: "row-5ixdvv", + cell: "cell-xrze3u", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-5bb547a2-6f71-4624-80c7-d0e1318c81a2", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-xbzv98", + cell: "cell-lie0ng", + }, + row: "row-xbzv98", + cell: "cell-lie0ng", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-b506de0d-efb6-4bd7-ba8e-2186cc57903e", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-xbzv98", + cell: "cell-s9sow1", + }, + row: "row-xbzv98", + cell: "cell-s9sow1", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-42d2ad20-5521-40e3-a88d-fe6906176e61", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-xbzv98", + cell: "cell-nodtcj", + }, + row: "row-xbzv98", + cell: "cell-nodtcj", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-7d3e4216-3f68-4dd6-bc77-4a9fad4ba008", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-5bqfil", + cell: "cell-c8c0f3", + }, + row: "row-5bqfil", + cell: "cell-c8c0f3", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-6671f221-551e-47fb-9b7d-9043b6b12cdc", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-5bqfil", + cell: "cell-jvxxif", + }, + row: "row-5bqfil", + cell: "cell-jvxxif", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { + "block-id": "block-51e3161b-0437-4fe3-ac4f-129a93a93fc3", + "table-cell-line": { + rowspan: "1", + colspan: "1", + row: "row-5bqfil", + cell: "cell-rmjpze", + }, + row: "row-5bqfil", + cell: "cell-rmjpze", + rowspan: "1", + colspan: "1", + }, + }, + { + insert: "\n", + attributes: { "block-id": "block-21099df0-afb2-4cd3-834d-bb37800eb06a" }, + }, + ]; + const ydoc = new Y.Doc(); + const ytext = ydoc.getOrCreateText("id"); + ytext.applyDelta(initialContent); + const changeEvent = [ + { retain: 90 }, + { delete: 4 }, + { + retain: 1, + attributes: { + layout: null, + "layout-width": null, + "block-id": "block-9d6566a1-be55-4e20-999a-b990bc15e143", + }, + }, + ]; + ytext.applyDelta(changeEvent); + const delta = ytext.toDelta(); + t.deepEqual(delta[41], { + insert: "\n", + attributes: { + "block-id": "block-9d6566a1-be55-4e20-999a-b990bc15e143", + }, + }); +}); + +/** + * In this test we are mainly interested in the cleanup behavior and whether the resulting delta makes sense. + * It is fine if the resulting delta is not minimal. But applying the delta to a rich-text editor should result in a + * synced document. + */ +test.skip("testDeltaAfterConcurrentFormatting", (t) => { + const { text0, text1, testConnector } = init(gen, { users: 2 }); + text0.insert(0, "abcde"); + testConnector.flushAllMessages(); + text0.format(0, 3, { bold: true }); + text1.format(2, 2, { bold: true }); + /** + * @type {any} + */ + const deltas: any = []; + text1.observe((event) => { + if (event.delta.length > 0) { + deltas.push(event.delta); + } + }); + testConnector.flushAllMessages(); + t.deepEqual(deltas, [ + [ + { retain: 3, attributes: { bold: true } }, + { retain: 2, attributes: { bold: null } }, + ], + ]); +}); + +test.skip("testBasicInsertAndDelete", (t) => { + const { users, text0 } = init(gen, { users: 2 }); + let delta; + + text0.observe((event) => { + delta = event.delta; + }); + + text0.delete(0, 0); + t.assert(true, "Does not throw when deleting zero elements with position 0"); + + text0.insert(0, "abc"); + t.assert(text0.toString() === "abc", "Basic insert works"); + t.deepEqual(delta, [{ insert: "abc" }]); + + text0.delete(0, 1); + t.assert(text0.toString() === "bc", "Basic delete works (position 0)"); + t.deepEqual(delta, [{ delete: 1 }]); + + text0.delete(1, 1); + t.assert(text0.toString() === "b", "Basic delete works (position 1)"); + t.deepEqual(delta, [{ retain: 1 }, { delete: 1 }]); + + users[0].transact(() => { + text0.insert(0, "1"); + text0.delete(0, 1); + }); + t.deepEqual(delta, []); + + compare(t, users); +}); + +test.skip("testBasicFormat", (t) => { + const { users, text0 } = init(gen, { users: 2 }); + let delta; + text0.observe((event) => { + delta = event.delta; + }); + text0.insert(0, "abc", { bold: true }); + t.assert(text0.toString() === "abc", "Basic insert with attributes works"); + t.deepEqual(text0.toDelta(), [{ insert: "abc", attributes: { bold: true } }]); + t.deepEqual(delta, [{ insert: "abc", attributes: { bold: true } }]); + text0.delete(0, 1); + t.assert( + text0.toString() === "bc", + "Basic delete on formatted works (position 0)", + ); + t.deepEqual(text0.toDelta(), [{ insert: "bc", attributes: { bold: true } }]); + t.deepEqual(delta, [{ delete: 1 }]); + text0.delete(1, 1); + t.assert(text0.toString() === "b", "Basic delete works (position 1)"); + t.deepEqual(text0.toDelta(), [{ insert: "b", attributes: { bold: true } }]); + t.deepEqual(delta, [{ retain: 1 }, { delete: 1 }]); + text0.insert(0, "z", { bold: true }); + t.assert(text0.toString() === "zb"); + t.deepEqual(text0.toDelta(), [{ insert: "zb", attributes: { bold: true } }]); + t.deepEqual(delta, [{ insert: "z", attributes: { bold: true } }]); + // @ts-ignore + t.assert( + text0._start.right.right.right.content.str === "b", + "Does not insert duplicate attribute marker", + ); + text0.insert(0, "y"); + t.assert(text0.toString() === "yzb"); + t.deepEqual(text0.toDelta(), [ + { insert: "y" }, + { insert: "zb", attributes: { bold: true } }, + ]); + t.deepEqual(delta, [{ insert: "y" }]); + text0.format(0, 2, { bold: null }); + t.assert(text0.toString() === "yzb"); + t.deepEqual(text0.toDelta(), [ + { insert: "yz" }, + { insert: "b", attributes: { bold: true } }, + ]); + t.deepEqual(delta, [ + { retain: 1 }, + { retain: 1, attributes: { bold: null } }, + ]); + compare(t, users); +}); + +test.skip("testFalsyFormats", (t) => { + const { users, text0 } = init(gen, { users: 2 }); + let delta; + text0.observe((event) => { + delta = event.delta; + }); + text0.insert(0, "abcde", { falsy: false }); + t.deepEqual(text0.toDelta(), [ + { insert: "abcde", attributes: { falsy: false } }, + ]); + t.deepEqual(delta, [{ insert: "abcde", attributes: { falsy: false } }]); + text0.format(1, 3, { falsy: true }); + t.deepEqual(text0.toDelta(), [ + { insert: "a", attributes: { falsy: false } }, + { insert: "bcd", attributes: { falsy: true } }, + { insert: "e", attributes: { falsy: false } }, + ]); + t.deepEqual(delta, [ + { retain: 1 }, + { retain: 3, attributes: { falsy: true } }, + ]); + text0.format(2, 1, { falsy: false }); + t.deepEqual(text0.toDelta(), [ + { insert: "a", attributes: { falsy: false } }, + { insert: "b", attributes: { falsy: true } }, + { insert: "c", attributes: { falsy: false } }, + { insert: "d", attributes: { falsy: true } }, + { insert: "e", attributes: { falsy: false } }, + ]); + t.deepEqual(delta, [ + { retain: 2 }, + { retain: 1, attributes: { falsy: false } }, + ]); + compare(t, users); +}); + +test.skip("testMultilineFormat", (t) => { + const ydoc = new Y.Doc(); + const testText = ydoc.getOrCreateText("test"); + testText.insert(0, "Test\nMulti-line\nFormatting"); + testText.applyDelta([ + { retain: 4, attributes: { bold: true } }, + { retain: 1 }, // newline character + { retain: 10, attributes: { bold: true } }, + { retain: 1 }, // newline character + { retain: 10, attributes: { bold: true } }, + ]); + t.deepEqual(testText.toDelta(), [ + { insert: "Test", attributes: { bold: true } }, + { insert: "\n" }, + { insert: "Multi-line", attributes: { bold: true } }, + { insert: "\n" }, + { insert: "Formatting", attributes: { bold: true } }, + ]); +}); + +test.skip("testNotMergeEmptyLinesFormat", (t) => { + const ydoc = new Y.Doc(); + const testText = ydoc.getOrCreateText("test"); + testText.applyDelta([ + { insert: "Text" }, + { insert: "\n", attributes: { title: true } }, + { insert: "\nText" }, + { insert: "\n", attributes: { title: true } }, + ]); + t.deepEqual(testText.toDelta(), [ + { insert: "Text" }, + { insert: "\n", attributes: { title: true } }, + { insert: "\nText" }, + { insert: "\n", attributes: { title: true } }, + ]); +}); + +test.skip("testPreserveAttributesThroughDelete", (t) => { + const ydoc = new Y.Doc(); + const testText = ydoc.getOrCreateText("test"); + testText.applyDelta([ + { insert: "Text" }, + { insert: "\n", attributes: { title: true } }, + { insert: "\n" }, + ]); + testText.applyDelta([ + { retain: 4 }, + { delete: 1 }, + { retain: 1, attributes: { title: true } }, + ]); + t.deepEqual(testText.toDelta(), [ + { insert: "Text" }, + { insert: "\n", attributes: { title: true } }, + ]); +}); + +test.skip("testGetDeltaWithEmbeds", (t) => { + const { text0 } = init(gen, { users: 1 }); + text0.applyDelta([ + { + insert: { linebreak: "s" }, + }, + ]); + t.deepEqual(text0.toDelta(), [ + { + insert: { linebreak: "s" }, + }, + ]); +}); + +test.skip("testTypesAsEmbed", (t) => { + const { text0, text1, testConnector } = init(gen, { users: 2 }); + text0.applyDelta([ + { + insert: new Y.Map([["key", "val"]]), + }, + ]); + t.deepEqual(text0.toDelta()[0].insert.toJSON(), { key: "val" }); + let firedEvent = false; + text1.observe((event) => { + const d = event.delta; + t.assert(d.length === 1); + t.deepEqual( + d.map((x) => /** @type {Y.AbstractType} */ x.insert.toJSON()), + [{ key: "val" }], + ); + firedEvent = true; + }); + testConnector.flushAllMessages(); + const delta = text1.toDelta(); + t.assert(delta.length === 1); + t.deepEqual(delta[0].insert.toJSON(), { key: "val" }); + t.assert(firedEvent, "fired the event observer containing a Type-Embed"); +}); + +test.skip("testSnapshot", (t) => { + const { text0 } = init(gen, { users: 1 }); + const doc0 = text0.doc; + doc0.gc = false; + text0.applyDelta([ + { + insert: "abcd", + }, + ]); + const snapshot1 = Y.snapshot(doc0); + text0.applyDelta([ + { + retain: 1, + }, + { + insert: "x", + }, + { + delete: 1, + }, + ]); + const snapshot2 = Y.snapshot(doc0); + text0.applyDelta([ + { + retain: 2, + }, + { + delete: 3, + }, + { + insert: "x", + }, + { + delete: 1, + }, + ]); + const state1 = text0.toDelta(snapshot1); + t.deepEqual(state1, [{ insert: "abcd" }]); + const state2 = text0.toDelta(snapshot2); + t.deepEqual(state2, [{ insert: "axcd" }]); + const state2Diff = text0.toDelta(snapshot2, snapshot1); + // @ts-ignore Remove userid info + state2Diff.forEach((v) => { + if (v.attributes && v.attributes.ychange) { + delete v.attributes.ychange.user; + } + }); + t.deepEqual(state2Diff, [ + { insert: "a" }, + { insert: "x", attributes: { ychange: { type: "added" } } }, + { insert: "b", attributes: { ychange: { type: "removed" } } }, + { insert: "cd" }, + ]); +}); + +test.skip("testSnapshotDeleteAfter", (t) => { + const { text0 } = init(gen, { users: 1 }); + const doc0 = text0.doc; + doc0.gc = false; + text0.applyDelta([ + { + insert: "abcd", + }, + ]); + const snapshot1 = Y.snapshot(doc0); + text0.applyDelta([ + { + retain: 4, + }, + { + insert: "e", + }, + ]); + const state1 = text0.toDelta(snapshot1); + t.deepEqual(state1, [{ insert: "abcd" }]); +}); + +test.skip("testToJson", (t) => { + const { text0 } = init(gen, { users: 1 }); + text0.insert(0, "abc", { bold: true }); + t.assert(text0.toJSON() === "abc", "toJSON returns the unformatted text"); +}); + +test.skip("testToDeltaEmbedAttributes", (t) => { + const { text0 } = init(gen, { users: 1 }); + text0.insert(0, "ab", { bold: true }); + text0.insertEmbed(1, { image: "imageSrc.png" }, { width: 100 }); + const delta0 = text0.toDelta(); + t.deepEqual(delta0, [ + { insert: "a", attributes: { bold: true } }, + { insert: { image: "imageSrc.png" }, attributes: { width: 100 } }, + { insert: "b", attributes: { bold: true } }, + ]); +}); + +test.skip("testToDeltaEmbedNoAttributes", (t) => { + const { text0 } = init(gen, { users: 1 }); + text0.insert(0, "ab", { bold: true }); + text0.insertEmbed(1, { image: "imageSrc.png" }); + const delta0 = text0.toDelta(); + t.deepEqual( + delta0, + [ + { insert: "a", attributes: { bold: true } }, + { insert: { image: "imageSrc.png" } }, + { insert: "b", attributes: { bold: true } }, + ], + "toDelta does not set attributes key when no attributes are present", + ); +}); + +test.skip("testFormattingRemoved", (t) => { + const { text0 } = init(gen, { users: 1 }); + text0.insert(0, "ab", { bold: true }); + text0.delete(0, 2); + t.assert(Y.getTypeChildren(text0).length === 1); +}); + +test.skip("testFormattingRemovedInMidText", (t) => { + const { text0 } = init(gen, { users: 1 }); + text0.insert(0, "1234"); + text0.insert(2, "ab", { bold: true }); + text0.delete(2, 2); + t.assert(Y.getTypeChildren(text0).length === 3); +}); + +/** + * Reported in https://github.com/yjs/yjs/issues/344 + */ +test.skip("testFormattingDeltaUnnecessaryAttributeChange", (t) => { + const { text0, text1, testConnector } = init(gen, { users: 2 }); + text0.insert(0, "\n", { + PARAGRAPH_STYLES: "normal", + LIST_STYLES: "bullet", + }); + text0.insert(1, "abc", { + PARAGRAPH_STYLES: "normal", + }); + testConnector.flushAllMessages(); + /** + * @type {Array} + */ + const deltas: Array = []; + text0.observe((event) => { + deltas.push(event.delta); + }); + text1.observe((event) => { + deltas.push(event.delta); + }); + text1.format(0, 1, { LIST_STYLES: "number" }); + testConnector.flushAllMessages(); + const filteredDeltas = deltas.filter((d) => d.length > 0); + t.assert(filteredDeltas.length === 2); + t.deepEqual(filteredDeltas[0], [ + { retain: 1, attributes: { LIST_STYLES: "number" } }, + ]); + t.deepEqual(filteredDeltas[0], filteredDeltas[1]); +}); + +test.skip("testInsertAndDeleteAtRandomPositions", (t) => { + const N = 100000; + const { text0 } = init(gen, { users: 1 }); + // create initial content + // let expectedResult = init + text0.insert(0, prng.word(gen, N / 2, N / 2)); + + // apply changes + for (let i = 0; i < N; i++) { + const pos = prng.uint32(gen, 0, text0.length); + if (prng.bool(gen)) { + const len = prng.uint32(gen, 1, 5); + const word = prng.word(gen, 0, len); + text0.insert(pos, word); + // expectedResult = expectedResult.slice(0, pos) + word + expectedResult.slice(pos) + } else { + const len = prng.uint32(gen, 0, math.min(3, text0.length - pos)); + text0.delete(pos, len); + // expectedResult = expectedResult.slice(0, pos) + expectedResult.slice(pos + len) + } + } + // t.deepEqual(text0.toString(), expectedResult) + t.describe("final length", "" + text0.length); +}); + +test.skip("testAppendChars", (t) => { + const N = 10000; + const { text0 } = init(gen, { users: 1 }); + // apply changes + for (let i = 0; i < N; i++) { + text0.insert(text0.length, "a"); + } + t.assert(text0.length === N); +}); + +const largeDocumentSize = 100000; + +// const id = Y.createID(0, 0); +// const c = new Y.ContentString("a"); + +test.skip("testBestCase", (t) => { + const N = largeDocumentSize; + const items = new Array(N); + t.measureTime("time to create two million items in the best case", () => { + const parent = /** @type {any} */ {}; + let prevItem = null; + for (let i = 0; i < N; i++) { + /** + * @type {Y.Item} + */ + const n: Y.Item = new Y.Item( + Y.createID(0, 0), + null, + null, + null, + null, + null, + null, + c, + ); + // items.push(n) + items[i] = n; + n.right = prevItem; + n.rightOrigin = prevItem ? id : null; + n.content = c; + n.parent = parent; + prevItem = n; + } + }); + const newArray = new Array(N); + t.measureTime("time to copy two million items to new Array", () => { + for (let i = 0; i < N; i++) { + newArray[i] = items[i]; + } + }); +}); + +const tryGc = () => { + // @ts-ignore + if (typeof global !== "undefined" && global.gc) { + // @ts-ignore + global.gc(); + } +}; + +test.skip("testLargeFragmentedDocument", (t) => { + const itemsToInsert = largeDocumentSize; + let update = /** @type {any} */ null; + (() => { + const doc1 = new Y.Doc(); + const text0 = doc1.getOrCreateText("txt"); + tryGc(); + t.measureTime(`time to insert ${itemsToInsert} items`, () => { + doc1.transact(() => { + for (let i = 0; i < itemsToInsert; i++) { + text0.insert(0, "0"); + } + }); + }); + tryGc(); + t.measureTime("time to encode document", () => { + update = Y.encodeStateAsUpdateV2(doc1); + }); + t.describe("Document size:", update.byteLength); + })(); + (() => { + const doc2 = new Y.Doc(); + tryGc(); + t.measureTime(`time to apply ${itemsToInsert} updates`, () => { + Y.applyUpdateV2(doc2, update); + }); + })(); +}); + +test.skip("testIncrementalUpdatesPerformanceOnLargeFragmentedDocument", (t) => { + const itemsToInsert = largeDocumentSize; + const updates = /** @type {Array} */ []; + (() => { + const doc1 = new Y.Doc(); + doc1.onUpdate((update) => { + updates.push(update); + }); + const text0 = doc1.getText("txt"); + tryGc(); + t.measureTime(`time to insert ${itemsToInsert} items`, () => { + doc1.transact(() => { + for (let i = 0; i < itemsToInsert; i++) { + text0.insert(0, "0"); + } + }); + }); + tryGc(); + })(); + (() => { + t.measureTime( + `time to merge ${itemsToInsert} updates (differential updates)`, + () => { + Y.mergeUpdates(updates); + }, + ); + tryGc(); + t.measureTime( + `time to merge ${itemsToInsert} updates (ydoc updates)`, + () => { + const ydoc = new Y.Doc(); + updates.forEach((update) => { + Y.applyUpdate(ydoc, update); + }); + }, + ); + })(); +}); + +/** + * Splitting surrogates can lead to invalid encoded documents. + * + * https://github.com/yjs/yjs/issues/248 + */ +test.skip("testSplitSurrogateCharacter", (t) => { + { + const { users, text0 } = init(gen, { users: 2 }); + users[1].disconnect(); // disconnecting forces the user to encode the split surrogate + text0.insert(0, "👾"); // insert surrogate character + // split surrogate, which should not lead to an encoding error + text0.insert(1, "hi!"); + compare(t, users); + } + { + const { users, text0 } = init(gen, { users: 2 }); + users[1].disconnect(); // disconnecting forces the user to encode the split surrogate + text0.insert(0, "👾👾"); // insert surrogate character + // partially delete surrogate + text0.delete(1, 2); + compare(t, users); + } + { + const { users, text0 } = init(gen, { users: 2 }); + users[1].disconnect(); // disconnecting forces the user to encode the split surrogate + text0.insert(0, "👾👾"); // insert surrogate character + // formatting will also split surrogates + text0.format(1, 2, { bold: true }); + compare(t, users); + } +}); + +/** + * Search marker bug https://github.com/yjs/yjs/issues/307 + */ +test.skip("testSearchMarkerBug1", (t) => { + const { users, text0, text1, testConnector } = init(gen, { users: 2 }); + users[0].onUpdate((update) => { + users[0].transact(() => { + Y.applyUpdate(users[0], update); + }); + }); + users[0].onUpdate((update) => { + users[1].transact(() => { + Y.applyUpdate(users[1], update); + }); + }); + + text0.insert(0, "a_a"); + testConnector.flushAllMessages(); + text0.insert(2, "s"); + testConnector.flushAllMessages(); + text1.insert(3, "d"); + testConnector.flushAllMessages(); + text0.delete(0, 5); + testConnector.flushAllMessages(); + text0.insert(0, "a_a"); + testConnector.flushAllMessages(); + text0.insert(2, "s"); + testConnector.flushAllMessages(); + text1.insert(3, "d"); + testConnector.flushAllMessages(); + t.deepEqual(text0.toString(), text1.toString()); + t.deepEqual(text0.toString(), "a_sda"); + compare(t, users); +}); + +/** + * Reported in https://github.com/yjs/yjs/pull/32 + */ +test.skip("testFormattingBug", (t) => { + const ydoc1 = new Y.Doc(); + const ydoc2 = new Y.Doc(); + const text1 = ydoc1.getText(); + text1.insert(0, "\n\n\n"); + text1.format(0, 3, { url: "http://example.com" }); + ydoc1.getText().format(1, 1, { url: "http://docs.yjs.dev" }); + ydoc2.getText().format(1, 1, { url: "http://docs.yjs.dev" }); + Y.applyUpdate(ydoc2, Y.encodeStateAsUpdate(ydoc1)); + const text2 = ydoc2.getText(); + const expectedResult = [ + { insert: "\n", attributes: { url: "http://example.com" } }, + { insert: "\n", attributes: { url: "http://docs.yjs.dev" } }, + { insert: "\n", attributes: { url: "http://example.com" } }, + ]; + t.deepEqual(text1.toDelta(), expectedResult); + t.deepEqual(text1.toDelta(), text2.toDelta()); + console.log(text1.toDelta()); +}); + +/** + * Delete formatting should not leave redundant formatting items. + * + * @param {t.TestCase} _tc + */ +test.skip("testDeleteFormatting", (t) => { + const doc = new Y.Doc(); + const text = doc.getText(); + text.insert(0, "Attack ships on fire off the shoulder of Orion."); + + const doc2 = new Y.Doc(); + const text2 = doc2.getText(); + Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc)); + + text.format(13, 7, { bold: true }); + Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc)); + + text.format(16, 4, { bold: null }); + Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc)); + + const expected = [ + { insert: "Attack ships " }, + { insert: "on ", attributes: { bold: true } }, + { insert: "fire off the shoulder of Orion." }, + ]; + t.deepEqual(text.toDelta(), expected); + t.deepEqual(text2.toDelta(), expected); +}); + +// RANDOM TESTS + +let charCounter = 0; + +/** + * Random tests for pure text operations without formatting. + * + * @type Array + */ +const textChanges: Array< + (t: ExecutionContext, arg0: any, arg1: prng.PRNG) => void +> = [ + (t, y, gen) => { + // insert text + const ytext = y.getOrCreateText("text"); + const insertPos = prng.int32(gen, 0, ytext.length); + const text = charCounter++ + prng.word(gen); + const prevText = ytext.toString(); + ytext.insert(insertPos, text); + t.deepEqual( + ytext.toString(), + prevText.slice(0, insertPos) + text + prevText.slice(insertPos), + ); + }, + (t, y, gen) => { + // delete text + const ytext = y.getOrCreateText("text"); + const contentLen = ytext.toString().length; + const insertPos = prng.int32(gen, 0, contentLen); + const overwrite = math.min(prng.int32(gen, 0, contentLen - insertPos), 2); + const prevText = ytext.toString(); + ytext.delete(insertPos, overwrite); + t.deepEqual( + ytext.toString(), + prevText.slice(0, insertPos) + prevText.slice(insertPos + overwrite), + ); + }, +]; + +test.skip("testRepeatGenerateTextChanges5", (t) => { + const { users } = checkResult(applyRandomTests(t, gen, textChanges, 5)); + const cleanups = Y.cleanupYTextFormatting(users[0].getText("text")); + t.assert(cleanups === 0); +}); + +test.skip("testRepeatGenerateTextChanges30", (t) => { + const { users } = checkResult(applyRandomTests(t, gen, textChanges, 30)); + const cleanups = Y.cleanupYTextFormatting(users[0].getText("text")); + t.assert(cleanups === 0); +}); + +test.skip("testRepeatGenerateTextChanges40", (t) => { + const { users } = checkResult(applyRandomTests(t, gen, textChanges, 40)); + const cleanups = Y.cleanupYTextFormatting(users[0].getText("text")); + t.assert(cleanups === 0); +}); + +test.skip("testRepeatGenerateTextChanges50", (t) => { + const { users } = checkResult(applyRandomTests(t, gen, textChanges, 50)); + const cleanups = Y.cleanupYTextFormatting(users[0].getText("text")); + t.assert(cleanups === 0); +}); + +test.skip("testRepeatGenerateTextChanges70", (t) => { + const { users } = checkResult(applyRandomTests(t, gen, textChanges, 70)); + const cleanups = Y.cleanupYTextFormatting(users[0].getText("text")); + t.assert(cleanups === 0); +}); + +test.skip("testRepeatGenerateTextChanges90", (t) => { + const { users } = checkResult(applyRandomTests(t, gen, textChanges, 90)); + const cleanups = Y.cleanupYTextFormatting(users[0].getText("text")); + t.assert(cleanups === 0); +}); + +test.skip("testRepeatGenerateTextChanges300", (t) => { + const { users } = checkResult(applyRandomTests(t, gen, textChanges, 300)); + const cleanups = Y.cleanupYTextFormatting(users[0].getText("text")); + t.assert(cleanups === 0); +}); + +const marks = [ + { bold: true }, + { italic: true }, + { italic: true, color: "#888" }, +]; + +const marksChoices = [undefined, ...marks]; + +/** + * Random tests for all features of y-text (formatting, embeds, ..). + * + * @type Array + */ +const qChanges: Array<(arg0: any, arg1: prng.PRNG) => void> = [ + /** + * @param {Y.Doc} y + * @param {prng.PRNG} gen + */ + (y: Y.Doc, gen: prng.PRNG) => { + // insert text + const ytext = y.getOrCreateText("text"); + const insertPos = prng.int32(gen, 0, ytext.length); + const attrs = prng.oneOf(gen, marksChoices); + const text = charCounter++ + prng.word(gen); + ytext.insert(insertPos, text, attrs); + }, + /** + * @param {Y.Doc} y + * @param {prng.PRNG} gen + */ + (y: Y.Doc, gen: prng.PRNG) => { + // insert embed + const ytext = y.getOrCreateText("text"); + const insertPos = prng.int32(gen, 0, ytext.length); + if (prng.bool(gen)) { + ytext.insertEmbed(insertPos, { + image: + "https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png", + }); + } else { + ytext.insertEmbed( + insertPos, + new Y.Map([[prng.word(gen), prng.word(gen)]]), + ); + } + }, + /** + * @param {Y.Doc} y + * @param {prng.PRNG} gen + */ + (y: Y.Doc, gen: prng.PRNG) => { + // delete text + const ytext = y.getOrCreateText("text"); + const contentLen = ytext.toString().length; + const insertPos = prng.int32(gen, 0, contentLen); + const overwrite = math.min(prng.int32(gen, 0, contentLen - insertPos), 2); + ytext.delete(insertPos, overwrite); + }, + /** + * @param {Y.Doc} y + * @param {prng.PRNG} gen + */ + (y: Y.Doc, gen: prng.PRNG) => { + // format text + const ytext = y.getOrCreateText("text"); + const contentLen = ytext.toString().length; + const insertPos = prng.int32(gen, 0, contentLen); + const overwrite = math.min(prng.int32(gen, 0, contentLen - insertPos), 2); + const format = prng.oneOf(gen, marks); + ytext.format(insertPos, overwrite, format); + }, + /** + * @param {Y.Doc} y + * @param {prng.PRNG} gen + */ + (y: Y.Doc, gen: prng.PRNG) => { + // insert codeblock + const ytext = y.getOrCreateText("text"); + const insertPos = prng.int32(gen, 0, ytext.toString().length); + const text = charCounter++ + prng.word(gen); + const ops = []; + if (insertPos > 0) { + ops.push({ retain: insertPos }); + } + ops.push( + { insert: text }, + { insert: "\n", format: { "code-block": true } }, + ); + ytext.applyDelta(ops); + }, + /** + * @param {Y.Doc} y + * @param {prng.PRNG} gen + */ + (y: Y.Doc, gen: prng.PRNG) => { + // complex delta op + const ytext = y.getOrCreateText("text"); + const contentLen = ytext.toString().length; + let currentPos = math.max(0, prng.int32(gen, 0, contentLen - 1)); + /** + * @type {Array} + */ + const ops: Array = currentPos > 0 ? [{ retain: currentPos }] : []; + // create max 3 ops + for (let i = 0; i < 7 && currentPos < contentLen; i++) { + prng.oneOf(gen, [ + () => { + // format + const retain = math.min( + prng.int32(gen, 0, contentLen - currentPos), + 5, + ); + const format = prng.oneOf(gen, marks); + ops.push({ retain, attributes: format }); + currentPos += retain; + }, + () => { + // insert + const attrs = prng.oneOf(gen, marksChoices); + const text = prng.word(gen, 1, 3); + ops.push({ insert: text, attributes: attrs }); + }, + () => { + // delete + const delLen = math.min( + prng.int32(gen, 0, contentLen - currentPos), + 10, + ); + ops.push({ delete: delLen }); + currentPos += delLen; + }, + ])(); + } + ytext.applyDelta(ops); + }, +]; + +const checkResult = (result: any) => { + for (let i = 1; i < result.testObjects.length; i++) { + /** + * @param {any} d + */ + const typeToObject = (d: any) => + Y.isAbstractType(d.insert) ? d.insert.toJSON() : d; + const p1 = result.users[i].getText("text").toDelta().map(typeToObject); + const p2 = result.users[i].getText("text").toDelta().map(typeToObject); + t.deepEqual(p1, p2); + } + // Uncomment this to find formatting-cleanup issues + // const cleanups = Y.cleanupYTextFormatting(result.users[0].getText('text')) + // t.assert(cleanups === 0) + return result; +}; + +test.skip("testRepeatGenerateQuillChanges1", (t) => { + const { users } = checkResult(applyRandomTests(t, gen, qChanges, 1)); + const cleanups = Y.cleanupYTextFormatting(users[0].getText("text")); + t.assert(cleanups === 0); +}); + +test.skip("testRepeatGenerateQuillChanges2", (t) => { + const { users } = checkResult(applyRandomTests(t, gen, qChanges, 2)); + const cleanups = Y.cleanupYTextFormatting(users[0].getText("text")); + t.assert(cleanups === 0); +}); + +test.skip("testRepeatGenerateQuillChanges2Repeat", (t) => { + for (let i = 0; i < 1000; i++) { + const { users } = checkResult(applyRandomTests(t, gen, qChanges, 2)); + const cleanups = Y.cleanupYTextFormatting(users[0].getText("text")); + t.assert(cleanups === 0); + } +}); + +test.skip("testRepeatGenerateQuillChanges3", (t) => { + checkResult(applyRandomTests(t, gen, qChanges, 3)); +}); + +test.skip("testRepeatGenerateQuillChanges30", (t) => { + checkResult(applyRandomTests(t, gen, qChanges, 30)); +}); + +test.skip("testRepeatGenerateQuillChanges40", (t) => { + checkResult(applyRandomTests(t, gen, qChanges, 40)); +}); + +test.skip("testRepeatGenerateQuillChanges70", (t) => { + checkResult(applyRandomTests(t, gen, qChanges, 70)); +}); + +test.skip("testRepeatGenerateQuillChanges100", (t) => { + checkResult(applyRandomTests(t, gen, qChanges, 100)); +}); + +test.skip("testRepeatGenerateQuillChanges300", (t) => { + checkResult(applyRandomTests(t, gen, qChanges, 300)); +}); diff --git a/y-octo-node/tsconfig.json b/y-octo-node/tsconfig.json index dd11afc..9560070 100644 --- a/y-octo-node/tsconfig.json +++ b/y-octo-node/tsconfig.json @@ -2,10 +2,10 @@ "extends": "../tsconfig.json", "compilerOptions": { "noEmit": false, - "outDir": "lib", + "outDir": "dist", "composite": true }, - "include": ["index.d.ts", "tests/**/*.mts"], + "include": ["src/**/*.(tsx?)", "tests/**/*.(mts|ts)"], "ts-node": { "esm": true, "experimentalSpecifierResolution": "node" diff --git a/y-octo/Cargo.toml b/y-octo/Cargo.toml index eb4284e..eb52e7f 100644 --- a/y-octo/Cargo.toml +++ b/y-octo/Cargo.toml @@ -38,8 +38,10 @@ thiserror = "1.0" [features] bench = [] debug = [] +default = ["subscribe"] large_refs = [] serde_json = [] +subscribe = [] [target.'cfg(fuzzing)'.dependencies] arbitrary = { version = "1.3", features = ["derive"] } diff --git a/y-octo/src/doc/awareness.rs b/y-octo/src/doc/awareness.rs index fcbb75a..bd44b87 100644 --- a/y-octo/src/doc/awareness.rs +++ b/y-octo/src/doc/awareness.rs @@ -20,6 +20,10 @@ impl Awareness { } } + pub fn local_id(&self) -> u64 { + self.local_id + } + pub fn on_update(&mut self, f: impl Fn(&Awareness, AwarenessEvent) + Send + Sync + 'static) { self.callback = Some(Arc::new(f)); } @@ -210,7 +214,7 @@ mod tests { let values: MutexGuard> = values.lock().unwrap(); assert_eq!(values.len(), 4); - let event = values.get(0).unwrap(); + let event = values.first().unwrap(); let mut added = event.added.clone(); added.sort(); diff --git a/y-octo/src/doc/batch.rs b/y-octo/src/doc/batch.rs new file mode 100644 index 0000000..63c9639 --- /dev/null +++ b/y-octo/src/doc/batch.rs @@ -0,0 +1,122 @@ +use super::*; + +#[derive(Debug, PartialEq)] +pub struct Batch { + doc: Doc, + before_state: StateVector, + after_state: StateVector, + changed: HashMap>, +} + +impl Batch { + pub fn new(doc: Doc) -> Self { + let current_state = doc.get_state_vector(); + + Batch { + doc, + before_state: current_state.clone(), + after_state: current_state, + changed: HashMap::new(), + } + } + + pub fn with_batch(&mut self, f: F) -> T + where + F: FnOnce(Doc) -> T, + { + let ret = f(self.doc.clone()); + for (k, v) in self.doc.get_changed() { + self.changed.entry(k).or_insert_with(Vec::new).extend(v.iter().cloned()); + } + ret + } +} + +pub fn batch_commit(mut doc: Doc, f: F) -> Option +where + F: FnOnce(Doc) -> T, +{ + // Initialize batch cleanups list + let mut batch_cleanups = vec![]; + + // Initial call and result initialization + let mut initial_call = false; + + { + if doc.batch.is_none() { + initial_call = true; + + // Start a new batch + let batch = Batch::new(doc.clone()); + doc.batch = Somr::new(batch); + batch_cleanups.push(doc.batch.clone()); + } + } + + let Some(batch) = doc.batch.get_mut() else { + return None; + }; + + let result = Some(batch.with_batch(f)); + + if initial_call { + if let Some(current_batch) = doc.batch.get() { + if Some(current_batch) == batch_cleanups[0].get() { + // Process observer calls and perform cleanup if this is the initial call + cleanup_batches(&mut batch_cleanups); + doc.batch.swap_take(); + } + } + } + + result +} + +fn cleanup_batches(batch_cleanups: &mut Vec>) { + for batch in batch_cleanups.drain(..) { + if let Some(batch) = batch.get() { + println!("changed: {:?}", batch.changed); + } else { + panic!("Batch not initialized"); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_get_changed_items() { + // loom_model!({ + let doc = DocOptions::new().with_client_id(1).build(); + + batch_commit(doc.clone(), |d| { + let mut arr = d.get_or_create_array("arr").unwrap(); + let mut text = d.create_text().unwrap(); + let mut map = d.create_map().unwrap(); + + batch_commit(doc.clone(), |_| { + arr.insert(0, Value::from(text.clone())).unwrap(); + arr.insert(1, Value::from(map.clone())).unwrap(); + }); + + batch_commit(doc.clone(), |_| { + text.insert(0, "hello world").unwrap(); + text.remove(5, 6).unwrap(); + }); + + batch_commit(doc.clone(), |_| { + map.insert("key".into(), 123).unwrap(); + }); + + batch_commit(doc.clone(), |_| { + map.remove("key"); + }); + + batch_commit(doc.clone(), |_| { + arr.remove(0, 1).unwrap(); + }); + }); + } +} diff --git a/y-octo/src/doc/codec/item.rs b/y-octo/src/doc/codec/item.rs index ce0d31c..91c6171 100644 --- a/y-octo/src/doc/codec/item.rs +++ b/y-octo/src/doc/codec/item.rs @@ -343,6 +343,22 @@ impl Item { Ok(()) } + + pub fn deep_compare(&self, other: &Self) -> bool { + if self.id != other.id + || self.deleted() != other.deleted() + || self.len() != other.len() + || self.left.get().map(|l| l.last_id()) != other.left.get().map(|l| l.last_id()) + || self.right.get().map(|r| r.id) != other.right.get().map(|r| r.id) + || self.origin_left_id != other.origin_left_id + || self.origin_right_id != other.origin_right_id + || self.parent_sub != other.parent_sub + { + return false; + } + + true + } } #[allow(dead_code)] diff --git a/y-octo/src/doc/codec/item_flag.rs b/y-octo/src/doc/codec/item_flag.rs index f019b7e..f90bf41 100644 --- a/y-octo/src/doc/codec/item_flag.rs +++ b/y-octo/src/doc/codec/item_flag.rs @@ -110,11 +110,11 @@ mod tests { fn test_flag_set_and_clear() { { let flag = super::ItemFlag::default(); - assert_eq!(flag.keep(), false); + assert!(!flag.keep()); flag.set_keep(); - assert_eq!(flag.keep(), true); + assert!(flag.keep()); flag.clear_keep(); - assert_eq!(flag.keep(), false); + assert!(!flag.keep()); assert_eq!( flag.0.load(Ordering::SeqCst), ItemFlag::default().0.load(Ordering::SeqCst) @@ -123,11 +123,11 @@ mod tests { { let flag = super::ItemFlag::default(); - assert_eq!(flag.countable(), false); + assert!(!flag.countable()); flag.set_countable(); - assert_eq!(flag.countable(), true); + assert!(flag.countable()); flag.clear_countable(); - assert_eq!(flag.countable(), false); + assert!(!flag.countable()); assert_eq!( flag.0.load(Ordering::SeqCst), ItemFlag::default().0.load(Ordering::SeqCst) @@ -136,11 +136,11 @@ mod tests { { let flag = super::ItemFlag::default(); - assert_eq!(flag.deleted(), false); + assert!(!flag.deleted()); flag.set_deleted(); - assert_eq!(flag.deleted(), true); + assert!(flag.deleted()); flag.clear_deleted(); - assert_eq!(flag.deleted(), false); + assert!(!flag.deleted()); assert_eq!( flag.0.load(Ordering::SeqCst), ItemFlag::default().0.load(Ordering::SeqCst) @@ -152,15 +152,15 @@ mod tests { flag.set_keep(); flag.set_countable(); flag.set_deleted(); - assert_eq!(flag.keep(), true); - assert_eq!(flag.countable(), true); - assert_eq!(flag.deleted(), true); + assert!(flag.keep()); + assert!(flag.countable()); + assert!(flag.deleted()); flag.clear_keep(); flag.clear_countable(); flag.clear_deleted(); - assert_eq!(flag.keep(), false); - assert_eq!(flag.countable(), false); - assert_eq!(flag.deleted(), false); + assert!(!flag.keep()); + assert!(!flag.countable()); + assert!(!flag.deleted()); assert_eq!( flag.0.load(Ordering::SeqCst), ItemFlag::default().0.load(Ordering::SeqCst) diff --git a/y-octo/src/doc/document.rs b/y-octo/src/doc/document.rs index 8acad3f..0513240 100644 --- a/y-octo/src/doc/document.rs +++ b/y-octo/src/doc/document.rs @@ -1,4 +1,11 @@ -use super::{history::StoreHistory, publisher::DocPublisher, store::StoreRef, *}; +use std::collections::HashMap; + +use super::{ + history::StoreHistory, + publisher::DocPublisher, + store::{ChangedTypeRefs, StoreRef}, + *, +}; use crate::sync::{Arc, RwLock}; #[cfg(feature = "debug")] @@ -40,24 +47,6 @@ impl Default for DocOptions { gc: true, } } else { - /// It tends to generate small numbers. - /// Since the client id will be included in all crdt items, the - /// small client helps to reduce the binary size. - /// - /// NOTE: The probability of 36% of the random number generated by - /// this function is greater than [u32::MAX] - fn prefer_small_random() -> u64 { - use rand::{distributions::Distribution, thread_rng}; - use rand_distr::Exp; - - let scale_factor = u16::MAX as f64; - let v: f64 = Exp::new(1.0 / scale_factor) - .map(|exp| exp.sample(&mut thread_rng())) - .unwrap_or_else(|_| rand::random()); - - (v * scale_factor) as u64 - } - Self { client_id: prefer_small_random(), guid: nanoid::nanoid!(), @@ -134,6 +123,7 @@ pub struct Doc { pub(crate) store: StoreRef, pub publisher: Arc, + pub(crate) batch: Somr, } unsafe impl Send for Doc {} @@ -165,6 +155,7 @@ impl Doc { opts: options, store, publisher, + batch: Somr::none(), } } @@ -176,6 +167,14 @@ impl Doc { self.client_id } + pub fn set_client(&mut self, client_id: u64) { + self.client_id = client_id; + } + + pub fn renew_client(&mut self) { + self.client_id = prefer_small_random(); + } + pub fn clients(&self) -> Vec { self.store.read().unwrap().clients() } @@ -199,6 +198,17 @@ impl Doc { } } + pub fn get_changed(&self) -> ChangedTypeRefs { + self.store.write().unwrap().get_changed() + } + + pub fn store_compare(&self, other: &Doc) -> bool { + let store = self.store.read().unwrap(); + let other_store = other.store.read().unwrap(); + + store.deep_compare(&other_store) + } + pub fn options(&self) -> &DocOptions { &self.opts } @@ -361,6 +371,10 @@ impl Doc { self.store.read().unwrap().get_state_vector() } + pub fn get_delete_sets(&self) -> DeleteSet { + self.store.read().unwrap().get_delete_sets() + } + pub fn subscribe(&self, cb: impl Fn(&[u8], &[History]) + Sync + Send + 'static) { self.publisher.subscribe(cb); } @@ -373,6 +387,10 @@ impl Doc { self.publisher.count() } + pub fn subscriber_count(&self) -> usize { + Arc::::strong_count(&self.publisher) + } + pub fn gc(&self) -> JwstCodecResult<()> { self.store.write().unwrap().optimize() } diff --git a/y-octo/src/doc/mod.rs b/y-octo/src/doc/mod.rs index 608f654..371813b 100644 --- a/y-octo/src/doc/mod.rs +++ b/y-octo/src/doc/mod.rs @@ -1,4 +1,5 @@ mod awareness; +mod batch; mod codec; mod common; mod document; @@ -11,6 +12,7 @@ mod utils; pub use ahash::{HashMap, HashMapExt, HashSet, HashSetExt}; pub use awareness::{Awareness, AwarenessEvent}; +pub use batch::{batch_commit, Batch}; pub use codec::*; pub use common::*; pub use document::{Doc, DocOptions}; diff --git a/y-octo/src/doc/publisher.rs b/y-octo/src/doc/publisher.rs index ff7eba5..b3755eb 100644 --- a/y-octo/src/doc/publisher.rs +++ b/y-octo/src/doc/publisher.rs @@ -34,7 +34,10 @@ impl DocPublisher { observing: Arc::new(AtomicBool::new(false)), }; - if cfg!(not(any(feature = "bench", fuzzing, loom, miri))) { + if cfg!(all( + feature = "subscribe", + not(any(feature = "bench", fuzzing, loom, miri)) + )) { publisher.start(); } @@ -175,7 +178,7 @@ mod tests { loom_model!({ let doc = Doc::default(); - let ret = vec![ + let ret = [ vec![vec!["(1, 0)", "test.key1", "val1"]], vec![vec!["(1, 1)", "test.key2", "val2"], vec!["(1, 2)", "test.key3", "val3"]], vec![ diff --git a/y-octo/src/doc/store.rs b/y-octo/src/doc/store.rs index d13eaea..cd85004 100644 --- a/y-octo/src/doc/store.rs +++ b/y-octo/src/doc/store.rs @@ -10,6 +10,8 @@ use crate::{ sync::{Arc, RwLock, RwLockWriteGuard, Weak}, }; +pub type ChangedTypeRefs = HashMap>; + unsafe impl Send for DocStore {} unsafe impl Sync for DocStore {} @@ -26,6 +28,8 @@ pub(crate) struct DocStore { pub dangling_types: HashMap, pub pending: Option, pub last_optimized_state: StateVector, + // changed item's parent, value is the parent's sub key if exists + pub changed: ChangedTypeRefs, } pub(crate) type StoreRef = Arc>; @@ -101,6 +105,10 @@ impl DocStore { Self::items_as_state_vector(&self.items) } + pub fn get_delete_sets(&self) -> DeleteSet { + self.delete_set.clone() + } + fn items_as_state_vector(items: &ClientMap>) -> StateVector { let mut state = StateVector::default(); for (client, structs) in items.iter() { @@ -579,6 +587,9 @@ impl DocStore { } parent_lock.take(); + + // mark changed item's parent + Self::mark_changed(&mut self.changed, ty.clone(), this.parent_sub.clone()); } else { // if parent not exists, integrate GC node instead // don't delete it because it may referenced by other nodes @@ -601,13 +612,18 @@ impl DocStore { pub fn delete_item(&mut self, item: &Item, parent: Option<&mut YType>) { let mut pending_delete_sets = HashMap::new(); - Self::delete_item_inner(&mut pending_delete_sets, item, parent); + Self::delete_item_inner(&mut pending_delete_sets, &mut self.changed, item, parent); for (client, ranges) in pending_delete_sets { self.delete_set.batch_add_ranges(client, ranges); } } - fn delete_item_inner(delete_set: &mut HashMap>>, item: &Item, parent: Option<&mut YType>) { + fn delete_item_inner( + delete_set: &mut HashMap>>, + changed: &mut ChangedTypeRefs, + item: &Item, + parent: Option<&mut YType>, + ) { // 1. mark item as deleted, if item is gced, return if !item.delete() { return; @@ -639,7 +655,7 @@ impl DocStore { let mut item_ref = ty.start.clone(); while let Some(item) = item_ref.get() { if !item.deleted() { - Self::delete_item_inner(delete_set, item, Some(&mut ty)); + Self::delete_item_inner(delete_set, changed, item, Some(&mut ty)); } item_ref = item.right.clone(); @@ -649,7 +665,7 @@ impl DocStore { for item in map_values { if let Some(item) = item.get() { if !item.deleted() { - Self::delete_item_inner(delete_set, item, Some(&mut ty)); + Self::delete_item_inner(delete_set, changed, item, Some(&mut ty)); } } } @@ -660,6 +676,11 @@ impl DocStore { } _ => {} } + + // mark deleted item's parent + if let Some(Parent::Type(ty)) = &item.parent { + Self::mark_changed(changed, ty.clone(), item.parent_sub.clone()); + } } pub fn delete_node(&mut self, struct_info: &Node, parent: Option<&mut YType>) { @@ -703,7 +724,7 @@ impl DocStore { DocStore::split_node_at(items, idx, end - id.clock)?; } - Self::delete_item_inner(&mut pending_delete_sets, item, None); + Self::delete_item_inner(&mut pending_delete_sets, &mut self.changed, item, None); } } } else { @@ -758,6 +779,24 @@ impl DocStore { Ok(update) } + fn mark_changed(changed: &mut ChangedTypeRefs, parent: YTypeRef, parent_sub: Option) { + if parent.inner.is_some() { + let vec = changed.entry(parent).or_insert_with(Vec::new); + if let Some(parent_sub) = parent_sub { + // only record the sub key if exists + vec.push(parent_sub); + } + } + } + + pub fn reset_changed(&mut self) { + self.changed.clear(); + } + + pub fn get_changed(&mut self) -> ChangedTypeRefs { + mem::replace(&mut self.changed, HashMap::new()) + } + fn diff_structs(map: &ClientMap>, sv: &StateVector) -> JwstCodecResult>> { let local_state_vector = Self::items_as_state_vector(map); let diff = Self::diff_state_vectors(&local_state_vector, sv); @@ -937,6 +976,39 @@ impl DocStore { // return the index of processed items idx - pos } + + pub fn deep_compare(&self, other: &Self) -> bool { + if self.items.len() != other.items.len() { + return false; + } + + for (client, structs) in self.items.iter() { + if let Some(other_structs) = other.items.get(client) { + if structs.len() != other_structs.len() { + return false; + } + + for (struct_info, other_struct_info) in structs.iter().zip(other_structs.iter()) { + if struct_info != other_struct_info { + return false; + } + if let (Node::Item(item), Node::Item(other_item)) = (struct_info, other_struct_info) { + if !match (item.get(), other_item.get()) { + (Some(item), Some(other_item)) => item.deep_compare(other_item), + (None, None) => true, + _ => false, + } { + return false; + } + } + } + } else { + return false; + } + } + + true + } } #[cfg(test)] @@ -1124,6 +1196,58 @@ mod tests { }); } + #[test] + fn should_mark_changed_items() { + loom_model!({ + let doc = DocOptions::new().with_client_id(1).build(); + + let mut arr = doc.get_or_create_array("arr").unwrap(); + let mut text = doc.create_text().unwrap(); + let mut map = doc.create_map().unwrap(); + + arr.insert(0, Value::from(text.clone())).unwrap(); + arr.insert(1, Value::from(map.clone())).unwrap(); + { + let changed = doc.store.write().unwrap().get_changed(); + // for array, we will only record the type ref itself + assert_eq!(changed.len(), 1); + assert_eq!(changed.get(&arr.0), Some(&vec![])); + } + + text.insert(0, "hello world").unwrap(); + text.remove(5, 6).unwrap(); + { + let changed = doc.store.write().unwrap().get_changed(); + assert_eq!(changed.len(), 1); + assert_eq!(changed.get(&text.0), Some(&vec![])); + } + + map.insert("key".into(), 123).unwrap(); + { + let changed = doc.store.write().unwrap().get_changed(); + assert_eq!(changed.len(), 1); + assert_eq!(changed.get(&map.0), Some(&vec!["key".into()])); + } + + map.remove("key"); + { + let changed = doc.store.write().unwrap().get_changed(); + assert_eq!(changed.len(), 1); + assert_eq!(changed.get(&map.0), Some(&vec!["key".into()])); + } + + arr.remove(0, 1).unwrap(); + { + let changed = doc.store.write().unwrap().get_changed(); + assert_eq!(changed.len(), 2); + // text's children mark parent(text) changed + assert_eq!(changed.get(&text.0), Some(&vec![])); + // text mark parent(arr) changed + assert_eq!(changed.get(&arr.0), Some(&vec![])); + } + }); + } + #[test] fn should_replace_gc_item_with_content_deleted() { loom_model!({ diff --git a/y-octo/src/doc/types/array.rs b/y-octo/src/doc/types/array.rs index 04b8390..5300b21 100644 --- a/y-octo/src/doc/types/array.rs +++ b/y-octo/src/doc/types/array.rs @@ -23,6 +23,11 @@ impl Iterator for ArrayIter<'_> { } impl Array { + #[inline(always)] + pub fn id(&self) -> Option { + self._id() + } + #[inline] pub fn len(&self) -> u64 { self.content_len() @@ -102,6 +107,23 @@ mod tests { }); } + #[test] + fn test_yarray_delete() { + let options = DocOptions::default(); + + loom_model!({ + let doc = Doc::with_options(options.clone()); + let mut array = doc.get_or_create_array("abc").unwrap(); + + array.insert(0, " ").unwrap(); + array.insert(0, "Hello").unwrap(); + array.insert(2, "World").unwrap(); + array.remove(0, 2).unwrap(); + + assert_eq!(array.get(0).unwrap(), Value::Any(Any::String("World".into()))); + }); + } + #[test] #[cfg_attr(miri, ignore)] fn test_ytext_equal() { diff --git a/y-octo/src/doc/types/list/mod.rs b/y-octo/src/doc/types/list/mod.rs index 864fa3d..9352e83 100644 --- a/y-octo/src/doc/types/list/mod.rs +++ b/y-octo/src/doc/types/list/mod.rs @@ -6,6 +6,7 @@ pub(crate) use search_marker::MarkerList; use super::*; +#[derive(Debug)] pub(crate) struct ItemPosition { pub parent: YTypeRef, pub left: ItemRef, @@ -55,6 +56,11 @@ impl ItemPosition { } pub(crate) trait ListType: AsInner { + #[inline(always)] + fn _id(&self) -> Option { + self.as_inner().ty().and_then(|ty| ty.item.get().map(|item| item.id)) + } + #[inline(always)] fn content_len(&self) -> u64 { self.as_inner().ty().unwrap().len @@ -97,6 +103,16 @@ pub(crate) trait ListType: AsInner { } }; + // avoid the first item of the list being deleted + while let Some(item) = pos.right.get() { + if item.deleted() { + pos.right = item.right.clone(); + continue; + } else { + break; + } + } + while remaining > 0 { if let Some(item) = pos.right.get() { if !item.deleted() { @@ -178,7 +194,12 @@ pub(crate) trait ListType: AsInner { return Ok(()); } - if idx >= self.content_len() { + let content_len = self.content_len(); + if content_len == 0 { + return Ok(()); + } + + if idx >= content_len { return Err(JwstCodecError::IndexOutOfBound(idx)); } diff --git a/y-octo/src/doc/types/map.rs b/y-octo/src/doc/types/map.rs index c2336f1..b17c5a5 100644 --- a/y-octo/src/doc/types/map.rs +++ b/y-octo/src/doc/types/map.rs @@ -9,6 +9,10 @@ use crate::{ impl_type!(Map); pub(crate) trait MapType: AsInner { + fn _id(&self) -> Option { + self.as_inner().ty().and_then(|ty| ty.item.get().map(|item| item.id)) + } + fn _insert>(&mut self, key: String, value: V) -> JwstCodecResult { if let Some((mut store, mut ty)) = self.as_inner().write() { let left = ty.map.get(&SmolStr::new(&key)).cloned(); @@ -154,6 +158,11 @@ impl<'a> Iterator for EntriesIterator<'a> { impl MapType for Map {} impl Map { + #[inline(always)] + pub fn id(&self) -> Option { + self._id() + } + #[inline(always)] pub fn insert>(&mut self, key: String, value: V) -> JwstCodecResult { self._insert(key, value) diff --git a/y-octo/src/doc/types/mod.rs b/y-octo/src/doc/types/mod.rs index 4934690..eaec0ef 100644 --- a/y-octo/src/doc/types/mod.rs +++ b/y-octo/src/doc/types/mod.rs @@ -5,7 +5,11 @@ mod text; mod value; mod xml; -use std::{collections::hash_map::Entry, sync::Weak}; +use std::{ + collections::hash_map::Entry, + hash::{Hash, Hasher}, + sync::Weak, +}; pub use array::*; use list::*; @@ -62,6 +66,14 @@ impl PartialEq for YTypeRef { } } +impl Eq for YTypeRef {} + +impl Hash for YTypeRef { + fn hash(&self, state: &mut H) { + self.inner.ptr().hash(state); + } +} + impl YType { pub fn new(kind: YTypeKind, tag_name: Option) -> Self { YType { diff --git a/y-octo/src/doc/types/text.rs b/y-octo/src/doc/types/text.rs index e701b65..977cd75 100644 --- a/y-octo/src/doc/types/text.rs +++ b/y-octo/src/doc/types/text.rs @@ -255,7 +255,7 @@ mod tests { loom_model!({ // in loom loop #[allow(clippy::needless_borrow)] - let doc = Doc::try_from_binary_v1(&binary).unwrap(); + let doc = Doc::try_from_binary_v1(binary).unwrap(); let mut text = doc.get_or_create_text("greating").unwrap(); assert_eq!(text.to_string(), "hello world"); diff --git a/y-octo/src/doc/types/value.rs b/y-octo/src/doc/types/value.rs index 53a8434..80ec6a1 100644 --- a/y-octo/src/doc/types/value.rs +++ b/y-octo/src/doc/types/value.rs @@ -2,7 +2,7 @@ use std::fmt::Display; use super::*; -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub enum Value { Any(Any), Doc(Doc), diff --git a/y-octo/src/doc/utils.rs b/y-octo/src/doc/utils.rs index 7463d38..1c52fa6 100644 --- a/y-octo/src/doc/utils.rs +++ b/y-octo/src/doc/utils.rs @@ -24,3 +24,21 @@ pub fn merge_updates_v1, I: IntoIterator>(updates: I) - Ok(Update::merge(updates)) } + +/// It tends to generate small numbers. +/// Since the client id will be included in all crdt items, the +/// small client helps to reduce the binary size. +/// +/// NOTE: The probability of 36% of the random number generated by +/// this function is greater than [u32::MAX] +pub fn prefer_small_random() -> u64 { + use rand::{distributions::Distribution, thread_rng}; + use rand_distr::Exp; + + let scale_factor = u16::MAX as f64; + let v: f64 = Exp::new(1.0 / scale_factor) + .map(|exp| exp.sample(&mut thread_rng())) + .unwrap_or_else(|_| rand::random()); + + (v * scale_factor) as u64 +} diff --git a/y-octo/src/lib.rs b/y-octo/src/lib.rs index e7e8ade..5e00b43 100644 --- a/y-octo/src/lib.rs +++ b/y-octo/src/lib.rs @@ -6,16 +6,17 @@ mod sync; pub use codec::*; pub use doc::{ - encode_awareness_as_message, encode_update_as_message, merge_updates_v1, Any, Array, Awareness, AwarenessEvent, - Client, ClientMap, Clock, CrdtRead, CrdtReader, CrdtWrite, CrdtWriter, Doc, DocOptions, HashMap as AHashMap, - HashMapExt, History, HistoryOptions, Id, Map, RawDecoder, RawEncoder, StateVector, StoreHistory, Text, Update, - Value, + batch_commit, encode_awareness_as_message, encode_update_as_message, merge_updates_v1, prefer_small_random, Any, + Array, Awareness, AwarenessEvent, Client, ClientMap, Clock, CrdtRead, CrdtReader, CrdtWrite, CrdtWriter, DeleteSet, + Doc, DocOptions, EntriesIterator, HashMap as AHashMap, HashMapExt, History, HistoryOptions, Id, KeysIterator, Map, + RawDecoder, RawEncoder, StateVector, StoreHistory, Text, Update, Value, ValuesIterator, }; pub(crate) use doc::{Content, Item}; use log::{debug, warn}; use nom::IResult; pub use protocol::{ - read_sync_message, write_sync_message, AwarenessState, AwarenessStates, DocMessage, SyncMessage, SyncMessageScanner, + read_doc_message, read_sync_message, write_doc_message, write_sync_message, AwarenessState, AwarenessStates, + DocMessage, SyncMessage, SyncMessageScanner, }; use thiserror::Error; diff --git a/y-octo/src/protocol/mod.rs b/y-octo/src/protocol/mod.rs index 51cd0c6..3b8e5bb 100644 --- a/y-octo/src/protocol/mod.rs +++ b/y-octo/src/protocol/mod.rs @@ -10,8 +10,7 @@ use std::{ use awareness::{read_awareness, write_awareness}; pub use awareness::{AwarenessState, AwarenessStates}; -pub use doc::DocMessage; -use doc::{read_doc_message, write_doc_message}; +pub use doc::{read_doc_message, write_doc_message, DocMessage}; use log::debug; use nom::{ error::{Error, ErrorKind}, diff --git a/yarn.lock b/yarn.lock index 2f97c54..565fa70 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,106 +12,1589 @@ __metadata: languageName: node linkType: hard -"@cspotcode/source-map-support@npm:^0.8.0": - version: 0.8.1 - resolution: "@cspotcode/source-map-support@npm:0.8.1" +"@emnapi/core@npm:^1.1.0": + version: 1.2.0 + resolution: "@emnapi/core@npm:1.2.0" + dependencies: + "@emnapi/wasi-threads": 1.0.1 + tslib: ^2.4.0 + checksum: b3b61bd01de93346f05803151eee9dc308262065034d835db95a46842ea75867c43745c227577f19fa0542fcb3883a752477eb012bf9e4b72f540f4e23f63cbe + languageName: node + linkType: hard + +"@emnapi/runtime@npm:^1.1.0": + version: 1.2.0 + resolution: "@emnapi/runtime@npm:1.2.0" + dependencies: + tslib: ^2.4.0 + checksum: c9f5814f65a7851eda3fae96320b7ebfaf3b7e0db4e1ac2d77b55f5c0785e56b459a029413dbfc0abb1b23f059b850169888f92833150a28cdf24b9a53e535c5 + languageName: node + linkType: hard + +"@emnapi/wasi-threads@npm:1.0.1": + version: 1.0.1 + resolution: "@emnapi/wasi-threads@npm:1.0.1" + dependencies: + tslib: ^2.4.0 + checksum: e154880440ff9bfe67b417f30134f0ff6fee28913dbf4a22de2e67dda5bf5b51055647c5d1565281df17ef5dfcc89256546bdf9b8ccfd07e07566617e7ce1498 + languageName: node + linkType: hard + +"@esbuild/aix-ppc64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/aix-ppc64@npm:0.21.5" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/aix-ppc64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/aix-ppc64@npm:0.23.1" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/android-arm64@npm:0.21.5" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-arm64@npm:0.23.1" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/android-arm@npm:0.21.5" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-arm@npm:0.23.1" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/android-x64@npm:0.21.5" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-x64@npm:0.23.1" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/darwin-arm64@npm:0.21.5" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/darwin-arm64@npm:0.23.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/darwin-x64@npm:0.21.5" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/darwin-x64@npm:0.23.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/freebsd-arm64@npm:0.21.5" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/freebsd-arm64@npm:0.23.1" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/freebsd-x64@npm:0.21.5" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/freebsd-x64@npm:0.23.1" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-arm64@npm:0.21.5" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-arm64@npm:0.23.1" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-arm@npm:0.21.5" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-arm@npm:0.23.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-ia32@npm:0.21.5" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-ia32@npm:0.23.1" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-loong64@npm:0.21.5" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-loong64@npm:0.23.1" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-mips64el@npm:0.21.5" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-mips64el@npm:0.23.1" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-ppc64@npm:0.21.5" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-ppc64@npm:0.23.1" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-riscv64@npm:0.21.5" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-riscv64@npm:0.23.1" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-s390x@npm:0.21.5" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-s390x@npm:0.23.1" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/linux-x64@npm:0.21.5" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-x64@npm:0.23.1" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/netbsd-x64@npm:0.21.5" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/netbsd-x64@npm:0.23.1" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/openbsd-arm64@npm:0.23.1" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/openbsd-x64@npm:0.21.5" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/openbsd-x64@npm:0.23.1" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/sunos-x64@npm:0.21.5" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/sunos-x64@npm:0.23.1" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/win32-arm64@npm:0.21.5" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-arm64@npm:0.23.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/win32-ia32@npm:0.21.5" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-ia32@npm:0.23.1" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.21.5": + version: 0.21.5 + resolution: "@esbuild/win32-x64@npm:0.21.5" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-x64@npm:0.23.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@inquirer/checkbox@npm:^2.5.0": + version: 2.5.0 + resolution: "@inquirer/checkbox@npm:2.5.0" + dependencies: + "@inquirer/core": ^9.1.0 + "@inquirer/figures": ^1.0.5 + "@inquirer/type": ^1.5.3 + ansi-escapes: ^4.3.2 + yoctocolors-cjs: ^2.1.2 + checksum: 4f1df42fe9eb725787803b11daf11d9bda30c31c68ff170d494b089d86bcf3858a7a98f0b6edd172d20479548bcfb241a7142f5f0880d536eac8c6cb7739489e + languageName: node + linkType: hard + +"@inquirer/confirm@npm:^3.2.0": + version: 3.2.0 + resolution: "@inquirer/confirm@npm:3.2.0" + dependencies: + "@inquirer/core": ^9.1.0 + "@inquirer/type": ^1.5.3 + checksum: 6b032a26c64075dc14769558720b17f09bc6784a223bbf2c85ec42e491be6ce4c4b83518433c47e05d7e8836ba680ab1b2f6b9c553410d4326582308a1fd2259 + languageName: node + linkType: hard + +"@inquirer/core@npm:^9.1.0": + version: 9.1.0 + resolution: "@inquirer/core@npm:9.1.0" + dependencies: + "@inquirer/figures": ^1.0.5 + "@inquirer/type": ^1.5.3 + "@types/mute-stream": ^0.0.4 + "@types/node": ^22.5.2 + "@types/wrap-ansi": ^3.0.0 + ansi-escapes: ^4.3.2 + cli-spinners: ^2.9.2 + cli-width: ^4.1.0 + mute-stream: ^1.0.0 + signal-exit: ^4.1.0 + strip-ansi: ^6.0.1 + wrap-ansi: ^6.2.0 + yoctocolors-cjs: ^2.1.2 + checksum: c671d88aaecf828ad8a9fe9a897637fb0c5c7dee5840e7c8711b914dba7e0caadf61a7c515b3f3302e77e6ac95a9249ea5c29792221ccda317db7ab760485077 + languageName: node + linkType: hard + +"@inquirer/editor@npm:^2.2.0": + version: 2.2.0 + resolution: "@inquirer/editor@npm:2.2.0" + dependencies: + "@inquirer/core": ^9.1.0 + "@inquirer/type": ^1.5.3 + external-editor: ^3.1.0 + checksum: 6f238050613b4db8d4d76eafe1a3531c211a016866826bf55f1187c89d29439e69ef9fc7a4f86b26f2a4a45260184bd8200056d25c79a540014abe66581c7b81 + languageName: node + linkType: hard + +"@inquirer/expand@npm:^2.3.0": + version: 2.3.0 + resolution: "@inquirer/expand@npm:2.3.0" + dependencies: + "@inquirer/core": ^9.1.0 + "@inquirer/type": ^1.5.3 + yoctocolors-cjs: ^2.1.2 + checksum: fdc9b2d0a509e9c0120fda8e1c044593b1f4b68038fd13e19fc35cc305f1e132fddd482bc1b44966cbcab06d579d130cabbb5cac50d917549d16d7e66fad4e74 + languageName: node + linkType: hard + +"@inquirer/figures@npm:^1.0.5": + version: 1.0.5 + resolution: "@inquirer/figures@npm:1.0.5" + checksum: 01dc7b95fe7b030b0577d59f45c4fa5c002dccb43ac75ff106d7142825e09dee63a6f9c42b044da2bc964bf38c40229a112a26505a68f3912b15dc8304106bbc + languageName: node + linkType: hard + +"@inquirer/input@npm:^2.3.0": + version: 2.3.0 + resolution: "@inquirer/input@npm:2.3.0" + dependencies: + "@inquirer/core": ^9.1.0 + "@inquirer/type": ^1.5.3 + checksum: 5c5833050eb231e81beac3b70999c6a7b66b59809b0e60889dd0df012084ed2b28235da8025391ff26f41f4e913d89ead82f4fd92e18a9bdde5f2465416080ae + languageName: node + linkType: hard + +"@inquirer/number@npm:^1.1.0": + version: 1.1.0 + resolution: "@inquirer/number@npm:1.1.0" + dependencies: + "@inquirer/core": ^9.1.0 + "@inquirer/type": ^1.5.3 + checksum: 5f56fd32490b35f6fe53032db19bcad5f5000c3ed88e27e58f0d9dfe4f858808d7b9447b5a3a1d85216b2a4293f2d97c51624abf87d06ac26da45b50485b61db + languageName: node + linkType: hard + +"@inquirer/password@npm:^2.2.0": + version: 2.2.0 + resolution: "@inquirer/password@npm:2.2.0" + dependencies: + "@inquirer/core": ^9.1.0 + "@inquirer/type": ^1.5.3 + ansi-escapes: ^4.3.2 + checksum: 85a15957a667fcfcbfbd36b1acaf31d5c23473f229cb03ade37adfffa2016cfe75d81b0c59cf697e42bfe7dd2fa4f8e400b7eeafbda711fb2785456520a939f8 + languageName: node + linkType: hard + +"@inquirer/prompts@npm:^5.5.0": + version: 5.5.0 + resolution: "@inquirer/prompts@npm:5.5.0" + dependencies: + "@inquirer/checkbox": ^2.5.0 + "@inquirer/confirm": ^3.2.0 + "@inquirer/editor": ^2.2.0 + "@inquirer/expand": ^2.3.0 + "@inquirer/input": ^2.3.0 + "@inquirer/number": ^1.1.0 + "@inquirer/password": ^2.2.0 + "@inquirer/rawlist": ^2.3.0 + "@inquirer/search": ^1.1.0 + "@inquirer/select": ^2.5.0 + checksum: 647312c644284223483ec67fa476fee7bcc099793fb6773e44f325554c91f7db7a124dd81f0b5a9ad22b07c9e807c9f276b34ee4614c99921a9644b9e831d4e9 + languageName: node + linkType: hard + +"@inquirer/rawlist@npm:^2.3.0": + version: 2.3.0 + resolution: "@inquirer/rawlist@npm:2.3.0" + dependencies: + "@inquirer/core": ^9.1.0 + "@inquirer/type": ^1.5.3 + yoctocolors-cjs: ^2.1.2 + checksum: 48635c5f62527dde46209d168da53e364c33ea7f795c23d9a5ee7e0836159404adc4f68e7a743a0a9a9c4c90fc1f96668b6ff869c3232f1a3b585d3afcf0b702 + languageName: node + linkType: hard + +"@inquirer/search@npm:^1.1.0": + version: 1.1.0 + resolution: "@inquirer/search@npm:1.1.0" + dependencies: + "@inquirer/core": ^9.1.0 + "@inquirer/figures": ^1.0.5 + "@inquirer/type": ^1.5.3 + yoctocolors-cjs: ^2.1.2 + checksum: 1304adf79f181941c4bc41e7a400e68e3d9281819d523b0efb04f928f96ab0f28cdf800236c6847757a02a958ee3b0047d94079aba04a0aececfd9968f656c01 + languageName: node + linkType: hard + +"@inquirer/select@npm:^2.5.0": + version: 2.5.0 + resolution: "@inquirer/select@npm:2.5.0" + dependencies: + "@inquirer/core": ^9.1.0 + "@inquirer/figures": ^1.0.5 + "@inquirer/type": ^1.5.3 + ansi-escapes: ^4.3.2 + yoctocolors-cjs: ^2.1.2 + checksum: fc7aa1a70d69f61ad2270ebfb83c059ba8d6bc749a90ae759a538acfa0ae158621f9653625f3fa7ac81072674f19013898e16598ce71a3dd2476897304832598 + languageName: node + linkType: hard + +"@inquirer/type@npm:^1.5.3": + version: 1.5.3 + resolution: "@inquirer/type@npm:1.5.3" + dependencies: + mute-stream: ^1.0.0 + checksum: 12ca8437b1c60fab52b84b27360a7715106bcab4514f7f1be017ccf50c5c027697828ccfaeccd083c71fcd59187b406fa31d414715e016a07c7dc439cb546fbc + languageName: node + linkType: hard + +"@isaacs/cliui@npm:^8.0.2": + version: 8.0.2 + resolution: "@isaacs/cliui@npm:8.0.2" + dependencies: + string-width: ^5.1.2 + string-width-cjs: "npm:string-width@^4.2.0" + strip-ansi: ^7.0.1 + strip-ansi-cjs: "npm:strip-ansi@^6.0.1" + wrap-ansi: ^8.1.0 + wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" + checksum: 4a473b9b32a7d4d3cfb7a614226e555091ff0c5a29a1734c28c72a182c2f6699b26fc6b5c2131dfd841e86b185aea714c72201d7c98c2fba5f17709333a67aeb + languageName: node + linkType: hard + +"@istanbuljs/schema@npm:^0.1.2, @istanbuljs/schema@npm:^0.1.3": + version: 0.1.3 + resolution: "@istanbuljs/schema@npm:0.1.3" + checksum: 5282759d961d61350f33d9118d16bcaed914ebf8061a52f4fa474b2cb08720c9c81d165e13b82f2e5a8a212cc5af482f0c6fc1ac27b9e067e5394c9a6ed186c9 + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:^3.1.0": + version: 3.1.1 + resolution: "@jridgewell/resolve-uri@npm:3.1.1" + checksum: f5b441fe7900eab4f9155b3b93f9800a916257f4e8563afbcd3b5a5337b55e52bd8ae6735453b1b745457d9f6cdb16d74cd6220bbdd98cf153239e13f6cbb653 + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.14": + version: 1.4.15 + resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" + checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.5.0": + version: 1.5.0 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" + checksum: 05df4f2538b3b0f998ea4c1cd34574d0feba216fa5d4ccaef0187d12abf82eafe6021cec8b49f9bb4d90f2ba4582ccc581e72986a5fcf4176ae0cfeb04cf52ec + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.12": + version: 0.3.19 + resolution: "@jridgewell/trace-mapping@npm:0.3.19" + dependencies: + "@jridgewell/resolve-uri": ^3.1.0 + "@jridgewell/sourcemap-codec": ^1.4.14 + checksum: 956a6f0f6fec060fb48c6bf1f5ec2064e13cd38c8be3873877d4b92b4a27ba58289a34071752671262a3e3c202abcc3fa2aac64d8447b4b0fa1ba3c9047f1c20 + languageName: node + linkType: hard + +"@mapbox/node-pre-gyp@npm:^1.0.5": + version: 1.0.11 + resolution: "@mapbox/node-pre-gyp@npm:1.0.11" + dependencies: + detect-libc: ^2.0.0 + https-proxy-agent: ^5.0.0 + make-dir: ^3.1.0 + node-fetch: ^2.6.7 + nopt: ^5.0.0 + npmlog: ^5.0.1 + rimraf: ^3.0.2 + semver: ^7.3.5 + tar: ^6.1.11 + bin: + node-pre-gyp: bin/node-pre-gyp + checksum: b848f6abc531a11961d780db813cc510ca5a5b6bf3184d72134089c6875a91c44d571ba6c1879470020803f7803609e7b2e6e429651c026fe202facd11d444b8 + languageName: node + linkType: hard + +"@napi-rs/cli@npm:^3.0.0-alpha.62": + version: 3.0.0-alpha.62 + resolution: "@napi-rs/cli@npm:3.0.0-alpha.62" + dependencies: + "@napi-rs/cross-toolchain": ^0.0.16 + "@napi-rs/wasm-tools": ^0.0.2 + "@octokit/rest": ^21.0.0 + clipanion: ^3.2.1 + colorette: ^2.0.20 + debug: ^4.3.4 + emnapi: ^1.2.0 + inquirer: ^10.0.0 + js-yaml: ^4.1.0 + lodash-es: ^4.17.21 + semver: ^7.5.4 + toml: ^3.0.0 + typanion: ^3.14.0 + wasm-sjlj: ^1.0.5 + peerDependencies: + "@emnapi/runtime": ^1.1.0 + emnapi: ^1.1.0 + peerDependenciesMeta: + "@emnapi/runtime": + optional: true + emnapi: + optional: true + bin: + napi: ./dist/cli.js + napi-raw: ./cli.mjs + checksum: 350e5181922449e38dfde5d0565c65ad5a021ae87681e126ae1174692d22fc64cfc64602078e95574157d9f5a34cefdceddb2da8025e0d8bd702f4091343d599 + languageName: node + linkType: hard + +"@napi-rs/cross-toolchain@npm:^0.0.16": + version: 0.0.16 + resolution: "@napi-rs/cross-toolchain@npm:0.0.16" + dependencies: + "@napi-rs/lzma": ^1.3.1 + "@napi-rs/tar": ^0.1.1 + debug: ^4.3.4 + peerDependencies: + "@napi-rs/cross-toolchain-arm64-target-aarch64": ^0.0.16 + "@napi-rs/cross-toolchain-arm64-target-armv7": ^0.0.16 + "@napi-rs/cross-toolchain-arm64-target-x86_64": ^0.0.16 + "@napi-rs/cross-toolchain-x64-target-aarch64": ^0.0.16 + "@napi-rs/cross-toolchain-x64-target-armv7": ^0.0.16 + "@napi-rs/cross-toolchain-x64-target-x86_64": ^0.0.16 + peerDependenciesMeta: + "@napi-rs/cross-toolchain-arm64-target-aarch64": + optional: true + "@napi-rs/cross-toolchain-arm64-target-armv7": + optional: true + "@napi-rs/cross-toolchain-arm64-target-x86_64": + optional: true + "@napi-rs/cross-toolchain-x64-target-aarch64": + optional: true + "@napi-rs/cross-toolchain-x64-target-armv7": + optional: true + "@napi-rs/cross-toolchain-x64-target-x86_64": + optional: true + checksum: 8a0e75b10fad368ba0b04f09281a42aa2cd3bdc880ceffa7671c099418635fccca1d578ac141bca09810ddf23681907965d2df5686f5e79991cac1f02b44e398 + languageName: node + linkType: hard + +"@napi-rs/lzma-android-arm-eabi@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-android-arm-eabi@npm:1.3.1" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/lzma-android-arm64@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-android-arm64@npm:1.3.1" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/lzma-darwin-arm64@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-darwin-arm64@npm:1.3.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/lzma-darwin-x64@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-darwin-x64@npm:1.3.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/lzma-freebsd-x64@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-freebsd-x64@npm:1.3.1" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/lzma-linux-arm-gnueabihf@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-linux-arm-gnueabihf@npm:1.3.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/lzma-linux-arm64-gnu@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-linux-arm64-gnu@npm:1.3.1" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/lzma-linux-arm64-musl@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-linux-arm64-musl@npm:1.3.1" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/lzma-linux-x64-gnu@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-linux-x64-gnu@npm:1.3.1" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/lzma-linux-x64-musl@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-linux-x64-musl@npm:1.3.1" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/lzma-wasm32-wasi@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-wasm32-wasi@npm:1.3.1" + dependencies: + "@napi-rs/wasm-runtime": ^0.2.3 + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@napi-rs/lzma-win32-arm64-msvc@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-win32-arm64-msvc@npm:1.3.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/lzma-win32-ia32-msvc@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-win32-ia32-msvc@npm:1.3.1" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@napi-rs/lzma-win32-x64-msvc@npm:1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma-win32-x64-msvc@npm:1.3.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/lzma@npm:^1.3.1": + version: 1.3.1 + resolution: "@napi-rs/lzma@npm:1.3.1" + dependencies: + "@napi-rs/lzma-android-arm-eabi": 1.3.1 + "@napi-rs/lzma-android-arm64": 1.3.1 + "@napi-rs/lzma-darwin-arm64": 1.3.1 + "@napi-rs/lzma-darwin-x64": 1.3.1 + "@napi-rs/lzma-freebsd-x64": 1.3.1 + "@napi-rs/lzma-linux-arm-gnueabihf": 1.3.1 + "@napi-rs/lzma-linux-arm64-gnu": 1.3.1 + "@napi-rs/lzma-linux-arm64-musl": 1.3.1 + "@napi-rs/lzma-linux-x64-gnu": 1.3.1 + "@napi-rs/lzma-linux-x64-musl": 1.3.1 + "@napi-rs/lzma-wasm32-wasi": 1.3.1 + "@napi-rs/lzma-win32-arm64-msvc": 1.3.1 + "@napi-rs/lzma-win32-ia32-msvc": 1.3.1 + "@napi-rs/lzma-win32-x64-msvc": 1.3.1 + dependenciesMeta: + "@napi-rs/lzma-android-arm-eabi": + optional: true + "@napi-rs/lzma-android-arm64": + optional: true + "@napi-rs/lzma-darwin-arm64": + optional: true + "@napi-rs/lzma-darwin-x64": + optional: true + "@napi-rs/lzma-freebsd-x64": + optional: true + "@napi-rs/lzma-linux-arm-gnueabihf": + optional: true + "@napi-rs/lzma-linux-arm64-gnu": + optional: true + "@napi-rs/lzma-linux-arm64-musl": + optional: true + "@napi-rs/lzma-linux-x64-gnu": + optional: true + "@napi-rs/lzma-linux-x64-musl": + optional: true + "@napi-rs/lzma-wasm32-wasi": + optional: true + "@napi-rs/lzma-win32-arm64-msvc": + optional: true + "@napi-rs/lzma-win32-ia32-msvc": + optional: true + "@napi-rs/lzma-win32-x64-msvc": + optional: true + checksum: fc9d7075b95cbb59e0f0f645174f64b3abe8af69483a721a4466c88c9daae2738928da98cd546967cc308fc4da9ca4c9f0908c3d9bffde35cce46f12cf81a80d + languageName: node + linkType: hard + +"@napi-rs/tar-android-arm-eabi@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-android-arm-eabi@npm:0.1.4" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/tar-android-arm64@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-android-arm64@npm:0.1.4" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/tar-darwin-arm64@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-darwin-arm64@npm:0.1.4" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/tar-darwin-x64@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-darwin-x64@npm:0.1.4" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/tar-freebsd-x64@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-freebsd-x64@npm:0.1.4" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/tar-linux-arm-gnueabihf@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-linux-arm-gnueabihf@npm:0.1.4" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/tar-linux-arm64-gnu@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-linux-arm64-gnu@npm:0.1.4" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/tar-linux-arm64-musl@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-linux-arm64-musl@npm:0.1.4" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/tar-linux-ppc64-gnu@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-linux-ppc64-gnu@npm:0.1.4" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/tar-linux-s390x-gnu@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-linux-s390x-gnu@npm:0.1.4" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/tar-linux-x64-gnu@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-linux-x64-gnu@npm:0.1.4" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/tar-linux-x64-musl@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-linux-x64-musl@npm:0.1.4" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/tar-wasm32-wasi@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-wasm32-wasi@npm:0.1.4" + dependencies: + "@napi-rs/wasm-runtime": ^0.2.4 + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@napi-rs/tar-win32-arm64-msvc@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-win32-arm64-msvc@npm:0.1.4" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/tar-win32-ia32-msvc@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-win32-ia32-msvc@npm:0.1.4" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@napi-rs/tar-win32-x64-msvc@npm:0.1.4": + version: 0.1.4 + resolution: "@napi-rs/tar-win32-x64-msvc@npm:0.1.4" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/tar@npm:^0.1.1": + version: 0.1.4 + resolution: "@napi-rs/tar@npm:0.1.4" + dependencies: + "@napi-rs/tar-android-arm-eabi": 0.1.4 + "@napi-rs/tar-android-arm64": 0.1.4 + "@napi-rs/tar-darwin-arm64": 0.1.4 + "@napi-rs/tar-darwin-x64": 0.1.4 + "@napi-rs/tar-freebsd-x64": 0.1.4 + "@napi-rs/tar-linux-arm-gnueabihf": 0.1.4 + "@napi-rs/tar-linux-arm64-gnu": 0.1.4 + "@napi-rs/tar-linux-arm64-musl": 0.1.4 + "@napi-rs/tar-linux-ppc64-gnu": 0.1.4 + "@napi-rs/tar-linux-s390x-gnu": 0.1.4 + "@napi-rs/tar-linux-x64-gnu": 0.1.4 + "@napi-rs/tar-linux-x64-musl": 0.1.4 + "@napi-rs/tar-wasm32-wasi": 0.1.4 + "@napi-rs/tar-win32-arm64-msvc": 0.1.4 + "@napi-rs/tar-win32-ia32-msvc": 0.1.4 + "@napi-rs/tar-win32-x64-msvc": 0.1.4 + dependenciesMeta: + "@napi-rs/tar-android-arm-eabi": + optional: true + "@napi-rs/tar-android-arm64": + optional: true + "@napi-rs/tar-darwin-arm64": + optional: true + "@napi-rs/tar-darwin-x64": + optional: true + "@napi-rs/tar-freebsd-x64": + optional: true + "@napi-rs/tar-linux-arm-gnueabihf": + optional: true + "@napi-rs/tar-linux-arm64-gnu": + optional: true + "@napi-rs/tar-linux-arm64-musl": + optional: true + "@napi-rs/tar-linux-ppc64-gnu": + optional: true + "@napi-rs/tar-linux-s390x-gnu": + optional: true + "@napi-rs/tar-linux-x64-gnu": + optional: true + "@napi-rs/tar-linux-x64-musl": + optional: true + "@napi-rs/tar-wasm32-wasi": + optional: true + "@napi-rs/tar-win32-arm64-msvc": + optional: true + "@napi-rs/tar-win32-ia32-msvc": + optional: true + "@napi-rs/tar-win32-x64-msvc": + optional: true + checksum: c94548e1784135ab4271ce970b054cfbe3b87014c6e51386298028616d59127fbec8d478b3b058548eb3ddca96027e24b144a18c535468e0300b5a3ae1cde8ae + languageName: node + linkType: hard + +"@napi-rs/wasm-runtime@npm:^0.2.3, @napi-rs/wasm-runtime@npm:^0.2.4": + version: 0.2.4 + resolution: "@napi-rs/wasm-runtime@npm:0.2.4" + dependencies: + "@emnapi/core": ^1.1.0 + "@emnapi/runtime": ^1.1.0 + "@tybys/wasm-util": ^0.9.0 + checksum: 976eeca9c411724bf004f92a94707f1c78b6a5932a354e8b456eaae16c476dd6b96244c4afec60a3f621c922fca3ef2c6c3f6a900bd6b79f509dd4c0c2b3376d + languageName: node + linkType: hard + +"@napi-rs/wasm-tools-android-arm-eabi@npm:0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools-android-arm-eabi@npm:0.0.2" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@napi-rs/wasm-tools-android-arm64@npm:0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools-android-arm64@npm:0.0.2" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/wasm-tools-darwin-arm64@npm:0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools-darwin-arm64@npm:0.0.2" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/wasm-tools-darwin-x64@npm:0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools-darwin-x64@npm:0.0.2" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/wasm-tools-freebsd-x64@npm:0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools-freebsd-x64@npm:0.0.2" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/wasm-tools-linux-arm64-gnu@npm:0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools-linux-arm64-gnu@npm:0.0.2" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/wasm-tools-linux-arm64-musl@npm:0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools-linux-arm64-musl@npm:0.0.2" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/wasm-tools-linux-x64-gnu@npm:0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools-linux-x64-gnu@npm:0.0.2" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@napi-rs/wasm-tools-linux-x64-musl@npm:0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools-linux-x64-musl@npm:0.0.2" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@napi-rs/wasm-tools-wasm32-wasi@npm:0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools-wasm32-wasi@npm:0.0.2" + dependencies: + "@napi-rs/wasm-runtime": ^0.2.3 + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@napi-rs/wasm-tools-win32-arm64-msvc@npm:0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools-win32-arm64-msvc@npm:0.0.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@napi-rs/wasm-tools-win32-ia32-msvc@npm:0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools-win32-ia32-msvc@npm:0.0.2" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@napi-rs/wasm-tools-win32-x64-msvc@npm:0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools-win32-x64-msvc@npm:0.0.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@napi-rs/wasm-tools@npm:^0.0.2": + version: 0.0.2 + resolution: "@napi-rs/wasm-tools@npm:0.0.2" + dependencies: + "@napi-rs/wasm-tools-android-arm-eabi": 0.0.2 + "@napi-rs/wasm-tools-android-arm64": 0.0.2 + "@napi-rs/wasm-tools-darwin-arm64": 0.0.2 + "@napi-rs/wasm-tools-darwin-x64": 0.0.2 + "@napi-rs/wasm-tools-freebsd-x64": 0.0.2 + "@napi-rs/wasm-tools-linux-arm64-gnu": 0.0.2 + "@napi-rs/wasm-tools-linux-arm64-musl": 0.0.2 + "@napi-rs/wasm-tools-linux-x64-gnu": 0.0.2 + "@napi-rs/wasm-tools-linux-x64-musl": 0.0.2 + "@napi-rs/wasm-tools-wasm32-wasi": 0.0.2 + "@napi-rs/wasm-tools-win32-arm64-msvc": 0.0.2 + "@napi-rs/wasm-tools-win32-ia32-msvc": 0.0.2 + "@napi-rs/wasm-tools-win32-x64-msvc": 0.0.2 + dependenciesMeta: + "@napi-rs/wasm-tools-android-arm-eabi": + optional: true + "@napi-rs/wasm-tools-android-arm64": + optional: true + "@napi-rs/wasm-tools-darwin-arm64": + optional: true + "@napi-rs/wasm-tools-darwin-x64": + optional: true + "@napi-rs/wasm-tools-freebsd-x64": + optional: true + "@napi-rs/wasm-tools-linux-arm64-gnu": + optional: true + "@napi-rs/wasm-tools-linux-arm64-musl": + optional: true + "@napi-rs/wasm-tools-linux-x64-gnu": + optional: true + "@napi-rs/wasm-tools-linux-x64-musl": + optional: true + "@napi-rs/wasm-tools-wasm32-wasi": + optional: true + "@napi-rs/wasm-tools-win32-arm64-msvc": + optional: true + "@napi-rs/wasm-tools-win32-ia32-msvc": + optional: true + "@napi-rs/wasm-tools-win32-x64-msvc": + optional: true + checksum: 5ef364f487353537b13006c222c1a8ee3b85e07227189c9bcd1d707152489c607aa91a69cff1484e52f6a23fbb3db1e188aa9d8a97a9d40486aa17deaf190738 + languageName: node + linkType: hard + +"@nodelib/fs.scandir@npm:2.1.5": + version: 2.1.5 + resolution: "@nodelib/fs.scandir@npm:2.1.5" + dependencies: + "@nodelib/fs.stat": 2.0.5 + run-parallel: ^1.1.9 + checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59 + languageName: node + linkType: hard + +"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": + version: 2.0.5 + resolution: "@nodelib/fs.stat@npm:2.0.5" + checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 + languageName: node + linkType: hard + +"@nodelib/fs.walk@npm:^1.2.3": + version: 1.2.8 + resolution: "@nodelib/fs.walk@npm:1.2.8" + dependencies: + "@nodelib/fs.scandir": 2.1.5 + fastq: ^1.6.0 + checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53 + languageName: node + linkType: hard + +"@nolyfill/shared@npm:1.0.28": + version: 1.0.28 + resolution: "@nolyfill/shared@npm:1.0.28" + checksum: 395261f73688e2a58f78c34238a13176feb2b79b0a331d9bcf6bfdb9d8473115934468e73eefe89614a0e5cb0b896d900c0e738de452fbb4d3648c944db02428 + languageName: node + linkType: hard + +"@npmcli/agent@npm:^2.0.0": + version: 2.2.2 + resolution: "@npmcli/agent@npm:2.2.2" + dependencies: + agent-base: ^7.1.0 + http-proxy-agent: ^7.0.0 + https-proxy-agent: ^7.0.1 + lru-cache: ^10.0.1 + socks-proxy-agent: ^8.0.3 + checksum: 67de7b88cc627a79743c88bab35e023e23daf13831a8aa4e15f998b92f5507b644d8ffc3788afc8e64423c612e0785a6a92b74782ce368f49a6746084b50d874 + languageName: node + linkType: hard + +"@npmcli/fs@npm:^3.1.0": + version: 3.1.1 + resolution: "@npmcli/fs@npm:3.1.1" + dependencies: + semver: ^7.3.5 + checksum: d960cab4b93adcb31ce223bfb75c5714edbd55747342efb67dcc2f25e023d930a7af6ece3e75f2f459b6f38fc14d031c766f116cd124fdc937fd33112579e820 + languageName: node + linkType: hard + +"@octokit/auth-token@npm:^5.0.0": + version: 5.1.1 + resolution: "@octokit/auth-token@npm:5.1.1" + checksum: b39516dda44aeced0326227c53aade621effe1d59c4b0f48ebe2b9fd32b5156e02705bcb2fb1bf48b11f26cc6aff1a0683c32c3d5424e0118dae6596e431d489 + languageName: node + linkType: hard + +"@octokit/core@npm:^6.1.2": + version: 6.1.2 + resolution: "@octokit/core@npm:6.1.2" dependencies: - "@jridgewell/trace-mapping": 0.3.9 - checksum: 5718f267085ed8edb3e7ef210137241775e607ee18b77d95aa5bd7514f47f5019aa2d82d96b3bf342ef7aa890a346fa1044532ff7cc3009e7d24fce3ce6200fa + "@octokit/auth-token": ^5.0.0 + "@octokit/graphql": ^8.0.0 + "@octokit/request": ^9.0.0 + "@octokit/request-error": ^6.0.1 + "@octokit/types": ^13.0.0 + before-after-hook: ^3.0.2 + universal-user-agent: ^7.0.0 + checksum: e794fb11b3942f55033f4cf6c0914953fd974587309498e8709c428660fa5c098334d83af5e41457dbe67d92d70a8b559c6cc00457d6c95290fa6c9e1d4bfc42 languageName: node linkType: hard -"@istanbuljs/schema@npm:^0.1.2, @istanbuljs/schema@npm:^0.1.3": - version: 0.1.3 - resolution: "@istanbuljs/schema@npm:0.1.3" - checksum: 5282759d961d61350f33d9118d16bcaed914ebf8061a52f4fa474b2cb08720c9c81d165e13b82f2e5a8a212cc5af482f0c6fc1ac27b9e067e5394c9a6ed186c9 +"@octokit/endpoint@npm:^10.0.0": + version: 10.1.1 + resolution: "@octokit/endpoint@npm:10.1.1" + dependencies: + "@octokit/types": ^13.0.0 + universal-user-agent: ^7.0.2 + checksum: fde158f40dc9a88e92a8ac1d347a54599aa5715ec24045be9cb8ff8decb3c17b63c91eca1bab12dfe0e0cd37433127dd05cd05db14a719dca749bc56093aa915 languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0": - version: 3.1.1 - resolution: "@jridgewell/resolve-uri@npm:3.1.1" - checksum: f5b441fe7900eab4f9155b3b93f9800a916257f4e8563afbcd3b5a5337b55e52bd8ae6735453b1b745457d9f6cdb16d74cd6220bbdd98cf153239e13f6cbb653 +"@octokit/graphql@npm:^8.0.0": + version: 8.1.1 + resolution: "@octokit/graphql@npm:8.1.1" + dependencies: + "@octokit/request": ^9.0.0 + "@octokit/types": ^13.0.0 + universal-user-agent: ^7.0.0 + checksum: 07239666b0ca38a7d8c581570b544ee9fd1a2616c8dd436af31879662b3345c44ed52e3d7b311840a1c5772a23f02caf7585aca56f36e50f38f0207a87577a9c languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": - version: 1.4.15 - resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" - checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 +"@octokit/openapi-types@npm:^22.2.0": + version: 22.2.0 + resolution: "@octokit/openapi-types@npm:22.2.0" + checksum: eca41feac2b83298e0d95e253ac1c5b6d65155ac57f65c5fd8d4a485d9728922d85ff4bee0e815a1f3a5421311db092bdb6da9d6104a1b1843d8b274bcad9630 languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:0.3.9": - version: 0.3.9 - resolution: "@jridgewell/trace-mapping@npm:0.3.9" +"@octokit/plugin-paginate-rest@npm:^11.0.0": + version: 11.3.3 + resolution: "@octokit/plugin-paginate-rest@npm:11.3.3" dependencies: - "@jridgewell/resolve-uri": ^3.0.3 - "@jridgewell/sourcemap-codec": ^1.4.10 - checksum: d89597752fd88d3f3480845691a05a44bd21faac18e2185b6f436c3b0fd0c5a859fbbd9aaa92050c4052caf325ad3e10e2e1d1b64327517471b7d51babc0ddef + "@octokit/types": ^13.5.0 + peerDependencies: + "@octokit/core": ">=6" + checksum: 93c7993562caed67b67f75aa77ffb10d032c242a70e9380e2fb9ab67dd2fb84d420231d09cd8a64f1553ffd325f3ef8c640c62e4267b7f3b352b16d4d5e11ef6 languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.12": - version: 0.3.19 - resolution: "@jridgewell/trace-mapping@npm:0.3.19" +"@octokit/plugin-request-log@npm:^5.3.1": + version: 5.3.1 + resolution: "@octokit/plugin-request-log@npm:5.3.1" + peerDependencies: + "@octokit/core": ">=6" + checksum: a27e163282c8d0ba8feee4d3cbbd1b62e1aa89a892877f7a9876fc17ddde3e1e1af922e6664221a0cabae99b8a7a2a5215b9ec2ee5222edb50e06298e99022b0 + languageName: node + linkType: hard + +"@octokit/plugin-rest-endpoint-methods@npm:^13.0.0": + version: 13.2.4 + resolution: "@octokit/plugin-rest-endpoint-methods@npm:13.2.4" dependencies: - "@jridgewell/resolve-uri": ^3.1.0 - "@jridgewell/sourcemap-codec": ^1.4.14 - checksum: 956a6f0f6fec060fb48c6bf1f5ec2064e13cd38c8be3873877d4b92b4a27ba58289a34071752671262a3e3c202abcc3fa2aac64d8447b4b0fa1ba3c9047f1c20 + "@octokit/types": ^13.5.0 + peerDependencies: + "@octokit/core": ">=6" + checksum: 149643bf98933af92003c55ad7f1e87c239941e843708cfc7389d378e85069e88b7cccaf8227469ee037d54da93cbdb881a34ce9888f5a60f89c689305eb5730 languageName: node linkType: hard -"@napi-rs/cli@npm:^2.16.2": - version: 2.16.3 - resolution: "@napi-rs/cli@npm:2.16.3" - bin: - napi: scripts/index.js - checksum: 11f78b09548bc5c22df56e4fab4a87b68c2d3f2a18a55cf11e775e6a4cb5739ec0e21a14e614db2cdc2b9773cb42536c6bd00c3f85d3b461f956594f8a89ddcb +"@octokit/request-error@npm:^6.0.1": + version: 6.1.4 + resolution: "@octokit/request-error@npm:6.1.4" + dependencies: + "@octokit/types": ^13.0.0 + checksum: e4e475ec50cef8e271f39e69667d0f8eaccb2367aa56b81638c629b5bbfa2b697b40207301e5c797a63051a82d8698e7c792b4050b84e383c54300a49a01304a languageName: node linkType: hard -"@nolyfill/shared@npm:1.0.20": - version: 1.0.20 - resolution: "@nolyfill/shared@npm:1.0.20" - checksum: cb2511c301e0e5dc15926a59a396352d0dd7f3376979c9526538ee25e223bc1d4524ecca4d245c1cd0c377d47ddbcad7f606d151f382b00f47844ef5f61872e5 +"@octokit/request@npm:^9.0.0": + version: 9.1.3 + resolution: "@octokit/request@npm:9.1.3" + dependencies: + "@octokit/endpoint": ^10.0.0 + "@octokit/request-error": ^6.0.1 + "@octokit/types": ^13.1.0 + universal-user-agent: ^7.0.2 + checksum: 0a1c1a4f9ba67954402ef6d1e3d8e78518487750f3a31c100133840fff393ed9cc29533282914adf0731f7cc880a2778b8a6ac81527b376a278360a86e79597d languageName: node linkType: hard -"@taplo/cli@npm:^0.5.2": - version: 0.5.2 - resolution: "@taplo/cli@npm:0.5.2" - bin: - taplo: dist/cli.js - checksum: c2e0e584172bfee1cca6624bdb4470259179e232472fc7f4bbbd2e0127233039b9ace21a8d6b8d5081b157d9f046dc942ab27a634e23924b8c8a6096f1d04e27 +"@octokit/rest@npm:^21.0.0": + version: 21.0.2 + resolution: "@octokit/rest@npm:21.0.2" + dependencies: + "@octokit/core": ^6.1.2 + "@octokit/plugin-paginate-rest": ^11.0.0 + "@octokit/plugin-request-log": ^5.3.1 + "@octokit/plugin-rest-endpoint-methods": ^13.0.0 + checksum: 81dc98bbc27d4891a211628ea49ba40f087f986ee85d7e2f0579b66e4046dd6b6d63ffeb0eb011c9240dd61906798795e4b9e309af230f31df0a42db79ae20bc languageName: node linkType: hard -"@tsconfig/node10@npm:^1.0.7": - version: 1.0.9 - resolution: "@tsconfig/node10@npm:1.0.9" - checksum: a33ae4dc2a621c0678ac8ac4bceb8e512ae75dac65417a2ad9b022d9b5411e863c4c198b6ba9ef659e14b9fb609bbec680841a2e84c1172df7a5ffcf076539df +"@octokit/types@npm:^13.0.0, @octokit/types@npm:^13.1.0, @octokit/types@npm:^13.5.0": + version: 13.5.0 + resolution: "@octokit/types@npm:13.5.0" + dependencies: + "@octokit/openapi-types": ^22.2.0 + checksum: 8e92f2b145b3c28a35312f93714245824a7b6b7353caa88edfdc85fc2ed4108321ed0c3988001ea53449fbb212febe0e8e9582744e85c3574dabe9d0441af5a0 languageName: node linkType: hard -"@tsconfig/node12@npm:^1.0.7": - version: 1.0.11 - resolution: "@tsconfig/node12@npm:1.0.11" - checksum: 5ce29a41b13e7897a58b8e2df11269c5395999e588b9a467386f99d1d26f6c77d1af2719e407621412520ea30517d718d5192a32403b8dfcc163bf33e40a338a +"@pkgjs/parseargs@npm:^0.11.0": + version: 0.11.0 + resolution: "@pkgjs/parseargs@npm:0.11.0" + checksum: 6ad6a00fc4f2f2cfc6bff76fb1d88b8ee20bc0601e18ebb01b6d4be583733a860239a521a7fbca73b612e66705078809483549d2b18f370eb346c5155c8e4a0f languageName: node linkType: hard -"@tsconfig/node14@npm:^1.0.0": - version: 1.0.3 - resolution: "@tsconfig/node14@npm:1.0.3" - checksum: 19275fe80c4c8d0ad0abed6a96dbf00642e88b220b090418609c4376e1cef81bf16237bf170ad1b341452feddb8115d8dd2e5acdfdea1b27422071163dc9ba9d +"@rollup/plugin-alias@npm:^5.1.0": + version: 5.1.0 + resolution: "@rollup/plugin-alias@npm:5.1.0" + dependencies: + slash: ^4.0.0 + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: e9f0a27b0f6f166c4c72757a2ecf23411dcc6da22ae2e020ddf30fa95526c8ab36ad372ed994dde806de4dcc47b2f1305138b953764a8f879c85fd725ac2a493 languageName: node linkType: hard -"@tsconfig/node16@npm:^1.0.2": - version: 1.0.4 - resolution: "@tsconfig/node16@npm:1.0.4" - checksum: 202319785901f942a6e1e476b872d421baec20cf09f4b266a1854060efbf78cde16a4d256e8bc949d31e6cd9a90f1e8ef8fb06af96a65e98338a2b6b0de0a0ff +"@rollup/plugin-commonjs@npm:^26.0.1": + version: 26.0.1 + resolution: "@rollup/plugin-commonjs@npm:26.0.1" + dependencies: + "@rollup/pluginutils": ^5.0.1 + commondir: ^1.0.1 + estree-walker: ^2.0.2 + glob: ^10.4.1 + is-reference: 1.2.1 + magic-string: ^0.30.3 + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 88d1349cc2cda4ad6193cce901356e4c14a830497fc01c91f38c94a871b203ffe657b29c9a98cd16787e3a6a8b45169dd0b471cb36d26d645478a177c958779a + languageName: node + linkType: hard + +"@rollup/plugin-inject@npm:^5.0.5": + version: 5.0.5 + resolution: "@rollup/plugin-inject@npm:5.0.5" + dependencies: + "@rollup/pluginutils": ^5.0.1 + estree-walker: ^2.0.2 + magic-string: ^0.30.3 + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 22cb772fd6f7178308b2ece95cdde5f8615f6257197832166294552a7e4c0d3976dc996cbfa6470af3151d8b86c00091aa93da5f4db6ec563f11b6db29fd1b63 + languageName: node + linkType: hard + +"@rollup/plugin-json@npm:^6.1.0": + version: 6.1.0 + resolution: "@rollup/plugin-json@npm:6.1.0" + dependencies: + "@rollup/pluginutils": ^5.1.0 + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: cc018d20c80242a2b8b44fae61a968049cf31bb8406218187cc7cda35747616594e79452dd65722e7da6dd825b392e90d4599d43cd4461a02fefa2865945164e + languageName: node + linkType: hard + +"@rollup/plugin-node-resolve@npm:^15.2.3": + version: 15.2.3 + resolution: "@rollup/plugin-node-resolve@npm:15.2.3" + dependencies: + "@rollup/pluginutils": ^5.0.1 + "@types/resolve": 1.20.2 + deepmerge: ^4.2.2 + is-builtin-module: ^3.2.1 + is-module: ^1.0.0 + resolve: ^1.22.1 + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 730f32c2f8fdddff07cf0fca86a5dac7c475605fb96930197a868c066e62eb6388c557545e4f7d99b7a283411754c9fbf98944ab086b6074e04fc1292e234aa8 + languageName: node + linkType: hard + +"@rollup/plugin-replace@npm:^5.0.7": + version: 5.0.7 + resolution: "@rollup/plugin-replace@npm:5.0.7" + dependencies: + "@rollup/pluginutils": ^5.0.1 + magic-string: ^0.30.3 + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 67985e3f4056b92a5f6847b9ddf5b8e9aaecefa0e20b96751dcd63c3ca1f907dadad2940f270867dab2e24bc27da6b0e82f0ce6bb20309aa3465869a9d2e3f13 + languageName: node + linkType: hard + +"@rollup/pluginutils@npm:^4.0.0": + version: 4.2.1 + resolution: "@rollup/pluginutils@npm:4.2.1" + dependencies: + estree-walker: ^2.0.1 + picomatch: ^2.2.2 + checksum: 6bc41f22b1a0f1efec3043899e4d3b6b1497b3dea4d94292d8f83b4cf07a1073ecbaedd562a22d11913ff7659f459677b01b09e9598a98936e746780ecc93a12 + languageName: node + linkType: hard + +"@rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.1.0": + version: 5.1.0 + resolution: "@rollup/pluginutils@npm:5.1.0" + dependencies: + "@types/estree": ^1.0.0 + estree-walker: ^2.0.2 + picomatch: ^2.3.1 + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 3cc5a6d91452a6eabbfd1ae79b4dd1f1e809d2eecda6e175deb784e75b0911f47e9ecce73f8dd315d6a8b3f362582c91d3c0f66908b6ced69345b3cbe28f8ce8 + languageName: node + linkType: hard + +"@rollup/rollup-android-arm-eabi@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.21.3" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@rollup/rollup-android-arm64@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-android-arm64@npm:4.21.3" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-arm64@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-darwin-arm64@npm:4.21.3" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-x64@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-darwin-x64@npm:4.21.3" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-gnueabihf@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.21.3" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-musleabihf@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.21.3" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-gnu@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.21.3" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-musl@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.21.3" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.21.3" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.21.3" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.21.3" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.21.3" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-musl@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.21.3" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-win32-arm64-msvc@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.21.3" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-ia32-msvc@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.21.3" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.21.3": + version: 4.21.3 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.21.3" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@sindresorhus/merge-streams@npm:^2.1.0": + version: 2.3.0 + resolution: "@sindresorhus/merge-streams@npm:2.3.0" + checksum: e989d53dee68d7e49b4ac02ae49178d561c461144cea83f66fa91ff012d981ad0ad2340cbd13f2fdb57989197f5c987ca22a74eb56478626f04e79df84291159 + languageName: node + linkType: hard + +"@taplo/cli@npm:^0.7.0": + version: 0.7.0 + resolution: "@taplo/cli@npm:0.7.0" + bin: + taplo: dist/cli.js + checksum: ec8e64e08c664961104e2d4abb8babd2bc5613b8c76444f02d2aec155e456af4c13e3e8dac86af8ab279cc5818d9cc094de71bd04c264d002f2a086fa6477b5f + languageName: node + linkType: hard + +"@tybys/wasm-util@npm:^0.9.0": + version: 0.9.0 + resolution: "@tybys/wasm-util@npm:0.9.0" + dependencies: + tslib: ^2.4.0 + checksum: 8d44c64e64e39c746e45b5dff7b534716f20e1f6e8fc206f8e4c8ac454ec0eb35b65646e446dd80745bc898db37a4eca549a936766d447c2158c9c43d44e7708 + languageName: node + linkType: hard + +"@types/estree@npm:*, @types/estree@npm:1.0.5, @types/estree@npm:^1.0.0": + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: dd8b5bed28e6213b7acd0fb665a84e693554d850b0df423ac8076cc3ad5823a6bc26b0251d080bdc545af83179ede51dd3f6fa78cad2c46ed1f29624ddf3e41a languageName: node linkType: hard @@ -122,6 +1605,15 @@ __metadata: languageName: node linkType: hard +"@types/mute-stream@npm:^0.0.4": + version: 0.0.4 + resolution: "@types/mute-stream@npm:0.0.4" + dependencies: + "@types/node": "*" + checksum: af8d83ad7b68ea05d9357985daf81b6c9b73af4feacb2f5c2693c7fd3e13e5135ef1bd083ce8d5bdc8e97acd28563b61bb32dec4e4508a8067fcd31b8a098632 + languageName: node + linkType: hard + "@types/node@npm:*": version: 20.6.2 resolution: "@types/node@npm:20.6.2" @@ -129,10 +1621,21 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^18.17.5": - version: 18.17.6 - resolution: "@types/node@npm:18.17.6" - checksum: 70bc92adde47d569f25c5ed40b55040cdf189518d6149e0c3041c6e60b1098cad9c48a856f0b7868ebd74d4098a0ca508b0ec4373dd96216eb8a387ee898e14c +"@types/node@npm:^20.16.4": + version: 20.16.4 + resolution: "@types/node@npm:20.16.4" + dependencies: + undici-types: ~6.19.2 + checksum: 533315175e2d46a38cb220e3fb41ecfb33625b95cae1120e001eab0aa23330ff02a4dc44e15fca39fd420a802da3b20b3e5d30a21daf5e4853ea48c16ec76a8e + languageName: node + linkType: hard + +"@types/node@npm:^22.5.2": + version: 22.5.4 + resolution: "@types/node@npm:22.5.4" + dependencies: + undici-types: ~6.19.2 + checksum: 77ac225c38c428200036780036da0bc6764e2721cfa8f528c7e7da7cfefe01a32a5791e28a54efbeedbc977949058d7db902b2e00139298225d4686cee4ae6db languageName: node linkType: hard @@ -146,11 +1649,47 @@ __metadata: languageName: node linkType: hard +"@types/resolve@npm:1.20.2": + version: 1.20.2 + resolution: "@types/resolve@npm:1.20.2" + checksum: 61c2cad2499ffc8eab36e3b773945d337d848d3ac6b7b0a87c805ba814bc838ef2f262fc0f109bfd8d2e0898ff8bd80ad1025f9ff64f1f71d3d4294c9f14e5f6 + languageName: node + linkType: hard + +"@types/wrap-ansi@npm:^3.0.0": + version: 3.0.0 + resolution: "@types/wrap-ansi@npm:3.0.0" + checksum: 492f0610093b5802f45ca292777679bb9b381f1f32ae939956dd9e00bf81dba7cc99979687620a2817d9a7d8b59928207698166c47a0861c6a2e5c30d4aaf1e9 + languageName: node + linkType: hard + +"@vercel/nft@npm:^0.26.2": + version: 0.26.5 + resolution: "@vercel/nft@npm:0.26.5" + dependencies: + "@mapbox/node-pre-gyp": ^1.0.5 + "@rollup/pluginutils": ^4.0.0 + acorn: ^8.6.0 + acorn-import-attributes: ^1.9.2 + async-sema: ^3.1.1 + bindings: ^1.4.0 + estree-walker: 2.0.2 + glob: ^7.1.3 + graceful-fs: ^4.2.9 + micromatch: ^4.0.2 + node-gyp-build: ^4.2.2 + resolve-from: ^5.0.0 + bin: + nft: out/cli.js + checksum: 0856c2a7d1c3e7f2bb624891570309a1ee06510338d45a7bc5517486f8c789d897e0783e1ee34782c905865b969f808bee53a145c748673b1a4bf9dd346f0788 + languageName: node + linkType: hard + "@y-octo/cli@workspace:.": version: 0.0.0-use.local resolution: "@y-octo/cli@workspace:." dependencies: - "@taplo/cli": ^0.5.2 + "@taplo/cli": ^0.7.0 husky: ^8.0.3 lint-staged: ^14.0.0 npm-run-all: ^4.1.5 @@ -162,30 +1701,94 @@ __metadata: version: 0.0.0-use.local resolution: "@y-octo/node@workspace:y-octo-node" dependencies: - "@napi-rs/cli": ^2.16.2 - "@types/node": ^18.17.5 + "@napi-rs/cli": ^3.0.0-alpha.62 + "@types/node": ^20.16.4 "@types/prompts": ^2.4.4 - c8: ^8.0.1 + ava: ^6.1.3 + c8: ^10.1.2 + pkgroll: ^2.5.0 prompts: ^2.4.2 - ts-node: ^10.9.2 + tsx: ^4.16.2 typescript: ^5.1.6 - yjs: ^13.6.8 + yjs: ^13.6.18 languageName: unknown linkType: soft -"acorn-walk@npm:^8.1.1": - version: 8.2.0 - resolution: "acorn-walk@npm:8.2.0" - checksum: 1715e76c01dd7b2d4ca472f9c58968516a4899378a63ad5b6c2d668bba8da21a71976c14ec5f5b75f887b6317c4ae0b897ab141c831d741dc76024d8745f1ad1 +"abbrev@npm:1": + version: 1.1.1 + resolution: "abbrev@npm:1.1.1" + checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 + languageName: node + linkType: hard + +"abbrev@npm:^2.0.0": + version: 2.0.0 + resolution: "abbrev@npm:2.0.0" + checksum: 0e994ad2aa6575f94670d8a2149afe94465de9cedaaaac364e7fb43a40c3691c980ff74899f682f4ca58fa96b4cbd7421a015d3a6defe43a442117d7821a2f36 + languageName: node + linkType: hard + +"acorn-import-attributes@npm:^1.9.2": + version: 1.9.5 + resolution: "acorn-import-attributes@npm:1.9.5" + peerDependencies: + acorn: ^8 + checksum: 1c0c49b6a244503964ae46ae850baccf306e84caf99bc2010ed6103c69a423987b07b520a6c619f075d215388bd4923eccac995886a54309eda049ab78a4be95 + languageName: node + linkType: hard + +"acorn-walk@npm:^8.3.2": + version: 8.3.3 + resolution: "acorn-walk@npm:8.3.3" + dependencies: + acorn: ^8.11.0 + checksum: 0f09d351fc30b69b2b9982bf33dc30f3d35a34e030e5f1ed3c49fc4e3814a192bf3101e4c30912a0595410f5e91bb70ddba011ea73398b3ecbfe41c7334c6dd0 languageName: node linkType: hard -"acorn@npm:^8.4.1": - version: 8.10.0 - resolution: "acorn@npm:8.10.0" +"acorn@npm:^8.11.0, acorn@npm:^8.11.3, acorn@npm:^8.6.0": + version: 8.12.1 + resolution: "acorn@npm:8.12.1" bin: acorn: bin/acorn - checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d + checksum: 677880034aee5bdf7434cc2d25b641d7bedb0b5ef47868a78dadabedccf58e1c5457526d9d8249cd253f2df087e081c3fe7d903b448d8e19e5131a3065b83c07 + languageName: node + linkType: hard + +"agent-base@npm:6": + version: 6.0.2 + resolution: "agent-base@npm:6.0.2" + dependencies: + debug: 4 + checksum: f52b6872cc96fd5f622071b71ef200e01c7c4c454ee68bc9accca90c98cfb39f2810e3e9aa330435835eedc8c23f4f8a15267f67c6e245d2b33757575bdac49d + languageName: node + linkType: hard + +"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": + version: 7.1.1 + resolution: "agent-base@npm:7.1.1" + dependencies: + debug: ^4.3.4 + checksum: 51c158769c5c051482f9ca2e6e1ec085ac72b5a418a9b31b4e82fe6c0a6699adb94c1c42d246699a587b3335215037091c79e0de512c516f73b6ea844202f037 + languageName: node + linkType: hard + +"aggregate-error@npm:^3.0.0": + version: 3.1.0 + resolution: "aggregate-error@npm:3.1.0" + dependencies: + clean-stack: ^2.0.0 + indent-string: ^4.0.0 + checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 + languageName: node + linkType: hard + +"ansi-escapes@npm:^4.3.2": + version: 4.3.2 + resolution: "ansi-escapes@npm:4.3.2" + dependencies: + type-fest: ^0.21.3 + checksum: 93111c42189c0a6bed9cdb4d7f2829548e943827ee8479c74d6e0b22ee127b2a21d3f8b5ca57723b8ef78ce011fbfc2784350eb2bde3ccfccf2f575fa8489815 languageName: node linkType: hard @@ -205,42 +1808,151 @@ __metadata: languageName: node linkType: hard -"ansi-regex@npm:^6.0.1": - version: 6.0.1 - resolution: "ansi-regex@npm:6.0.1" - checksum: 1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 +"ansi-regex@npm:^6.0.1": + version: 6.0.1 + resolution: "ansi-regex@npm:6.0.1" + checksum: 1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 + languageName: node + linkType: hard + +"ansi-styles@npm:^3.2.1": + version: 3.2.1 + resolution: "ansi-styles@npm:3.2.1" + dependencies: + color-convert: ^1.9.0 + checksum: d85ade01c10e5dd77b6c89f34ed7531da5830d2cb5882c645f330079975b716438cd7ebb81d0d6e6b4f9c577f19ae41ab55f07f19786b02f9dfd9e0377395665 + languageName: node + linkType: hard + +"ansi-styles@npm:^4.0.0": + version: 4.3.0 + resolution: "ansi-styles@npm:4.3.0" + dependencies: + color-convert: ^2.0.1 + checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 + languageName: node + linkType: hard + +"ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.1.0, ansi-styles@npm:^6.2.1": + version: 6.2.1 + resolution: "ansi-styles@npm:6.2.1" + checksum: ef940f2f0ced1a6347398da88a91da7930c33ecac3c77b72c5905f8b8fe402c52e6fde304ff5347f616e27a742da3f1dc76de98f6866c69251ad0b07a66776d9 + languageName: node + linkType: hard + +"aproba@npm:^1.0.3 || ^2.0.0": + version: 2.0.0 + resolution: "aproba@npm:2.0.0" + checksum: 5615cadcfb45289eea63f8afd064ab656006361020e1735112e346593856f87435e02d8dcc7ff0d11928bc7d425f27bc7c2a84f6c0b35ab0ff659c814c138a24 + languageName: node + linkType: hard + +"are-we-there-yet@npm:^2.0.0": + version: 2.0.0 + resolution: "are-we-there-yet@npm:2.0.0" + dependencies: + delegates: ^1.0.0 + readable-stream: ^3.6.0 + checksum: 6c80b4fd04ecee6ba6e737e0b72a4b41bdc64b7d279edfc998678567ff583c8df27e27523bc789f2c99be603ffa9eaa612803da1d886962d2086e7ff6fa90c7c + languageName: node + linkType: hard + +"argparse@npm:^1.0.7": + version: 1.0.10 + resolution: "argparse@npm:1.0.10" + dependencies: + sprintf-js: ~1.0.2 + checksum: 7ca6e45583a28de7258e39e13d81e925cfa25d7d4aacbf806a382d3c02fcb13403a07fb8aeef949f10a7cfe4a62da0e2e807b348a5980554cc28ee573ef95945 + languageName: node + linkType: hard + +"argparse@npm:^2.0.1": + version: 2.0.1 + resolution: "argparse@npm:2.0.1" + checksum: 83644b56493e89a254bae05702abf3a1101b4fa4d0ca31df1c9985275a5a5bd47b3c27b7fa0b71098d41114d8ca000e6ed90cad764b306f8a503665e4d517ced + languageName: node + linkType: hard + +"array-find-index@npm:^1.0.1": + version: 1.0.2 + resolution: "array-find-index@npm:1.0.2" + checksum: aac128bf369e1ac6c06ff0bb330788371c0e256f71279fb92d745e26fb4b9db8920e485b4ec25e841c93146bf71a34dcdbcefa115e7e0f96927a214d237b7081 languageName: node linkType: hard -"ansi-styles@npm:^3.2.1": - version: 3.2.1 - resolution: "ansi-styles@npm:3.2.1" - dependencies: - color-convert: ^1.9.0 - checksum: d85ade01c10e5dd77b6c89f34ed7531da5830d2cb5882c645f330079975b716438cd7ebb81d0d6e6b4f9c577f19ae41ab55f07f19786b02f9dfd9e0377395665 +"arrgv@npm:^1.0.2": + version: 1.0.2 + resolution: "arrgv@npm:1.0.2" + checksum: 470bbb406ea3b34810dd8b03c0b33282617a42d9fce0ab45d58596efefd042fc548eda49161fa8e3f607cbe9df90e7a67003a09043ab9081eff70f97c63dd0e2 languageName: node linkType: hard -"ansi-styles@npm:^4.0.0": - version: 4.3.0 - resolution: "ansi-styles@npm:4.3.0" - dependencies: - color-convert: ^2.0.1 - checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 +"arrify@npm:^3.0.0": + version: 3.0.0 + resolution: "arrify@npm:3.0.0" + checksum: d6c6f3dad9571234f320e130d57fddb2cc283c87f2ac7df6c7005dffc5161b7bb9376f4be655ed257050330336e84afc4f3020d77696ad231ff580a94ae5aba6 languageName: node linkType: hard -"ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.1.0": - version: 6.2.1 - resolution: "ansi-styles@npm:6.2.1" - checksum: ef940f2f0ced1a6347398da88a91da7930c33ecac3c77b72c5905f8b8fe402c52e6fde304ff5347f616e27a742da3f1dc76de98f6866c69251ad0b07a66776d9 +"async-sema@npm:^3.1.1": + version: 3.1.1 + resolution: "async-sema@npm:3.1.1" + checksum: 07b8c51f6cab107417ecdd8126b7a9fe5a75151b7f69fdd420dcc8ee08f9e37c473a217247e894b56e999b088b32e902dbe41637e4e9b594d3f8dfcdddfadc5e languageName: node linkType: hard -"arg@npm:^4.1.0": - version: 4.1.3 - resolution: "arg@npm:4.1.3" - checksum: 544af8dd3f60546d3e4aff084d451b96961d2267d668670199692f8d054f0415d86fc5497d0e641e91546f0aa920e7c29e5250e99fc89f5552a34b5d93b77f43 +"ava@npm:^6.1.3": + version: 6.1.3 + resolution: "ava@npm:6.1.3" + dependencies: + "@vercel/nft": ^0.26.2 + acorn: ^8.11.3 + acorn-walk: ^8.3.2 + ansi-styles: ^6.2.1 + arrgv: ^1.0.2 + arrify: ^3.0.0 + callsites: ^4.1.0 + cbor: ^9.0.1 + chalk: ^5.3.0 + chunkd: ^2.0.1 + ci-info: ^4.0.0 + ci-parallel-vars: ^1.0.1 + cli-truncate: ^4.0.0 + code-excerpt: ^4.0.0 + common-path-prefix: ^3.0.0 + concordance: ^5.0.4 + currently-unhandled: ^0.4.1 + debug: ^4.3.4 + emittery: ^1.0.1 + figures: ^6.0.1 + globby: ^14.0.0 + ignore-by-default: ^2.1.0 + indent-string: ^5.0.0 + is-plain-object: ^5.0.0 + is-promise: ^4.0.0 + matcher: ^5.0.0 + memoize: ^10.0.0 + ms: ^2.1.3 + p-map: ^7.0.1 + package-config: ^5.0.0 + picomatch: ^3.0.1 + plur: ^5.1.0 + pretty-ms: ^9.0.0 + resolve-cwd: ^3.0.0 + stack-utils: ^2.0.6 + strip-ansi: ^7.1.0 + supertap: ^3.0.1 + temp-dir: ^3.0.0 + write-file-atomic: ^5.0.1 + yargs: ^17.7.2 + peerDependencies: + "@ava/typescript": "*" + peerDependenciesMeta: + "@ava/typescript": + optional: true + bin: + ava: entrypoints/cli.mjs + checksum: a445de7b9b7ae73bd7f5b15114a2e6fdfc5675d4b2d65fef9c63b3ce4f1dc2a25e4827209c7eaf2e54490d3d7d8bc27eea3a8cfd08807a9d7fcf8ef035d1e143 languageName: node linkType: hard @@ -251,6 +1963,29 @@ __metadata: languageName: node linkType: hard +"before-after-hook@npm:^3.0.2": + version: 3.0.2 + resolution: "before-after-hook@npm:3.0.2" + checksum: 5f76a9d31909f7f1f7125b7e017ff018799308f5c1fc5a5bfeba9986149da77e6a5cdde0d151671cf374a7fa6452533237bb1de62dfd6c235c20e7c61cc9569d + languageName: node + linkType: hard + +"bindings@npm:^1.4.0": + version: 1.5.0 + resolution: "bindings@npm:1.5.0" + dependencies: + file-uri-to-path: 1.0.0 + checksum: 65b6b48095717c2e6105a021a7da4ea435aa8d3d3cd085cb9e85bcb6e5773cf318c4745c3f7c504412855940b585bdf9b918236612a1c7a7942491de176f1ae7 + languageName: node + linkType: hard + +"blueimp-md5@npm:^2.10.0": + version: 2.19.0 + resolution: "blueimp-md5@npm:2.19.0" + checksum: 28095dcbd2c67152a2938006e8d7c74c3406ba6556071298f872505432feb2c13241b0476644160ee0a5220383ba94cb8ccdac0053b51f68d168728f9c382530 + languageName: node + linkType: hard + "brace-expansion@npm:^1.1.7": version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" @@ -261,6 +1996,15 @@ __metadata: languageName: node linkType: hard +"brace-expansion@npm:^2.0.1": + version: 2.0.1 + resolution: "brace-expansion@npm:2.0.1" + dependencies: + balanced-match: ^1.0.0 + checksum: a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 + languageName: node + linkType: hard + "braces@npm:^3.0.2": version: 3.0.2 resolution: "braces@npm:3.0.2" @@ -270,29 +2014,85 @@ __metadata: languageName: node linkType: hard -"c8@npm:^8.0.1": - version: 8.0.1 - resolution: "c8@npm:8.0.1" +"braces@npm:^3.0.3": + version: 3.0.3 + resolution: "braces@npm:3.0.3" + dependencies: + fill-range: ^7.1.1 + checksum: b95aa0b3bd909f6cd1720ffcf031aeaf46154dd88b4da01f9a1d3f7ea866a79eba76a6d01cbc3c422b2ee5cdc39a4f02491058d5df0d7bf6e6a162a832df1f69 + languageName: node + linkType: hard + +"builtin-modules@npm:^3.3.0": + version: 3.3.0 + resolution: "builtin-modules@npm:3.3.0" + checksum: db021755d7ed8be048f25668fe2117620861ef6703ea2c65ed2779c9e3636d5c3b82325bd912244293959ff3ae303afa3471f6a15bf5060c103e4cc3a839749d + languageName: node + linkType: hard + +"c8@npm:^10.1.2": + version: 10.1.2 + resolution: "c8@npm:10.1.2" dependencies: "@bcoe/v8-coverage": ^0.2.3 "@istanbuljs/schema": ^0.1.3 find-up: ^5.0.0 - foreground-child: ^2.0.0 + foreground-child: ^3.1.1 istanbul-lib-coverage: ^3.2.0 istanbul-lib-report: ^3.0.1 istanbul-reports: ^3.1.6 - rimraf: ^3.0.2 - test-exclude: ^6.0.0 + test-exclude: ^7.0.1 v8-to-istanbul: ^9.0.0 yargs: ^17.7.2 yargs-parser: ^21.1.1 + peerDependencies: + monocart-coverage-reports: ^2 + peerDependenciesMeta: + monocart-coverage-reports: + optional: true bin: c8: bin/c8.js - checksum: 2c47531d21cb67b1e533fbb203ddb5a1c4b45d52c004dcf4eb1376ac8df205f2f4a1b2b9611777ca88dadbbcc2bbdad26b8c5f7ca58a02ecd52afa2aebef73fe + checksum: 8a07191df0ff7fa267ba7701967876cfb7e4f8f7fac7de6dfdf7b329b2d95e2ed1aeeacad5c8646d0c3aba44333e3b57414dbc4494263b06ffba46002450629f + languageName: node + linkType: hard + +"cacache@npm:^18.0.0": + version: 18.0.3 + resolution: "cacache@npm:18.0.3" + dependencies: + "@npmcli/fs": ^3.1.0 + fs-minipass: ^3.0.0 + glob: ^10.2.2 + lru-cache: ^10.0.1 + minipass: ^7.0.3 + minipass-collect: ^2.0.1 + minipass-flush: ^1.0.5 + minipass-pipeline: ^1.2.4 + p-map: ^4.0.0 + ssri: ^10.0.0 + tar: ^6.1.11 + unique-filename: ^3.0.0 + checksum: b717fd9b36e9c3279bfde4545c3a8f6d5a539b084ee26a9504d48f83694beb724057d26e090b97540f9cc62bea18b9f6cf671c50e18fb7dac60eda9db691714f + languageName: node + linkType: hard + +"callsites@npm:^4.1.0": + version: 4.2.0 + resolution: "callsites@npm:4.2.0" + checksum: 9a740675712076a38208967d7f80b525c9c7f4524c2af5d3936c5e278a601af0423a07e91f79679fec0546f3a52514d56969c6fe65f84d794e64a36b1f5eda8a + languageName: node + linkType: hard + +"cbor@npm:^9.0.1": + version: 9.0.2 + resolution: "cbor@npm:9.0.2" + dependencies: + nofilter: ^3.1.0 + checksum: 925edae7bf964be5a26dba1b7ba6311ac12b6a66234dc958958997a0576cdc740632dc19852a5b84d8a75101936bea1fe122dc22539d6e11f4539c731853ba2e languageName: node linkType: hard -"chalk@npm:5.3.0": +"chalk@npm:5.3.0, chalk@npm:^5.3.0": version: 5.3.0 resolution: "chalk@npm:5.3.0" checksum: 623922e077b7d1e9dedaea6f8b9e9352921f8ae3afe739132e0e00c275971bdd331268183b2628cf4ab1727c45ea1f28d7e24ac23ce1db1eb653c414ca8a5a80 @@ -310,6 +2110,48 @@ __metadata: languageName: node linkType: hard +"chardet@npm:^0.7.0": + version: 0.7.0 + resolution: "chardet@npm:0.7.0" + checksum: 6fd5da1f5d18ff5712c1e0aed41da200d7c51c28f11b36ee3c7b483f3696dabc08927fc6b227735eb8f0e1215c9a8abd8154637f3eff8cada5959df7f58b024d + languageName: node + linkType: hard + +"chownr@npm:^2.0.0": + version: 2.0.0 + resolution: "chownr@npm:2.0.0" + checksum: c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f + languageName: node + linkType: hard + +"chunkd@npm:^2.0.1": + version: 2.0.1 + resolution: "chunkd@npm:2.0.1" + checksum: bab8cc08c752a3648984385dc6f61d751e89dbeef648d22a3b661e1d470eaa0f5182f0b4303710f13ae83d2f85144f8eb2dde7a975861d9021b5c56b881f457b + languageName: node + linkType: hard + +"ci-info@npm:^4.0.0": + version: 4.0.0 + resolution: "ci-info@npm:4.0.0" + checksum: 122fe41c5eb8d0b5fa0ab6fd674c5ddcf2dc59766528b062a0144ff0d913cfb210ef925ec52110e7c2a7f4e603d5f0e8b91cfe68867e196e9212fa0b94d0a08a + languageName: node + linkType: hard + +"ci-parallel-vars@npm:^1.0.1": + version: 1.0.1 + resolution: "ci-parallel-vars@npm:1.0.1" + checksum: ae859831f7e8e3585db731b8306c336616e37bd709dad1d7775ea4c0731aefd94741dabb48201edc6827d000008fd7fb72cb977967614ee2d99d6b499f0c35fe + languageName: node + linkType: hard + +"clean-stack@npm:^2.0.0": + version: 2.2.0 + resolution: "clean-stack@npm:2.2.0" + checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 + languageName: node + linkType: hard + "cli-cursor@npm:^4.0.0": version: 4.0.0 resolution: "cli-cursor@npm:4.0.0" @@ -319,6 +2161,13 @@ __metadata: languageName: node linkType: hard +"cli-spinners@npm:^2.9.2": + version: 2.9.2 + resolution: "cli-spinners@npm:2.9.2" + checksum: 1bd588289b28432e4676cb5d40505cfe3e53f2e4e10fbe05c8a710a154d6fe0ce7836844b00d6858f740f2ffe67cdc36e0fce9c7b6a8430e80e6388d5aa4956c + languageName: node + linkType: hard + "cli-truncate@npm:^3.1.0": version: 3.1.0 resolution: "cli-truncate@npm:3.1.0" @@ -329,6 +2178,34 @@ __metadata: languageName: node linkType: hard +"cli-truncate@npm:^4.0.0": + version: 4.0.0 + resolution: "cli-truncate@npm:4.0.0" + dependencies: + slice-ansi: ^5.0.0 + string-width: ^7.0.0 + checksum: d5149175fd25ca985731bdeec46a55ec237475cf74c1a5e103baea696aceb45e372ac4acbaabf1316f06bd62e348123060f8191ffadfeedebd2a70a2a7fb199d + languageName: node + linkType: hard + +"cli-width@npm:^4.1.0": + version: 4.1.0 + resolution: "cli-width@npm:4.1.0" + checksum: 0a79cff2dbf89ef530bcd54c713703ba94461457b11e5634bd024c78796ed21401e32349c004995954e06f442d82609287e7aabf6a5f02c919a1cf3b9b6854ff + languageName: node + linkType: hard + +"clipanion@npm:^3.2.1": + version: 3.2.1 + resolution: "clipanion@npm:3.2.1" + dependencies: + typanion: ^3.8.0 + peerDependencies: + typanion: "*" + checksum: 448efd122ead3c802e61ba7a2002e2080c8cce01ce8a0a789d9b9e4f8fe70fd887dcf163ef8c778f5364a9e6f4b498b9f1853f709d7ed4291713e78bcfb88ee8 + languageName: node + linkType: hard + "cliui@npm:^8.0.1": version: 8.0.1 resolution: "cliui@npm:8.0.1" @@ -340,6 +2217,15 @@ __metadata: languageName: node linkType: hard +"code-excerpt@npm:^4.0.0": + version: 4.0.0 + resolution: "code-excerpt@npm:4.0.0" + dependencies: + convert-to-spaces: ^2.0.1 + checksum: d57137d8f4825879283a828cc02a1115b56858dc54ed06c625c8f67d6685d1becd2fbaa7f0ab19ecca1f5cca03f8c97bbc1f013cab40261e4d3275032e65efe9 + languageName: node + linkType: hard + "color-convert@npm:^1.9.0": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -372,6 +2258,15 @@ __metadata: languageName: node linkType: hard +"color-support@npm:^1.1.2": + version: 1.1.3 + resolution: "color-support@npm:1.1.3" + bin: + color-support: bin.js + checksum: 9b7356817670b9a13a26ca5af1c21615463b500783b739b7634a0c2047c16cef4b2865d7576875c31c3cddf9dd621fa19285e628f20198b233a5cfdda6d0793b + languageName: node + linkType: hard + "colorette@npm:^2.0.20": version: 2.0.20 resolution: "colorette@npm:2.0.20" @@ -386,6 +2281,20 @@ __metadata: languageName: node linkType: hard +"common-path-prefix@npm:^3.0.0": + version: 3.0.0 + resolution: "common-path-prefix@npm:3.0.0" + checksum: fdb3c4f54e51e70d417ccd950c07f757582de800c0678ca388aedefefc84982039f346f9fd9a1252d08d2da9e9ef4019f580a1d1d3a10da031e4bb3c924c5818 + languageName: node + linkType: hard + +"commondir@npm:^1.0.1": + version: 1.0.1 + resolution: "commondir@npm:1.0.1" + checksum: 59715f2fc456a73f68826285718503340b9f0dd89bfffc42749906c5cf3d4277ef11ef1cca0350d0e79204f00f1f6d83851ececc9095dc88512a697ac0b9bdcb + languageName: node + linkType: hard + "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -393,6 +2302,29 @@ __metadata: languageName: node linkType: hard +"concordance@npm:^5.0.4": + version: 5.0.4 + resolution: "concordance@npm:5.0.4" + dependencies: + date-time: ^3.1.0 + esutils: ^2.0.3 + fast-diff: ^1.2.0 + js-string-escape: ^1.0.1 + lodash: ^4.17.15 + md5-hex: ^3.0.1 + semver: ^7.3.2 + well-known-symbols: ^2.0.0 + checksum: 749153ba711492feb7c3d2f5bb04c107157440b3e39509bd5dd19ee7b3ac751d1e4cd75796d9f702e0a713312dbc661421c68aa4a2c34d5f6d91f47e3a1c64a6 + languageName: node + linkType: hard + +"console-control-strings@npm:^1.0.0, console-control-strings@npm:^1.1.0": + version: 1.1.0 + resolution: "console-control-strings@npm:1.1.0" + checksum: 8755d76787f94e6cf79ce4666f0c5519906d7f5b02d4b884cf41e11dcd759ed69c57da0670afd9236d229a46e0f9cf519db0cd829c6dca820bb5a5c3def584ed + languageName: node + linkType: hard + "convert-source-map@npm:^1.6.0": version: 1.9.0 resolution: "convert-source-map@npm:1.9.0" @@ -400,10 +2332,10 @@ __metadata: languageName: node linkType: hard -"create-require@npm:^1.1.0": - version: 1.1.1 - resolution: "create-require@npm:1.1.1" - checksum: a9a1503d4390d8b59ad86f4607de7870b39cad43d929813599a23714831e81c520bddf61bcdd1f8e30f05fd3a2b71ae8538e946eb2786dc65c2bbc520f692eff +"convert-to-spaces@npm:^2.0.1": + version: 2.0.1 + resolution: "convert-to-spaces@npm:2.0.1" + checksum: bbb324e5916fe9866f65c0ff5f9c1ea933764d0bdb09fccaf59542e40545ed483db6b2339c6d9eb56a11965a58f1a6038f3174f0e2fb7601343c7107ca5e2751 languageName: node linkType: hard @@ -431,66 +2363,360 @@ __metadata: languageName: node linkType: hard +"currently-unhandled@npm:^0.4.1": + version: 0.4.1 + resolution: "currently-unhandled@npm:0.4.1" + dependencies: + array-find-index: ^1.0.1 + checksum: 1f59fe10b5339b54b1a1eee110022f663f3495cf7cf2f480686e89edc7fa8bfe42dbab4b54f85034bc8b092a76cc7becbc2dad4f9adad332ab5831bec39ad540 + languageName: node + linkType: hard + +"date-time@npm:^3.1.0": + version: 3.1.0 + resolution: "date-time@npm:3.1.0" + dependencies: + time-zone: ^1.0.0 + checksum: f9cfcd1b15dfeabab15c0b9d18eb9e4e2d9d4371713564178d46a8f91ad577a290b5178b80050718d02d9c0cf646f8a875011e12d1ed05871e9f72c72c8a8fe6 + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:^4.3.4": + version: 4.3.5 + resolution: "debug@npm:4.3.5" + dependencies: + ms: 2.1.2 + peerDependenciesMeta: + supports-color: + optional: true + checksum: 7c002b51e256257f936dda09eb37167df952758c57badf6bf44bdc40b89a4bcb8e5a0a2e4c7b53f97c69e2970dd5272d33a757378a12c8f8e64ea7bf99e8e86e + languageName: node + linkType: hard + "debug@npm:4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: - ms: 2.1.2 - peerDependenciesMeta: - supports-color: + ms: 2.1.2 + peerDependenciesMeta: + supports-color: + optional: true + checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 + languageName: node + linkType: hard + +"deepmerge@npm:^4.2.2": + version: 4.3.1 + resolution: "deepmerge@npm:4.3.1" + checksum: 2024c6a980a1b7128084170c4cf56b0fd58a63f2da1660dcfe977415f27b17dbe5888668b59d0b063753f3220719d5e400b7f113609489c90160bb9a5518d052 + languageName: node + linkType: hard + +"delegates@npm:^1.0.0": + version: 1.0.0 + resolution: "delegates@npm:1.0.0" + checksum: a51744d9b53c164ba9c0492471a1a2ffa0b6727451bdc89e31627fdf4adda9d51277cfcbfb20f0a6f08ccb3c436f341df3e92631a3440226d93a8971724771fd + languageName: node + linkType: hard + +"detect-libc@npm:^2.0.0": + version: 2.0.3 + resolution: "detect-libc@npm:2.0.3" + checksum: 2ba6a939ae55f189aea996ac67afceb650413c7a34726ee92c40fb0deb2400d57ef94631a8a3f052055eea7efb0f99a9b5e6ce923415daa3e68221f963cfc27d + languageName: node + linkType: hard + +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 7d00d7cd8e49b9afa762a813faac332dee781932d6f2c848dc348939c4253f1d4564341b7af1d041853bc3f32c2ef141b58e0a4d9862c17a7f08f68df1e0f1ed + languageName: node + linkType: hard + +"emittery@npm:^1.0.1": + version: 1.0.3 + resolution: "emittery@npm:1.0.3" + checksum: c9e760431294a546dacc236e563ee29cc650374696ef5f824a465a4a7c584ca2c0046885a3e5d7cd3d9592713200c82f4a4ded11d0b49c06cb5bb587dedc46b4 + languageName: node + linkType: hard + +"emnapi@npm:^1.2.0": + version: 1.2.0 + resolution: "emnapi@npm:1.2.0" + peerDependencies: + node-addon-api: ">= 6.1.0" + peerDependenciesMeta: + node-addon-api: + optional: true + checksum: ea9df8c47dbf1d9f2b9d92b6e7cb334267bfd27b835403cbc47627fe5a9beddf00fed343ccbe2940a37e634813dfdba80016cba1f518fa25a7e3e482d4a98753 + languageName: node + linkType: hard + +"emoji-regex@npm:^10.3.0": + version: 10.3.0 + resolution: "emoji-regex@npm:10.3.0" + checksum: 5da48edfeb9462fb1ae5495cff2d79129974c696853fb0ce952cbf560f29a2756825433bf51cfd5157ec7b9f93f46f31d712e896d63e3d8ac9c3832bdb45ab73 + languageName: node + linkType: hard + +"emoji-regex@npm:^8.0.0": + version: 8.0.0 + resolution: "emoji-regex@npm:8.0.0" + checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 + languageName: node + linkType: hard + +"emoji-regex@npm:^9.2.2": + version: 9.2.2 + resolution: "emoji-regex@npm:9.2.2" + checksum: 8487182da74aabd810ac6d6f1994111dfc0e331b01271ae01ec1eb0ad7b5ecc2bbbbd2f053c05cb55a1ac30449527d819bbfbf0e3de1023db308cbcb47f86601 + languageName: node + linkType: hard + +"encoding@npm:^0.1.13": + version: 0.1.13 + resolution: "encoding@npm:0.1.13" + dependencies: + iconv-lite: ^0.6.2 + checksum: bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f + languageName: node + linkType: hard + +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e + languageName: node + linkType: hard + +"err-code@npm:^2.0.2": + version: 2.0.3 + resolution: "err-code@npm:2.0.3" + checksum: 8b7b1be20d2de12d2255c0bc2ca638b7af5171142693299416e6a9339bd7d88fc8d7707d913d78e0993176005405a236b066b45666b27b797252c771156ace54 + languageName: node + linkType: hard + +"error-ex@npm:^1.3.1": + version: 1.3.2 + resolution: "error-ex@npm:1.3.2" + dependencies: + is-arrayish: ^0.2.1 + checksum: c1c2b8b65f9c91b0f9d75f0debaa7ec5b35c266c2cac5de412c1a6de86d4cbae04ae44e510378cb14d032d0645a36925d0186f8bb7367bcc629db256b743a001 + languageName: node + linkType: hard + +"esbuild@npm:^0.23.0": + version: 0.23.1 + resolution: "esbuild@npm:0.23.1" + dependencies: + "@esbuild/aix-ppc64": 0.23.1 + "@esbuild/android-arm": 0.23.1 + "@esbuild/android-arm64": 0.23.1 + "@esbuild/android-x64": 0.23.1 + "@esbuild/darwin-arm64": 0.23.1 + "@esbuild/darwin-x64": 0.23.1 + "@esbuild/freebsd-arm64": 0.23.1 + "@esbuild/freebsd-x64": 0.23.1 + "@esbuild/linux-arm": 0.23.1 + "@esbuild/linux-arm64": 0.23.1 + "@esbuild/linux-ia32": 0.23.1 + "@esbuild/linux-loong64": 0.23.1 + "@esbuild/linux-mips64el": 0.23.1 + "@esbuild/linux-ppc64": 0.23.1 + "@esbuild/linux-riscv64": 0.23.1 + "@esbuild/linux-s390x": 0.23.1 + "@esbuild/linux-x64": 0.23.1 + "@esbuild/netbsd-x64": 0.23.1 + "@esbuild/openbsd-arm64": 0.23.1 + "@esbuild/openbsd-x64": 0.23.1 + "@esbuild/sunos-x64": 0.23.1 + "@esbuild/win32-arm64": 0.23.1 + "@esbuild/win32-ia32": 0.23.1 + "@esbuild/win32-x64": 0.23.1 + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 0413c3b9257327fb598427688b7186ea335bf1693746fe5713cc93c95854d6388b8ed4ad643fddf5b5ace093f7dcd9038dd58e087bf2da1f04dfb4c5571660af + languageName: node + linkType: hard + +"esbuild@npm:~0.21.5": + version: 0.21.5 + resolution: "esbuild@npm:0.21.5" + dependencies: + "@esbuild/aix-ppc64": 0.21.5 + "@esbuild/android-arm": 0.21.5 + "@esbuild/android-arm64": 0.21.5 + "@esbuild/android-x64": 0.21.5 + "@esbuild/darwin-arm64": 0.21.5 + "@esbuild/darwin-x64": 0.21.5 + "@esbuild/freebsd-arm64": 0.21.5 + "@esbuild/freebsd-x64": 0.21.5 + "@esbuild/linux-arm": 0.21.5 + "@esbuild/linux-arm64": 0.21.5 + "@esbuild/linux-ia32": 0.21.5 + "@esbuild/linux-loong64": 0.21.5 + "@esbuild/linux-mips64el": 0.21.5 + "@esbuild/linux-ppc64": 0.21.5 + "@esbuild/linux-riscv64": 0.21.5 + "@esbuild/linux-s390x": 0.21.5 + "@esbuild/linux-x64": 0.21.5 + "@esbuild/netbsd-x64": 0.21.5 + "@esbuild/openbsd-x64": 0.21.5 + "@esbuild/sunos-x64": 0.21.5 + "@esbuild/win32-arm64": 0.21.5 + "@esbuild/win32-ia32": 0.21.5 + "@esbuild/win32-x64": 0.21.5 + dependenciesMeta: + "@esbuild/aix-ppc64": optional: true - checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 2911c7b50b23a9df59a7d6d4cdd3a4f85855787f374dce751148dbb13305e0ce7e880dde1608c2ab7a927fc6cec3587b80995f7fc87a64b455f8b70b55fd8ec1 languageName: node linkType: hard -"diff@npm:^4.0.1": - version: 4.0.2 - resolution: "diff@npm:4.0.2" - checksum: f2c09b0ce4e6b301c221addd83bf3f454c0bc00caa3dd837cf6c127d6edf7223aa2bbe3b688feea110b7f262adbfc845b757c44c8a9f8c0c5b15d8fa9ce9d20d +"escalade@npm:^3.1.1": + version: 3.1.1 + resolution: "escalade@npm:3.1.1" + checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133 languageName: node linkType: hard -"eastasianwidth@npm:^0.2.0": - version: 0.2.0 - resolution: "eastasianwidth@npm:0.2.0" - checksum: 7d00d7cd8e49b9afa762a813faac332dee781932d6f2c848dc348939c4253f1d4564341b7af1d041853bc3f32c2ef141b58e0a4d9862c17a7f08f68df1e0f1ed +"escape-string-regexp@npm:^1.0.5": + version: 1.0.5 + resolution: "escape-string-regexp@npm:1.0.5" + checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 languageName: node linkType: hard -"emoji-regex@npm:^8.0.0": - version: 8.0.0 - resolution: "emoji-regex@npm:8.0.0" - checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 +"escape-string-regexp@npm:^2.0.0": + version: 2.0.0 + resolution: "escape-string-regexp@npm:2.0.0" + checksum: 9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 languageName: node linkType: hard -"emoji-regex@npm:^9.2.2": - version: 9.2.2 - resolution: "emoji-regex@npm:9.2.2" - checksum: 8487182da74aabd810ac6d6f1994111dfc0e331b01271ae01ec1eb0ad7b5ecc2bbbbd2f053c05cb55a1ac30449527d819bbfbf0e3de1023db308cbcb47f86601 +"escape-string-regexp@npm:^5.0.0": + version: 5.0.0 + resolution: "escape-string-regexp@npm:5.0.0" + checksum: 20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e languageName: node linkType: hard -"error-ex@npm:^1.3.1": - version: 1.3.2 - resolution: "error-ex@npm:1.3.2" - dependencies: - is-arrayish: ^0.2.1 - checksum: c1c2b8b65f9c91b0f9d75f0debaa7ec5b35c266c2cac5de412c1a6de86d4cbae04ae44e510378cb14d032d0645a36925d0186f8bb7367bcc629db256b743a001 +"esprima@npm:^4.0.0": + version: 4.0.1 + resolution: "esprima@npm:4.0.1" + bin: + esparse: ./bin/esparse.js + esvalidate: ./bin/esvalidate.js + checksum: b45bc805a613dbea2835278c306b91aff6173c8d034223fa81498c77dcbce3b2931bf6006db816f62eacd9fd4ea975dfd85a5b7f3c6402cfd050d4ca3c13a628 languageName: node linkType: hard -"escalade@npm:^3.1.1": - version: 3.1.1 - resolution: "escalade@npm:3.1.1" - checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133 +"estree-walker@npm:2.0.2, estree-walker@npm:^2.0.1, estree-walker@npm:^2.0.2": + version: 2.0.2 + resolution: "estree-walker@npm:2.0.2" + checksum: 6151e6f9828abe2259e57f5fd3761335bb0d2ebd76dc1a01048ccee22fabcfef3c0859300f6d83ff0d1927849368775ec5a6d265dde2f6de5a1be1721cd94efc languageName: node linkType: hard -"escape-string-regexp@npm:^1.0.5": - version: 1.0.5 - resolution: "escape-string-regexp@npm:1.0.5" - checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 +"esutils@npm:^2.0.3": + version: 2.0.3 + resolution: "esutils@npm:2.0.3" + checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87 languageName: node linkType: hard @@ -518,6 +2744,69 @@ __metadata: languageName: node linkType: hard +"exponential-backoff@npm:^3.1.1": + version: 3.1.1 + resolution: "exponential-backoff@npm:3.1.1" + checksum: 3d21519a4f8207c99f7457287291316306255a328770d320b401114ec8481986e4e467e854cb9914dd965e0a1ca810a23ccb559c642c88f4c7f55c55778a9b48 + languageName: node + linkType: hard + +"external-editor@npm:^3.1.0": + version: 3.1.0 + resolution: "external-editor@npm:3.1.0" + dependencies: + chardet: ^0.7.0 + iconv-lite: ^0.4.24 + tmp: ^0.0.33 + checksum: 1c2a616a73f1b3435ce04030261bed0e22d4737e14b090bb48e58865da92529c9f2b05b893de650738d55e692d071819b45e1669259b2b354bc3154d27a698c7 + languageName: node + linkType: hard + +"fast-diff@npm:^1.2.0": + version: 1.3.0 + resolution: "fast-diff@npm:1.3.0" + checksum: d22d371b994fdc8cce9ff510d7b8dc4da70ac327bcba20df607dd5b9cae9f908f4d1028f5fe467650f058d1e7270235ae0b8230809a262b4df587a3b3aa216c3 + languageName: node + linkType: hard + +"fast-glob@npm:^3.3.2": + version: 3.3.2 + resolution: "fast-glob@npm:3.3.2" + dependencies: + "@nodelib/fs.stat": ^2.0.2 + "@nodelib/fs.walk": ^1.2.3 + glob-parent: ^5.1.2 + merge2: ^1.3.0 + micromatch: ^4.0.4 + checksum: 900e4979f4dbc3313840078419245621259f349950411ca2fa445a2f9a1a6d98c3b5e7e0660c5ccd563aa61abe133a21765c6c0dec8e57da1ba71d8000b05ec1 + languageName: node + linkType: hard + +"fastq@npm:^1.6.0": + version: 1.17.1 + resolution: "fastq@npm:1.17.1" + dependencies: + reusify: ^1.0.4 + checksum: a8c5b26788d5a1763f88bae56a8ddeee579f935a831c5fe7a8268cea5b0a91fbfe705f612209e02d639b881d7b48e461a50da4a10cfaa40da5ca7cc9da098d88 + languageName: node + linkType: hard + +"figures@npm:^6.0.1": + version: 6.1.0 + resolution: "figures@npm:6.1.0" + dependencies: + is-unicode-supported: ^2.0.0 + checksum: 35c81239d4fa40b75c2c7c010833b0bc8861c27187e4c9388fca1d9731103ec9989b70ee3b664ef426ddd9abe02ec5f4fd973424aa8c6fd3ea5d3bf57a2d01b4 + languageName: node + linkType: hard + +"file-uri-to-path@npm:1.0.0": + version: 1.0.0 + resolution: "file-uri-to-path@npm:1.0.0" + checksum: b648580bdd893a008c92c7ecc96c3ee57a5e7b6c4c18a9a09b44fb5d36d79146f8e442578bc0e173dc027adf3987e254ba1dfd6e3ec998b7c282873010502144 + languageName: node + linkType: hard + "fill-range@npm:^7.0.1": version: 7.0.1 resolution: "fill-range@npm:7.0.1" @@ -527,6 +2816,22 @@ __metadata: languageName: node linkType: hard +"fill-range@npm:^7.1.1": + version: 7.1.1 + resolution: "fill-range@npm:7.1.1" + dependencies: + to-regex-range: ^5.0.1 + checksum: b4abfbca3839a3d55e4ae5ec62e131e2e356bf4859ce8480c64c4876100f4df292a63e5bb1618e1d7460282ca2b305653064f01654474aa35c68000980f17798 + languageName: node + linkType: hard + +"find-up-simple@npm:^1.0.0": + version: 1.0.0 + resolution: "find-up-simple@npm:1.0.0" + checksum: 91c3d51c1111b5eb4e6e6d71d21438f6571a37a69dc288d4222b98996756e2f472fa5393a4dddb5e1a84929405d87e86f4bdce798ba84ee513b79854960ec140 + languageName: node + linkType: hard + "find-up@npm:^5.0.0": version: 5.0.0 resolution: "find-up@npm:5.0.0" @@ -537,13 +2842,41 @@ __metadata: languageName: node linkType: hard -"foreground-child@npm:^2.0.0": - version: 2.0.0 - resolution: "foreground-child@npm:2.0.0" +"foreground-child@npm:^3.1.0": + version: 3.2.1 + resolution: "foreground-child@npm:3.2.1" dependencies: cross-spawn: ^7.0.0 - signal-exit: ^3.0.2 - checksum: f77ec9aff621abd6b754cb59e690743e7639328301fbea6ff09df27d2befaf7dd5b77cec51c32323d73a81a7d91caaf9413990d305cbe3d873eec4fe58960956 + signal-exit: ^4.0.1 + checksum: 3e2e844d6003c96d70affe8ae98d7eaaba269a868c14d997620c088340a8775cd5d2d9043e6ceebae1928d8d9a874911c4d664b9a267e8995945df20337aebc0 + languageName: node + linkType: hard + +"foreground-child@npm:^3.1.1": + version: 3.3.0 + resolution: "foreground-child@npm:3.3.0" + dependencies: + cross-spawn: ^7.0.0 + signal-exit: ^4.0.1 + checksum: 1989698488f725b05b26bc9afc8a08f08ec41807cd7b92ad85d96004ddf8243fd3e79486b8348c64a3011ae5cc2c9f0936af989e1f28339805d8bc178a75b451 + languageName: node + linkType: hard + +"fs-minipass@npm:^2.0.0": + version: 2.1.0 + resolution: "fs-minipass@npm:2.1.0" + dependencies: + minipass: ^3.0.0 + checksum: 1b8d128dae2ac6cc94230cc5ead341ba3e0efaef82dab46a33d171c044caaa6ca001364178d42069b2809c35a1c3c35079a32107c770e9ffab3901b59af8c8b1 + languageName: node + linkType: hard + +"fs-minipass@npm:^3.0.0": + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" + dependencies: + minipass: ^7.0.3 + checksum: 8722a41109130851d979222d3ec88aabaceeaaf8f57b2a8f744ef8bd2d1ce95453b04a61daa0078822bc5cd21e008814f06fe6586f56fef511e71b8d2394d802 languageName: node linkType: hard @@ -554,6 +2887,42 @@ __metadata: languageName: node linkType: hard +"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" + dependencies: + node-gyp: latest + checksum: 11e6ea6fea15e42461fc55b4b0e4a0a3c654faa567f1877dbd353f39156f69def97a69936d1746619d656c4b93de2238bf731f6085a03a50cabf287c9d024317 + conditions: os=darwin + languageName: node + linkType: hard + +"fsevents@patch:fsevents@~2.3.2#~builtin, fsevents@patch:fsevents@~2.3.3#~builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#~builtin::version=2.3.3&hash=df0bf1" + dependencies: + node-gyp: latest + conditions: os=darwin + languageName: node + linkType: hard + +"gauge@npm:^3.0.0": + version: 3.0.2 + resolution: "gauge@npm:3.0.2" + dependencies: + aproba: ^1.0.3 || ^2.0.0 + color-support: ^1.1.2 + console-control-strings: ^1.0.0 + has-unicode: ^2.0.1 + object-assign: ^4.1.1 + signal-exit: ^3.0.0 + string-width: ^4.2.3 + strip-ansi: ^6.0.1 + wide-align: ^1.1.2 + checksum: 81296c00c7410cdd48f997800155fbead4f32e4f82109be0719c63edc8560e6579946cc8abd04205297640691ec26d21b578837fd13a4e96288ab4b40b1dc3e9 + languageName: node + linkType: hard + "get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" @@ -561,6 +2930,13 @@ __metadata: languageName: node linkType: hard +"get-east-asian-width@npm:^1.0.0": + version: 1.2.0 + resolution: "get-east-asian-width@npm:1.2.0" + checksum: ea55f4d4a42c4b00d3d9be3111bc17eb0161f60ed23fc257c1390323bb780a592d7a8bdd550260fd4627dabee9a118cdfa3475ae54edca35ebcd3bdae04179e3 + languageName: node + linkType: hard + "get-stream@npm:^6.0.1": version: 6.0.1 resolution: "get-stream@npm:6.0.1" @@ -568,7 +2944,57 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.1.3, glob@npm:^7.1.4": +"get-tsconfig@npm:^4.7.5": + version: 4.7.5 + resolution: "get-tsconfig@npm:4.7.5" + dependencies: + resolve-pkg-maps: ^1.0.0 + checksum: e5b271fae2b4cd1869bbfc58db56983026cc4a08fdba988725a6edd55d04101507de154722503a22ee35920898ff9bdcba71f99d93b17df35dddb8e8a2ad91be + languageName: node + linkType: hard + +"glob-parent@npm:^5.1.2": + version: 5.1.2 + resolution: "glob-parent@npm:5.1.2" + dependencies: + is-glob: ^4.0.1 + checksum: f4f2bfe2425296e8a47e36864e4f42be38a996db40420fe434565e4480e3322f18eb37589617a98640c5dc8fdec1a387007ee18dbb1f3f5553409c34d17f425e + languageName: node + linkType: hard + +"glob@npm:^10.2.2, glob@npm:^10.3.10": + version: 10.4.2 + resolution: "glob@npm:10.4.2" + dependencies: + foreground-child: ^3.1.0 + jackspeak: ^3.1.2 + minimatch: ^9.0.4 + minipass: ^7.1.2 + package-json-from-dist: ^1.0.0 + path-scurry: ^1.11.1 + bin: + glob: dist/esm/bin.mjs + checksum: bd7c0e30701136e936f414e5f6f82c7f04503f01df77408f177aa584927412f0bde0338e6ec541618cd21eacc57dde33e7b3c6c0a779cc1c6e6a0e14f3d15d9b + languageName: node + linkType: hard + +"glob@npm:^10.4.1": + version: 10.4.5 + resolution: "glob@npm:10.4.5" + dependencies: + foreground-child: ^3.1.0 + jackspeak: ^3.1.2 + minimatch: ^9.0.4 + minipass: ^7.1.2 + package-json-from-dist: ^1.0.0 + path-scurry: ^1.11.1 + bin: + glob: dist/esm/bin.mjs + checksum: 0bc725de5e4862f9f387fd0f2b274baf16850dcd2714502ccf471ee401803997983e2c05590cb65f9675a3c6f2a58e7a53f9e365704108c6ad3cbf1d60934c4a + languageName: node + linkType: hard + +"glob@npm:^7.1.3": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -582,7 +3008,21 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.2": +"globby@npm:^14.0.0": + version: 14.0.2 + resolution: "globby@npm:14.0.2" + dependencies: + "@sindresorhus/merge-streams": ^2.1.0 + fast-glob: ^3.3.2 + ignore: ^5.2.4 + path-type: ^5.0.0 + slash: ^5.1.0 + unicorn-magic: ^0.1.0 + checksum: 2cee79efefca4383a825fc2fcbdb37e5706728f2d39d4b63851927c128fff62e6334ef7d4d467949d411409ad62767dc2d214e0f837a0f6d4b7290b6711d485c + languageName: node + linkType: hard + +"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 @@ -603,12 +3043,10 @@ __metadata: languageName: node linkType: hard -"has@npm:@nolyfill/has@latest": - version: 1.0.20 - resolution: "@nolyfill/has@npm:1.0.20" - dependencies: - "@nolyfill/shared": 1.0.20 - checksum: b92b5b617a90b210cb84ecffae2dc407e087b83fcbe8658f7b422b21e93ba874d807c395e2d18a2efe93b13f9430fdebd0f2aa27bf641be78a66f79a6f536578 +"has-unicode@npm:^2.0.1": + version: 2.0.1 + resolution: "has-unicode@npm:2.0.1" + checksum: 1eab07a7436512db0be40a710b29b5dc21fa04880b7f63c9980b706683127e3c1b57cb80ea96d47991bdae2dfe479604f6a1ba410106ee1046a41d1bd0814400 languageName: node linkType: hard @@ -626,6 +3064,43 @@ __metadata: languageName: node linkType: hard +"http-cache-semantics@npm:^4.1.1": + version: 4.1.1 + resolution: "http-cache-semantics@npm:4.1.1" + checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 + languageName: node + linkType: hard + +"http-proxy-agent@npm:^7.0.0": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" + dependencies: + agent-base: ^7.1.0 + debug: ^4.3.4 + checksum: 670858c8f8f3146db5889e1fa117630910101db601fff7d5a8aa637da0abedf68c899f03d3451cac2f83bcc4c3d2dabf339b3aa00ff8080571cceb02c3ce02f3 + languageName: node + linkType: hard + +"https-proxy-agent@npm:^5.0.0": + version: 5.0.1 + resolution: "https-proxy-agent@npm:5.0.1" + dependencies: + agent-base: 6 + debug: 4 + checksum: 571fccdf38184f05943e12d37d6ce38197becdd69e58d03f43637f7fa1269cf303a7d228aa27e5b27bbd3af8f09fd938e1c91dcfefff2df7ba77c20ed8dfc765 + languageName: node + linkType: hard + +"https-proxy-agent@npm:^7.0.1": + version: 7.0.5 + resolution: "https-proxy-agent@npm:7.0.5" + dependencies: + agent-base: ^7.0.2 + debug: 4 + checksum: 2e1a28960f13b041a50702ee74f240add8e75146a5c37fc98f1960f0496710f6918b3a9fe1e5aba41e50f58e6df48d107edd9c405c5f0d73ac260dabf2210857 + languageName: node + linkType: hard + "human-signals@npm:^4.3.0": version: 4.3.1 resolution: "human-signals@npm:4.3.1" @@ -642,6 +3117,59 @@ __metadata: languageName: node linkType: hard +"iconv-lite@npm:^0.4.24": + version: 0.4.24 + resolution: "iconv-lite@npm:0.4.24" + dependencies: + safer-buffer: ">= 2.1.2 < 3" + checksum: bd9f120f5a5b306f0bc0b9ae1edeb1577161503f5f8252a20f1a9e56ef8775c9959fd01c55f2d3a39d9a8abaf3e30c1abeb1895f367dcbbe0a8fd1c9ca01c4f6 + languageName: node + linkType: hard + +"iconv-lite@npm:^0.6.2": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" + dependencies: + safer-buffer: ">= 2.1.2 < 3.0.0" + checksum: 3f60d47a5c8fc3313317edfd29a00a692cc87a19cac0159e2ce711d0ebc9019064108323b5e493625e25594f11c6236647d8e256fbe7a58f4a3b33b89e6d30bf + languageName: node + linkType: hard + +"ignore-by-default@npm:^2.1.0": + version: 2.1.0 + resolution: "ignore-by-default@npm:2.1.0" + checksum: 2b2df4622b6a07a3e91893987be8f060dc553f7736b67e72aa2312041c450a6fa8371733d03c42f45a02e47ec824e961c2fba63a3d94fc59cbd669220a5b0d7a + languageName: node + linkType: hard + +"ignore@npm:^5.2.4": + version: 5.3.1 + resolution: "ignore@npm:5.3.1" + checksum: 71d7bb4c1dbe020f915fd881108cbe85a0db3d636a0ea3ba911393c53946711d13a9b1143c7e70db06d571a5822c0a324a6bcde5c9904e7ca5047f01f1bf8cd3 + languageName: node + linkType: hard + +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 7cae75c8cd9a50f57dadd77482359f659eaebac0319dd9368bcd1714f55e65badd6929ca58569da2b6494ef13fdd5598cd700b1eba23f8b79c5f19d195a3ecf7 + languageName: node + linkType: hard + +"indent-string@npm:^4.0.0": + version: 4.0.0 + resolution: "indent-string@npm:4.0.0" + checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612 + languageName: node + linkType: hard + +"indent-string@npm:^5.0.0": + version: 5.0.0 + resolution: "indent-string@npm:5.0.0" + checksum: e466c27b6373440e6d84fbc19e750219ce25865cb82d578e41a6053d727e5520dc5725217d6eb1cc76005a1bb1696a0f106d84ce7ebda3033b963a38583fb3b3 + languageName: node + linkType: hard + "inflight@npm:^1.0.4": version: 1.0.6 resolution: "inflight@npm:1.0.6" @@ -652,13 +3180,46 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2": +"inherits@npm:2, inherits@npm:^2.0.3": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 languageName: node linkType: hard +"inquirer@npm:^10.0.0": + version: 10.2.2 + resolution: "inquirer@npm:10.2.2" + dependencies: + "@inquirer/core": ^9.1.0 + "@inquirer/prompts": ^5.5.0 + "@inquirer/type": ^1.5.3 + "@types/mute-stream": ^0.0.4 + ansi-escapes: ^4.3.2 + mute-stream: ^1.0.0 + run-async: ^3.0.0 + rxjs: ^7.8.1 + checksum: 41e09d818f9545d52698f69f6c832f6a2ea2cf40e7b0e056147aadd8ea4b76d489a2a10e34b0593cd1f43989def3114c086502166c2a0bdab353ea5c43f4173b + languageName: node + linkType: hard + +"ip-address@npm:^9.0.5": + version: 9.0.5 + resolution: "ip-address@npm:9.0.5" + dependencies: + jsbn: 1.1.0 + sprintf-js: ^1.1.3 + checksum: aa15f12cfd0ef5e38349744e3654bae649a34c3b10c77a674a167e99925d1549486c5b14730eebce9fea26f6db9d5e42097b00aa4f9f612e68c79121c71652dc + languageName: node + linkType: hard + +"irregular-plurals@npm:^3.3.0": + version: 3.5.0 + resolution: "irregular-plurals@npm:3.5.0" + checksum: 5b663091dc89155df7b2e9d053e8fb11941a0c4be95c4b6549ed3ea020489fdf4f75ea586c915b5b543704252679a5a6e8c6c3587da5ac3fc57b12da90a9aee7 + languageName: node + linkType: hard + "is-arrayish@npm:^0.2.1": version: 0.2.1 resolution: "is-arrayish@npm:0.2.1" @@ -666,12 +3227,26 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.13.0": - version: 2.13.0 - resolution: "is-core-module@npm:2.13.0" +"is-builtin-module@npm:^3.2.1": + version: 3.2.1 + resolution: "is-builtin-module@npm:3.2.1" dependencies: - has: ^1.0.3 - checksum: 053ab101fb390bfeb2333360fd131387bed54e476b26860dc7f5a700bbf34a0ec4454f7c8c4d43e8a0030957e4b3db6e16d35e1890ea6fb654c833095e040355 + builtin-modules: ^3.3.0 + checksum: e8f0ffc19a98240bda9c7ada84d846486365af88d14616e737d280d378695c8c448a621dcafc8332dbf0fcd0a17b0763b845400709963fa9151ddffece90ae88 + languageName: node + linkType: hard + +"is-core-module@npm:@nolyfill/is-core-module@^1": + version: 1.0.39 + resolution: "@nolyfill/is-core-module@npm:1.0.39" + checksum: 0d6e098b871eca71d875651288e1f0fa770a63478b0b50479c99dc760c64175a56b5b04f58d5581bbcc6b552b8191ab415eada093d8df9597ab3423c8cac1815 + languageName: node + linkType: hard + +"is-extglob@npm:^2.1.1": + version: 2.1.1 + resolution: "is-extglob@npm:2.1.1" + checksum: df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85 languageName: node linkType: hard @@ -689,6 +3264,29 @@ __metadata: languageName: node linkType: hard +"is-glob@npm:^4.0.1": + version: 4.0.3 + resolution: "is-glob@npm:4.0.3" + dependencies: + is-extglob: ^2.1.1 + checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4 + languageName: node + linkType: hard + +"is-lambda@npm:^1.0.1": + version: 1.0.1 + resolution: "is-lambda@npm:1.0.1" + checksum: 93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35 + languageName: node + linkType: hard + +"is-module@npm:^1.0.0": + version: 1.0.0 + resolution: "is-module@npm:1.0.0" + checksum: 8cd5390730c7976fb4e8546dd0b38865ee6f7bacfa08dfbb2cc07219606755f0b01709d9361e01f13009bbbd8099fa2927a8ed665118a6105d66e40f1b838c3f + languageName: node + linkType: hard + "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" @@ -696,6 +3294,29 @@ __metadata: languageName: node linkType: hard +"is-plain-object@npm:^5.0.0": + version: 5.0.0 + resolution: "is-plain-object@npm:5.0.0" + checksum: e32d27061eef62c0847d303125440a38660517e586f2f3db7c9d179ae5b6674ab0f469d519b2e25c147a1a3bc87156d0d5f4d8821e0ce4a9ee7fe1fcf11ce45c + languageName: node + linkType: hard + +"is-promise@npm:^4.0.0": + version: 4.0.0 + resolution: "is-promise@npm:4.0.0" + checksum: 0b46517ad47b00b6358fd6553c83ec1f6ba9acd7ffb3d30a0bf519c5c69e7147c132430452351b8a9fc198f8dd6c4f76f8e6f5a7f100f8c77d57d9e0f4261a8a + languageName: node + linkType: hard + +"is-reference@npm:1.2.1": + version: 1.2.1 + resolution: "is-reference@npm:1.2.1" + dependencies: + "@types/estree": "*" + checksum: e7b48149f8abda2c10849ea51965904d6a714193d68942ad74e30522231045acf06cbfae5a4be2702fede5d232e61bf50b3183acdc056e6e3afe07fcf4f4b2bc + languageName: node + linkType: hard + "is-stream@npm:^3.0.0": version: 3.0.0 resolution: "is-stream@npm:3.0.0" @@ -703,6 +3324,13 @@ __metadata: languageName: node linkType: hard +"is-unicode-supported@npm:^2.0.0": + version: 2.0.0 + resolution: "is-unicode-supported@npm:2.0.0" + checksum: 000b80639dedaf59a385f1c0a57f97a4d1435e0723716f24cc19ad94253a7a0a9f838bdc9ac49b10a29ac93b01f52ae9b2ed358a8876caf1eb74d73b4ede92b2 + languageName: node + linkType: hard + "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -710,6 +3338,13 @@ __metadata: languageName: node linkType: hard +"isexe@npm:^3.1.1": + version: 3.1.1 + resolution: "isexe@npm:3.1.1" + checksum: 7fe1931ee4e88eb5aa524cd3ceb8c882537bc3a81b02e438b240e47012eef49c86904d0f0e593ea7c3a9996d18d0f1f3be8d3eaa92333977b0c3a9d353d5563e + languageName: node + linkType: hard + "isomorphic.js@npm:^0.2.4": version: 0.2.5 resolution: "isomorphic.js@npm:0.2.5" @@ -745,6 +3380,56 @@ __metadata: languageName: node linkType: hard +"jackspeak@npm:^3.1.2": + version: 3.4.0 + resolution: "jackspeak@npm:3.4.0" + dependencies: + "@isaacs/cliui": ^8.0.2 + "@pkgjs/parseargs": ^0.11.0 + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 350f6f311018bb175ffbe736b19c26ac0b134bb5a17a638169e89594eb0c24ab1c658ab3a2fda24ff63b3b19292e1a5ec19d2255bc526df704e8168d392bef85 + languageName: node + linkType: hard + +"js-string-escape@npm:^1.0.1": + version: 1.0.1 + resolution: "js-string-escape@npm:1.0.1" + checksum: f11e0991bf57e0c183b55c547acec85bd2445f043efc9ea5aa68b41bd2a3e7d3ce94636cb233ae0d84064ba4c1a505d32e969813c5b13f81e7d4be12c59256fe + languageName: node + linkType: hard + +"js-yaml@npm:^3.14.1": + version: 3.14.1 + resolution: "js-yaml@npm:3.14.1" + dependencies: + argparse: ^1.0.7 + esprima: ^4.0.0 + bin: + js-yaml: bin/js-yaml.js + checksum: bef146085f472d44dee30ec34e5cf36bf89164f5d585435a3d3da89e52622dff0b188a580e4ad091c3341889e14cb88cac6e4deb16dc5b1e9623bb0601fc255c + languageName: node + linkType: hard + +"js-yaml@npm:^4.1.0": + version: 4.1.0 + resolution: "js-yaml@npm:4.1.0" + dependencies: + argparse: ^2.0.1 + bin: + js-yaml: bin/js-yaml.js + checksum: c7830dfd456c3ef2c6e355cc5a92e6700ceafa1d14bba54497b34a99f0376cecbb3e9ac14d3e5849b426d5a5140709a66237a8c991c675431271c4ce5504151a + languageName: node + linkType: hard + +"jsbn@npm:1.1.0": + version: 1.1.0 + resolution: "jsbn@npm:1.1.0" + checksum: 944f924f2bd67ad533b3850eee47603eed0f6ae425fd1ee8c760f477e8c34a05f144c1bd4f5a5dd1963141dc79a2c55f89ccc5ab77d039e7077f3ad196b64965 + languageName: node + linkType: hard + "json-parse-better-errors@npm:^1.0.1": version: 1.0.2 resolution: "json-parse-better-errors@npm:1.0.2" @@ -759,15 +3444,16 @@ __metadata: languageName: node linkType: hard -"lib0@npm:^0.2.74": - version: 0.2.85 - resolution: "lib0@npm:0.2.85" +"lib0@npm:^0.2.86": + version: 0.2.94 + resolution: "lib0@npm:0.2.94" dependencies: isomorphic.js: ^0.2.4 bin: + 0ecdsa-generate-keypair: bin/0ecdsa-generate-keypair.js 0gentesthtml: bin/gentesthtml.js 0serve: bin/0serve.js - checksum: 6a3c5c5c3f37f0940eff9309b2595f9a77822f521773db773e0d809309ccf5e6ecab8f39cc47b55b6b167f60b3824c44bb7d92b5c9ffb81a3f331b21277906d2 + checksum: b091c7b39875a58d92ae6dcb014a42b56caf1336e03d310403c47a2fcea079eba92ffb43da90eaff9d010f08bcd20de35fffed7c655c83312ff4e3477f5dc261 languageName: node linkType: hard @@ -829,6 +3515,13 @@ __metadata: languageName: node linkType: hard +"load-json-file@npm:^7.0.1": + version: 7.0.1 + resolution: "load-json-file@npm:7.0.1" + checksum: a560288da6891778321ef993e4bdbdf05374a4f3a3aeedd5ba6b64672798c830d748cfc59a2ec9891a3db30e78b3d04172e0dcb0d4828168289a393147ca0e74 + languageName: node + linkType: hard + "locate-path@npm:^6.0.0": version: 6.0.0 resolution: "locate-path@npm:6.0.0" @@ -838,6 +3531,20 @@ __metadata: languageName: node linkType: hard +"lodash-es@npm:^4.17.21": + version: 4.17.21 + resolution: "lodash-es@npm:4.17.21" + checksum: 05cbffad6e2adbb331a4e16fbd826e7faee403a1a04873b82b42c0f22090f280839f85b95393f487c1303c8a3d2a010048bf06151a6cbe03eee4d388fb0a12d2 + languageName: node + linkType: hard + +"lodash@npm:^4.17.15": + version: 4.17.21 + resolution: "lodash@npm:4.17.21" + checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 + languageName: node + linkType: hard + "log-update@npm:^5.0.1": version: 5.0.1 resolution: "log-update@npm:5.0.1" @@ -851,12 +3558,28 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^6.0.0": - version: 6.0.0 - resolution: "lru-cache@npm:6.0.0" +"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": + version: 10.3.0 + resolution: "lru-cache@npm:10.3.0" + checksum: f2289639bd94cf3c87bfd8a77ac991f9afe3af004ddca3548c3dae63ead1c73bba449a60a4e270992e16cf3261b3d4130943234d52ca3a4d4de2fc074a3cc7b5 + languageName: node + linkType: hard + +"magic-string@npm:^0.30.10, magic-string@npm:^0.30.3": + version: 0.30.11 + resolution: "magic-string@npm:0.30.11" dependencies: - yallist: ^4.0.0 - checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297 + "@jridgewell/sourcemap-codec": ^1.5.0 + checksum: e041649453c9a3f31d2e731fc10e38604d50e20d3585cd48bc7713a6e2e1a3ad3012105929ca15750d59d0a3f1904405e4b95a23b7e69dc256db3c277a73a3ca + languageName: node + linkType: hard + +"make-dir@npm:^3.1.0": + version: 3.1.0 + resolution: "make-dir@npm:3.1.0" + dependencies: + semver: ^6.0.0 + checksum: 484200020ab5a1fdf12f393fe5f385fc8e4378824c940fba1729dcd198ae4ff24867bc7a5646331e50cead8abff5d9270c456314386e629acec6dff4b8016b78 languageName: node linkType: hard @@ -869,10 +3592,50 @@ __metadata: languageName: node linkType: hard -"make-error@npm:^1.1.1": - version: 1.3.6 - resolution: "make-error@npm:1.3.6" - checksum: b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402 +"make-fetch-happen@npm:^13.0.0": + version: 13.0.1 + resolution: "make-fetch-happen@npm:13.0.1" + dependencies: + "@npmcli/agent": ^2.0.0 + cacache: ^18.0.0 + http-cache-semantics: ^4.1.1 + is-lambda: ^1.0.1 + minipass: ^7.0.2 + minipass-fetch: ^3.0.0 + minipass-flush: ^1.0.5 + minipass-pipeline: ^1.2.4 + negotiator: ^0.6.3 + proc-log: ^4.2.0 + promise-retry: ^2.0.1 + ssri: ^10.0.0 + checksum: 5c9fad695579b79488fa100da05777213dd9365222f85e4757630f8dd2a21a79ddd3206c78cfd6f9b37346819681782b67900ac847a57cf04190f52dda5343fd + languageName: node + linkType: hard + +"matcher@npm:^5.0.0": + version: 5.0.0 + resolution: "matcher@npm:5.0.0" + dependencies: + escape-string-regexp: ^5.0.0 + checksum: 28f191c2d23fee0f6f32fd0181d9fe173b0ab815a919edba55605438a2f9fa40372e002574a1b17add981b0a8669c75bc6194318d065ed2dceffd8b160c38118 + languageName: node + linkType: hard + +"md5-hex@npm:^3.0.1": + version: 3.0.1 + resolution: "md5-hex@npm:3.0.1" + dependencies: + blueimp-md5: ^2.10.0 + checksum: 6799a19e8bdd3e0c2861b94c1d4d858a89220488d7885c1fa236797e367d0c2e5f2b789e05309307083503f85be3603a9686a5915568a473137d6b4117419cc2 + languageName: node + linkType: hard + +"memoize@npm:^10.0.0": + version: 10.0.0 + resolution: "memoize@npm:10.0.0" + dependencies: + mimic-function: ^5.0.0 + checksum: a052912fcd4f1e258438abd800c15c6be6cc7123d3affbbcc438e95c11c5d7e0209882f8e58938e92d62a435b839cc359f69674b455d906596a484cbbe29727d languageName: node linkType: hard @@ -890,6 +3653,13 @@ __metadata: languageName: node linkType: hard +"merge2@npm:^1.3.0": + version: 1.4.1 + resolution: "merge2@npm:1.4.1" + checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 + languageName: node + linkType: hard + "micromatch@npm:4.0.5": version: 4.0.5 resolution: "micromatch@npm:4.0.5" @@ -900,6 +3670,16 @@ __metadata: languageName: node linkType: hard +"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4": + version: 4.0.7 + resolution: "micromatch@npm:4.0.7" + dependencies: + braces: ^3.0.3 + picomatch: ^2.3.1 + checksum: 3cde047d70ad80cf60c787b77198d680db3b8c25b23feb01de5e2652205d9c19f43bd81882f69a0fd1f0cde6a7a122d774998aad3271ddb1b8accf8a0f480cf7 + languageName: node + linkType: hard + "mimic-fn@npm:^2.1.0": version: 2.1.0 resolution: "mimic-fn@npm:2.1.0" @@ -914,6 +3694,13 @@ __metadata: languageName: node linkType: hard +"mimic-function@npm:^5.0.0": + version: 5.0.1 + resolution: "mimic-function@npm:5.0.1" + checksum: eb5893c99e902ccebbc267c6c6b83092966af84682957f79313311edb95e8bb5f39fb048d77132b700474d1c86d90ccc211e99bae0935447a4834eb4c882982c + languageName: node + linkType: hard + "minimatch@npm:^3.0.4, minimatch@npm:^3.1.1": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -923,6 +3710,108 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^9.0.4": + version: 9.0.5 + resolution: "minimatch@npm:9.0.5" + dependencies: + brace-expansion: ^2.0.1 + checksum: 2c035575eda1e50623c731ec6c14f65a85296268f749b9337005210bb2b34e2705f8ef1a358b188f69892286ab99dc42c8fb98a57bde55c8d81b3023c19cea28 + languageName: node + linkType: hard + +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" + dependencies: + minipass: ^7.0.3 + checksum: b251bceea62090f67a6cced7a446a36f4cd61ee2d5cea9aee7fff79ba8030e416327a1c5aa2908dc22629d06214b46d88fdab8c51ac76bacbf5703851b5ad342 + languageName: node + linkType: hard + +"minipass-fetch@npm:^3.0.0": + version: 3.0.5 + resolution: "minipass-fetch@npm:3.0.5" + dependencies: + encoding: ^0.1.13 + minipass: ^7.0.3 + minipass-sized: ^1.0.3 + minizlib: ^2.1.2 + dependenciesMeta: + encoding: + optional: true + checksum: 8047d273236157aab27ab7cd8eab7ea79e6ecd63e8f80c3366ec076cb9a0fed550a6935bab51764369027c414647fd8256c2a20c5445fb250c483de43350de83 + languageName: node + linkType: hard + +"minipass-flush@npm:^1.0.5": + version: 1.0.5 + resolution: "minipass-flush@npm:1.0.5" + dependencies: + minipass: ^3.0.0 + checksum: 56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf + languageName: node + linkType: hard + +"minipass-pipeline@npm:^1.2.4": + version: 1.2.4 + resolution: "minipass-pipeline@npm:1.2.4" + dependencies: + minipass: ^3.0.0 + checksum: b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b + languageName: node + linkType: hard + +"minipass-sized@npm:^1.0.3": + version: 1.0.3 + resolution: "minipass-sized@npm:1.0.3" + dependencies: + minipass: ^3.0.0 + checksum: 79076749fcacf21b5d16dd596d32c3b6bf4d6e62abb43868fac21674078505c8b15eaca4e47ed844985a4514854f917d78f588fcd029693709417d8f98b2bd60 + languageName: node + linkType: hard + +"minipass@npm:^3.0.0": + version: 3.3.6 + resolution: "minipass@npm:3.3.6" + dependencies: + yallist: ^4.0.0 + checksum: a30d083c8054cee83cdcdc97f97e4641a3f58ae743970457b1489ce38ee1167b3aaf7d815cd39ec7a99b9c40397fd4f686e83750e73e652b21cb516f6d845e48 + languageName: node + linkType: hard + +"minipass@npm:^5.0.0": + version: 5.0.0 + resolution: "minipass@npm:5.0.0" + checksum: 425dab288738853fded43da3314a0b5c035844d6f3097a8e3b5b29b328da8f3c1af6fc70618b32c29ff906284cf6406b6841376f21caaadd0793c1d5a6a620ea + languageName: node + linkType: hard + +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.1.2": + version: 7.1.2 + resolution: "minipass@npm:7.1.2" + checksum: 2bfd325b95c555f2b4d2814d49325691c7bee937d753814861b0b49d5edcda55cbbf22b6b6a60bb91eddac8668771f03c5ff647dcd9d0f798e9548b9cdc46ee3 + languageName: node + linkType: hard + +"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": + version: 2.1.2 + resolution: "minizlib@npm:2.1.2" + dependencies: + minipass: ^3.0.0 + yallist: ^4.0.0 + checksum: f1fdeac0b07cf8f30fcf12f4b586795b97be856edea22b5e9072707be51fc95d41487faec3f265b42973a304fe3a64acd91a44a3826a963e37b37bafde0212c3 + languageName: node + linkType: hard + +"mkdirp@npm:^1.0.3": + version: 1.0.4 + resolution: "mkdirp@npm:1.0.4" + bin: + mkdirp: bin/cmd.js + checksum: a96865108c6c3b1b8e1d5e9f11843de1e077e57737602de1b82030815f311be11f96f09cce59bd5b903d0b29834733e5313f9301e3ed6d6f6fba2eae0df4298f + languageName: node + linkType: hard + "ms@npm:2.1.2": version: 2.1.2 resolution: "ms@npm:2.1.2" @@ -930,6 +3819,27 @@ __metadata: languageName: node linkType: hard +"ms@npm:^2.1.3": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d + languageName: node + linkType: hard + +"mute-stream@npm:^1.0.0": + version: 1.0.0 + resolution: "mute-stream@npm:1.0.0" + checksum: 36fc968b0e9c9c63029d4f9dc63911950a3bdf55c9a87f58d3a266289b67180201cade911e7699f8b2fa596b34c9db43dad37649e3f7fdd13c3bb9edb0017ee7 + languageName: node + linkType: hard + +"negotiator@npm:^0.6.3": + version: 0.6.3 + resolution: "negotiator@npm:0.6.3" + checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9 + languageName: node + linkType: hard + "nice-try@npm:^1.0.4": version: 1.0.5 resolution: "nice-try@npm:1.0.5" @@ -937,6 +3847,80 @@ __metadata: languageName: node linkType: hard +"node-fetch@npm:^2.6.7": + version: 2.7.0 + resolution: "node-fetch@npm:2.7.0" + dependencies: + whatwg-url: ^5.0.0 + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + checksum: d76d2f5edb451a3f05b15115ec89fc6be39de37c6089f1b6368df03b91e1633fd379a7e01b7ab05089a25034b2023d959b47e59759cb38d88341b2459e89d6e5 + languageName: node + linkType: hard + +"node-gyp-build@npm:^4.2.2": + version: 4.8.1 + resolution: "node-gyp-build@npm:4.8.1" + bin: + node-gyp-build: bin.js + node-gyp-build-optional: optional.js + node-gyp-build-test: build-test.js + checksum: fe6e95da6f4608c1a98655f6bf2fe4e8dd9c877cd13256056a8acaf585cc7f98718823fe9366be11b78c2f332d5a184b00cf07a4af96c9d8fea45f640c019f98 + languageName: node + linkType: hard + +"node-gyp@npm:latest": + version: 10.1.0 + resolution: "node-gyp@npm:10.1.0" + dependencies: + env-paths: ^2.2.0 + exponential-backoff: ^3.1.1 + glob: ^10.3.10 + graceful-fs: ^4.2.6 + make-fetch-happen: ^13.0.0 + nopt: ^7.0.0 + proc-log: ^3.0.0 + semver: ^7.3.5 + tar: ^6.1.2 + which: ^4.0.0 + bin: + node-gyp: bin/node-gyp.js + checksum: 72e2ab4b23fc32007a763da94018f58069fc0694bf36115d49a2b195c8831e12cf5dd1e7a3718fa85c06969aedf8fc126722d3b672ec1cb27e06ed33caee3c60 + languageName: node + linkType: hard + +"nofilter@npm:^3.1.0": + version: 3.1.0 + resolution: "nofilter@npm:3.1.0" + checksum: 58aa85a5b4b35cbb6e42de8a8591c5e338061edc9f3e7286f2c335e9e9b9b8fa7c335ae45daa8a1f3433164dc0b9a3d187fa96f9516e04a17a1f9ce722becc4f + languageName: node + linkType: hard + +"nopt@npm:^5.0.0": + version: 5.0.0 + resolution: "nopt@npm:5.0.0" + dependencies: + abbrev: 1 + bin: + nopt: bin/nopt.js + checksum: d35fdec187269503843924e0114c0c6533fb54bbf1620d0f28b4b60ba01712d6687f62565c55cc20a504eff0fbe5c63e22340c3fad549ad40469ffb611b04f2f + languageName: node + linkType: hard + +"nopt@npm:^7.0.0": + version: 7.2.1 + resolution: "nopt@npm:7.2.1" + dependencies: + abbrev: ^2.0.0 + bin: + nopt: bin/nopt.js + checksum: 6fa729cc77ce4162cfad8abbc9ba31d4a0ff6850c3af61d59b505653bef4781ec059f8890ecfe93ee8aa0c511093369cca88bfc998101616a2904e715bbbb7c9 + languageName: node + linkType: hard + "normalize-package-data@npm:^2.3.2": version: 2.5.0 resolution: "normalize-package-data@npm:2.5.0" @@ -979,6 +3963,25 @@ __metadata: languageName: node linkType: hard +"npmlog@npm:^5.0.1": + version: 5.0.1 + resolution: "npmlog@npm:5.0.1" + dependencies: + are-we-there-yet: ^2.0.0 + console-control-strings: ^1.1.0 + gauge: ^3.0.0 + set-blocking: ^2.0.0 + checksum: 516b2663028761f062d13e8beb3f00069c5664925871a9b57989642ebe09f23ab02145bf3ab88da7866c4e112cafff72401f61a672c7c8a20edc585a7016ef5f + languageName: node + linkType: hard + +"object-assign@npm:^4.1.1": + version: 4.1.1 + resolution: "object-assign@npm:4.1.1" + checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f + languageName: node + linkType: hard + "once@npm:^1.3.0": version: 1.4.0 resolution: "once@npm:1.4.0" @@ -1006,6 +4009,13 @@ __metadata: languageName: node linkType: hard +"os-tmpdir@npm:~1.0.2": + version: 1.0.2 + resolution: "os-tmpdir@npm:1.0.2" + checksum: 5666560f7b9f10182548bf7013883265be33620b1c1b4a4d405c25be2636f970c5488ff3e6c48de75b55d02bde037249fe5dbfbb4c0fb7714953d56aed062e6d + languageName: node + linkType: hard + "p-limit@npm:^3.0.2": version: 3.1.0 resolution: "p-limit@npm:3.1.0" @@ -1024,6 +4034,39 @@ __metadata: languageName: node linkType: hard +"p-map@npm:^4.0.0": + version: 4.0.0 + resolution: "p-map@npm:4.0.0" + dependencies: + aggregate-error: ^3.0.0 + checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c + languageName: node + linkType: hard + +"p-map@npm:^7.0.1": + version: 7.0.2 + resolution: "p-map@npm:7.0.2" + checksum: bc128c2b244ef5d4619392b2247d718a3fe471d5fa4a73834fd96182a237f460ec7e0ad0f95139ef7103a6b50ed164228c62e2f8e41ba2b15360fe1c20d13563 + languageName: node + linkType: hard + +"package-config@npm:^5.0.0": + version: 5.0.0 + resolution: "package-config@npm:5.0.0" + dependencies: + find-up-simple: ^1.0.0 + load-json-file: ^7.0.1 + checksum: dfff5264c51a0dad7af9a55b02e3b8b6e457075e9c4f02d0ffacfeee9af4dd5db2b566dae41486412161292b8741483cd89d5a8404a5742fc54d718dadacac4a + languageName: node + linkType: hard + +"package-json-from-dist@npm:^1.0.0": + version: 1.0.0 + resolution: "package-json-from-dist@npm:1.0.0" + checksum: ac706ec856a5a03f5261e4e48fa974f24feb044d51f84f8332e2af0af04fbdbdd5bbbfb9cbbe354190409bc8307c83a9e38c6672c3c8855f709afb0006a009ea + languageName: node + linkType: hard + "parse-json@npm:^4.0.0": version: 4.0.0 resolution: "parse-json@npm:4.0.0" @@ -1034,6 +4077,13 @@ __metadata: languageName: node linkType: hard +"parse-ms@npm:^4.0.0": + version: 4.0.0 + resolution: "parse-ms@npm:4.0.0" + checksum: 673c801d9f957ff79962d71ed5a24850163f4181a90dd30c4e3666b3a804f53b77f1f0556792e8b2adbb5d58757907d1aa51d7d7dc75997c2a56d72937cbc8b7 + languageName: node + linkType: hard + "path-exists@npm:^4.0.0": version: 4.0.0 resolution: "path-exists@npm:4.0.0" @@ -1076,6 +4126,16 @@ __metadata: languageName: node linkType: hard +"path-scurry@npm:^1.11.1": + version: 1.11.1 + resolution: "path-scurry@npm:1.11.1" + dependencies: + lru-cache: ^10.2.0 + minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 + checksum: 890d5abcd593a7912dcce7cf7c6bf7a0b5648e3dee6caf0712c126ca0a65c7f3d7b9d769072a4d1baf370f61ce493ab5b038d59988688e0c5f3f646ee3c69023 + languageName: node + linkType: hard + "path-type@npm:^3.0.0": version: 3.0.0 resolution: "path-type@npm:3.0.0" @@ -1085,13 +4145,27 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^2.3.1": +"path-type@npm:^5.0.0": + version: 5.0.0 + resolution: "path-type@npm:5.0.0" + checksum: 15ec24050e8932c2c98d085b72cfa0d6b4eeb4cbde151a0a05726d8afae85784fc5544f733d8dfc68536587d5143d29c0bd793623fad03d7e61cc00067291cd5 + languageName: node + linkType: hard + +"picomatch@npm:^2.2.2, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf languageName: node linkType: hard +"picomatch@npm:^3.0.1": + version: 3.0.1 + resolution: "picomatch@npm:3.0.1" + checksum: b7fe18174bcc05bbf0ea09cc85623ae395676b3e6bc25636d4c20db79a948586237e429905453bf1ba385bc7a7aa5b56f1b351680e650d2b5c305ceb98dfc914 + languageName: node + linkType: hard + "pidtree@npm:0.6.0": version: 0.6.0 resolution: "pidtree@npm:0.6.0" @@ -1117,6 +4191,40 @@ __metadata: languageName: node linkType: hard +"pkgroll@npm:^2.5.0": + version: 2.5.0 + resolution: "pkgroll@npm:2.5.0" + dependencies: + "@rollup/plugin-alias": ^5.1.0 + "@rollup/plugin-commonjs": ^26.0.1 + "@rollup/plugin-inject": ^5.0.5 + "@rollup/plugin-json": ^6.1.0 + "@rollup/plugin-node-resolve": ^15.2.3 + "@rollup/plugin-replace": ^5.0.7 + "@rollup/pluginutils": ^5.1.0 + esbuild: ^0.23.0 + magic-string: ^0.30.10 + rollup: ^4.18.1 + peerDependencies: + typescript: ^4.1 || ^5.0 + peerDependenciesMeta: + typescript: + optional: true + bin: + pkgroll: dist/cli.js + checksum: e5526c8fed5252d168526dc4d0ebcdc60fc6d7fc21c2c76bc7f497ac06cdc2ea3a6547ac0cfca3bf28ea4a478dff708bde1632f215a1256789b0b0adfbc37b48 + languageName: node + linkType: hard + +"plur@npm:^5.1.0": + version: 5.1.0 + resolution: "plur@npm:5.1.0" + dependencies: + irregular-plurals: ^3.3.0 + checksum: 57e400dc4b926768fb0abab7f8688fe17e85673712134546e7beaaee188bae7e0504976e847d7e41d0d6103ff2fd61204095f03c2a45de19a8bad15aecb45cc1 + languageName: node + linkType: hard + "prettier@npm:^3.0.2": version: 3.0.2 resolution: "prettier@npm:3.0.2" @@ -1126,6 +4234,39 @@ __metadata: languageName: node linkType: hard +"pretty-ms@npm:^9.0.0": + version: 9.0.0 + resolution: "pretty-ms@npm:9.0.0" + dependencies: + parse-ms: ^4.0.0 + checksum: 072b17547e09cb232e8e4c7be0281e256b6d8acd18dfb2fdd715d50330d1689fdaa877f53cf90c62ed419ef842f0f5fb94a2cd8ed1aa6d7608ad48834219435d + languageName: node + linkType: hard + +"proc-log@npm:^3.0.0": + version: 3.0.0 + resolution: "proc-log@npm:3.0.0" + checksum: 02b64e1b3919e63df06f836b98d3af002b5cd92655cab18b5746e37374bfb73e03b84fe305454614b34c25b485cc687a9eebdccf0242cda8fda2475dd2c97e02 + languageName: node + linkType: hard + +"proc-log@npm:^4.2.0": + version: 4.2.0 + resolution: "proc-log@npm:4.2.0" + checksum: 98f6cd012d54b5334144c5255ecb941ee171744f45fca8b43b58ae5a0c1af07352475f481cadd9848e7f0250376ee584f6aa0951a856ff8f021bdfbff4eb33fc + languageName: node + linkType: hard + +"promise-retry@npm:^2.0.1": + version: 2.0.1 + resolution: "promise-retry@npm:2.0.1" + dependencies: + err-code: ^2.0.2 + retry: ^0.12.0 + checksum: f96a3f6d90b92b568a26f71e966cbbc0f63ab85ea6ff6c81284dc869b41510e6cdef99b6b65f9030f0db422bf7c96652a3fff9f2e8fb4a0f069d8f4430359429 + languageName: node + linkType: hard + "prompts@npm:^2.4.2": version: 2.4.2 resolution: "prompts@npm:2.4.2" @@ -1136,6 +4277,13 @@ __metadata: languageName: node linkType: hard +"queue-microtask@npm:^1.2.2": + version: 1.2.3 + resolution: "queue-microtask@npm:1.2.3" + checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4 + languageName: node + linkType: hard + "read-pkg@npm:^3.0.0": version: 3.0.0 resolution: "read-pkg@npm:3.0.0" @@ -1147,6 +4295,17 @@ __metadata: languageName: node linkType: hard +"readable-stream@npm:^3.6.0": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" + dependencies: + inherits: ^2.0.3 + string_decoder: ^1.1.1 + util-deprecate: ^1.0.1 + checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d + languageName: node + linkType: hard + "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" @@ -1154,6 +4313,29 @@ __metadata: languageName: node linkType: hard +"resolve-cwd@npm:^3.0.0": + version: 3.0.0 + resolution: "resolve-cwd@npm:3.0.0" + dependencies: + resolve-from: ^5.0.0 + checksum: 546e0816012d65778e580ad62b29e975a642989108d9a3c5beabfb2304192fa3c9f9146fbdfe213563c6ff51975ae41bac1d3c6e047dd9572c94863a057b4d81 + languageName: node + linkType: hard + +"resolve-from@npm:^5.0.0": + version: 5.0.0 + resolution: "resolve-from@npm:5.0.0" + checksum: 4ceeb9113e1b1372d0cd969f3468fa042daa1dd9527b1b6bb88acb6ab55d8b9cd65dbf18819f9f9ddf0db804990901dcdaade80a215e7b2c23daae38e64f5bdf + languageName: node + linkType: hard + +"resolve-pkg-maps@npm:^1.0.0": + version: 1.0.0 + resolution: "resolve-pkg-maps@npm:1.0.0" + checksum: 1012afc566b3fdb190a6309cc37ef3b2dcc35dff5fa6683a9d00cd25c3247edfbc4691b91078c97adc82a29b77a2660c30d791d65dab4fc78bfc473f60289977 + languageName: node + linkType: hard + "resolve@npm:^1.10.0": version: 1.22.4 resolution: "resolve@npm:1.22.4" @@ -1167,6 +4349,19 @@ __metadata: languageName: node linkType: hard +"resolve@npm:^1.22.1": + version: 1.22.8 + resolution: "resolve@npm:1.22.8" + dependencies: + is-core-module: ^2.13.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: f8a26958aa572c9b064562750b52131a37c29d072478ea32e129063e2da7f83e31f7f11e7087a18225a8561cfe8d2f0df9dbea7c9d331a897571c0a2527dbb4c + languageName: node + linkType: hard + "resolve@patch:resolve@^1.10.0#~builtin": version: 1.22.4 resolution: "resolve@patch:resolve@npm%3A1.22.4#~builtin::version=1.22.4&hash=c3c19d" @@ -1180,6 +4375,19 @@ __metadata: languageName: node linkType: hard +"resolve@patch:resolve@^1.22.1#~builtin": + version: 1.22.8 + resolution: "resolve@patch:resolve@npm%3A1.22.8#~builtin::version=1.22.8&hash=c3c19d" + dependencies: + is-core-module: ^2.13.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: 5479b7d431cacd5185f8db64bfcb7286ae5e31eb299f4c4f404ad8aa6098b77599563ac4257cb2c37a42f59dfc06a1bec2bcf283bb448f319e37f0feb9a09847 + languageName: node + linkType: hard + "restore-cursor@npm:^4.0.0": version: 4.0.0 resolution: "restore-cursor@npm:4.0.0" @@ -1190,6 +4398,20 @@ __metadata: languageName: node linkType: hard +"retry@npm:^0.12.0": + version: 0.12.0 + resolution: "retry@npm:0.12.0" + checksum: 623bd7d2e5119467ba66202d733ec3c2e2e26568074923bc0585b6b99db14f357e79bdedb63cab56cec47491c4a0da7e6021a7465ca6dc4f481d3898fdd3158c + languageName: node + linkType: hard + +"reusify@npm:^1.0.4": + version: 1.0.4 + resolution: "reusify@npm:1.0.4" + checksum: c3076ebcc22a6bc252cb0b9c77561795256c22b757f40c0d8110b1300723f15ec0fc8685e8d4ea6d7666f36c79ccc793b1939c748bf36f18f542744a4e379fcc + languageName: node + linkType: hard + "rfdc@npm:^1.3.0": version: 1.3.0 resolution: "rfdc@npm:1.3.0" @@ -1208,6 +4430,108 @@ __metadata: languageName: node linkType: hard +"rollup@npm:^4.18.1": + version: 4.21.3 + resolution: "rollup@npm:4.21.3" + dependencies: + "@rollup/rollup-android-arm-eabi": 4.21.3 + "@rollup/rollup-android-arm64": 4.21.3 + "@rollup/rollup-darwin-arm64": 4.21.3 + "@rollup/rollup-darwin-x64": 4.21.3 + "@rollup/rollup-linux-arm-gnueabihf": 4.21.3 + "@rollup/rollup-linux-arm-musleabihf": 4.21.3 + "@rollup/rollup-linux-arm64-gnu": 4.21.3 + "@rollup/rollup-linux-arm64-musl": 4.21.3 + "@rollup/rollup-linux-powerpc64le-gnu": 4.21.3 + "@rollup/rollup-linux-riscv64-gnu": 4.21.3 + "@rollup/rollup-linux-s390x-gnu": 4.21.3 + "@rollup/rollup-linux-x64-gnu": 4.21.3 + "@rollup/rollup-linux-x64-musl": 4.21.3 + "@rollup/rollup-win32-arm64-msvc": 4.21.3 + "@rollup/rollup-win32-ia32-msvc": 4.21.3 + "@rollup/rollup-win32-x64-msvc": 4.21.3 + "@types/estree": 1.0.5 + fsevents: ~2.3.2 + dependenciesMeta: + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-powerpc64le-gnu": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 19689840d25ced3924124b012d7e0048f2b0844a0765a5dde0804ae9961af1103657c2ec3e90f7a19876ebe40b3fa2c33f53fca071d46639c57bd327b82aba22 + languageName: node + linkType: hard + +"run-async@npm:^3.0.0": + version: 3.0.0 + resolution: "run-async@npm:3.0.0" + checksum: 280c03d5a88603f48103fc6fd69f07fb0c392a1e0d319c34ec96a2516030e07ba06f79231a563c78698b882649c2fc1fda601bc84705f57d50efcd1fa506cfc0 + languageName: node + linkType: hard + +"run-parallel@npm:^1.1.9": + version: 1.2.0 + resolution: "run-parallel@npm:1.2.0" + dependencies: + queue-microtask: ^1.2.2 + checksum: cb4f97ad25a75ebc11a8ef4e33bb962f8af8516bb2001082ceabd8902e15b98f4b84b4f8a9b222e5d57fc3bd1379c483886ed4619367a7680dad65316993021d + languageName: node + linkType: hard + +"rxjs@npm:^7.8.1": + version: 7.8.1 + resolution: "rxjs@npm:7.8.1" + dependencies: + tslib: ^2.1.0 + checksum: de4b53db1063e618ec2eca0f7965d9137cabe98cf6be9272efe6c86b47c17b987383df8574861bcced18ebd590764125a901d5506082be84a8b8e364bf05f119 + languageName: node + linkType: hard + +"safe-buffer@npm:~5.2.0": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 + languageName: node + linkType: hard + +"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0 + languageName: node + linkType: hard + "semver@npm:2 || 3 || 4 || 5, semver@npm:^5.5.0": version: 5.7.2 resolution: "semver@npm:5.7.2" @@ -1217,14 +4541,46 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.5.3": - version: 7.5.4 - resolution: "semver@npm:7.5.4" - dependencies: - lru-cache: ^6.0.0 +"semver@npm:^6.0.0": + version: 6.3.1 + resolution: "semver@npm:6.3.1" + bin: + semver: bin/semver.js + checksum: ae47d06de28836adb9d3e25f22a92943477371292d9b665fb023fae278d345d508ca1958232af086d85e0155aee22e313e100971898bbb8d5d89b8b1d4054ca2 + languageName: node + linkType: hard + +"semver@npm:^7.3.2, semver@npm:^7.3.5, semver@npm:^7.5.3": + version: 7.6.2 + resolution: "semver@npm:7.6.2" + bin: + semver: bin/semver.js + checksum: 40f6a95101e8d854357a644da1b8dd9d93ce786d5c6a77227bc69dbb17bea83d0d1d1d7c4cd5920a6df909f48e8bd8a5909869535007f90278289f2451d0292d + languageName: node + linkType: hard + +"semver@npm:^7.5.4": + version: 7.6.3 + resolution: "semver@npm:7.6.3" bin: semver: bin/semver.js - checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3 + checksum: 4110ec5d015c9438f322257b1c51fe30276e5f766a3f64c09edd1d7ea7118ecbc3f379f3b69032bacf13116dc7abc4ad8ce0d7e2bd642e26b0d271b56b61a7d8 + languageName: node + linkType: hard + +"serialize-error@npm:^7.0.1": + version: 7.0.1 + resolution: "serialize-error@npm:7.0.1" + dependencies: + type-fest: ^0.13.1 + checksum: e0aba4dca2fc9fe74ae1baf38dbd99190e1945445a241ba646290f2176cdb2032281a76443b02ccf0caf30da5657d510746506368889a593b9835a497fc0732e + languageName: node + linkType: hard + +"set-blocking@npm:^2.0.0": + version: 2.0.0 + resolution: "set-blocking@npm:2.0.0" + checksum: 6e65a05f7cf7ebdf8b7c75b101e18c0b7e3dff4940d480efed8aad3a36a4005140b660fa1d804cb8bce911cac290441dc728084a30504d3516ac2ff7ad607b02 languageName: node linkType: hard @@ -1267,13 +4623,20 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.7": +"signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 languageName: node linkType: hard +"signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 64c757b498cb8629ffa5f75485340594d2f8189e9b08700e69199069c8e3070fb3e255f7ab873c05dc0b3cec412aea7402e10a5990cb6a050bd33ba062a6c549 + languageName: node + linkType: hard + "sisteransi@npm:^1.0.5": version: 1.0.5 resolution: "sisteransi@npm:1.0.5" @@ -1281,6 +4644,20 @@ __metadata: languageName: node linkType: hard +"slash@npm:^4.0.0": + version: 4.0.0 + resolution: "slash@npm:4.0.0" + checksum: da8e4af73712253acd21b7853b7e0dbba776b786e82b010a5bfc8b5051a1db38ed8aba8e1e8f400dd2c9f373be91eb1c42b66e91abb407ff42b10feece5e1d2d + languageName: node + linkType: hard + +"slash@npm:^5.1.0": + version: 5.1.0 + resolution: "slash@npm:5.1.0" + checksum: 70434b34c50eb21b741d37d455110258c42d2cf18c01e6518aeb7299f3c6e626330c889c0c552b5ca2ef54a8f5a74213ab48895f0640717cacefeef6830a1ba4 + languageName: node + linkType: hard + "slice-ansi@npm:^5.0.0": version: 5.0.0 resolution: "slice-ansi@npm:5.0.0" @@ -1291,6 +4668,34 @@ __metadata: languageName: node linkType: hard +"smart-buffer@npm:^4.2.0": + version: 4.2.0 + resolution: "smart-buffer@npm:4.2.0" + checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b + languageName: node + linkType: hard + +"socks-proxy-agent@npm:^8.0.3": + version: 8.0.4 + resolution: "socks-proxy-agent@npm:8.0.4" + dependencies: + agent-base: ^7.1.1 + debug: ^4.3.4 + socks: ^2.8.3 + checksum: b2ec5051d85fe49072f9a250c427e0e9571fd09d5db133819192d078fd291276e1f0f50f6dbc04329b207738b1071314cee8bdbb4b12e27de42dbcf1d4233c67 + languageName: node + linkType: hard + +"socks@npm:^2.8.3": + version: 2.8.3 + resolution: "socks@npm:2.8.3" + dependencies: + ip-address: ^9.0.5 + smart-buffer: ^4.2.0 + checksum: 7a6b7f6eedf7482b9e4597d9a20e09505824208006ea8f2c49b71657427f3c137ca2ae662089baa73e1971c62322d535d9d0cf1c9235cf6f55e315c18203eadd + languageName: node + linkType: hard + "spdx-correct@npm:^3.0.0": version: 3.2.0 resolution: "spdx-correct@npm:3.2.0" @@ -1325,6 +4730,38 @@ __metadata: languageName: node linkType: hard +"sprintf-js@npm:^1.1.3": + version: 1.1.3 + resolution: "sprintf-js@npm:1.1.3" + checksum: a3fdac7b49643875b70864a9d9b469d87a40dfeaf5d34d9d0c5b1cda5fd7d065531fcb43c76357d62254c57184a7b151954156563a4d6a747015cfb41021cad0 + languageName: node + linkType: hard + +"sprintf-js@npm:~1.0.2": + version: 1.0.3 + resolution: "sprintf-js@npm:1.0.3" + checksum: 19d79aec211f09b99ec3099b5b2ae2f6e9cdefe50bc91ac4c69144b6d3928a640bb6ae5b3def70c2e85a2c3d9f5ec2719921e3a59d3ca3ef4b2fd1a4656a0df3 + languageName: node + linkType: hard + +"ssri@npm:^10.0.0": + version: 10.0.6 + resolution: "ssri@npm:10.0.6" + dependencies: + minipass: ^7.0.3 + checksum: 4603d53a05bcd44188747d38f1cc43833b9951b5a1ee43ba50535bdfc5fe4a0897472dbe69837570a5417c3c073377ef4f8c1a272683b401857f72738ee57299 + languageName: node + linkType: hard + +"stack-utils@npm:^2.0.6": + version: 2.0.6 + resolution: "stack-utils@npm:2.0.6" + dependencies: + escape-string-regexp: ^2.0.0 + checksum: 052bf4d25bbf5f78e06c1d5e67de2e088b06871fa04107ca8d3f0e9d9263326e2942c8bedee3545795fc77d787d443a538345eef74db2f8e35db3558c6f91ff7 + languageName: node + linkType: hard + "string-argv@npm:0.3.2": version: 0.3.2 resolution: "string-argv@npm:0.3.2" @@ -1332,7 +4769,7 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -1343,7 +4780,7 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^5.0.0, string-width@npm:^5.0.1": +"string-width@npm:^5.0.0, string-width@npm:^5.0.1, string-width@npm:^5.1.2": version: 5.1.2 resolution: "string-width@npm:5.1.2" dependencies: @@ -1354,16 +4791,36 @@ __metadata: languageName: node linkType: hard -"string.prototype.padend@npm:@nolyfill/string.prototype.padend@latest": - version: 1.0.20 - resolution: "@nolyfill/string.prototype.padend@npm:1.0.20" +"string-width@npm:^7.0.0": + version: 7.2.0 + resolution: "string-width@npm:7.2.0" + dependencies: + emoji-regex: ^10.3.0 + get-east-asian-width: ^1.0.0 + strip-ansi: ^7.1.0 + checksum: 42f9e82f61314904a81393f6ef75b832c39f39761797250de68c041d8ba4df2ef80db49ab6cd3a292923a6f0f409b8c9980d120f7d32c820b4a8a84a2598a295 + languageName: node + linkType: hard + +"string.prototype.padend@npm:@nolyfill/string.prototype.padend@^1": + version: 1.0.28 + resolution: "@nolyfill/string.prototype.padend@npm:1.0.28" + dependencies: + "@nolyfill/shared": 1.0.28 + checksum: 47a51619785ca1b8a852b742a6c88f807b2f89c91affa51ab3b946632c08e82cd8f91c0f61de282670227a03efd3b4258f7ff97a910b2c4e627e020d11380e96 + languageName: node + linkType: hard + +"string_decoder@npm:^1.1.1": + version: 1.3.0 + resolution: "string_decoder@npm:1.3.0" dependencies: - "@nolyfill/shared": 1.0.20 - checksum: 4f7853e46d8ec4d295f741d2139eeb8bddc7d64a9016abe89d9e74cd1c96252a7948831afba16afed64ac67d3eb5b3affc2e1ebcb6d871cdf4967e9eba7f2e50 + safe-buffer: ~5.2.0 + checksum: 8417646695a66e73aefc4420eb3b84cc9ffd89572861fe004e6aeb13c7bc00e2f616247505d2dbbef24247c372f70268f594af7126f43548565c68c117bdeb56 languageName: node linkType: hard -"strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" dependencies: @@ -1372,7 +4829,7 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^7.0.1": +"strip-ansi@npm:^7.0.1, strip-ansi@npm:^7.1.0": version: 7.1.0 resolution: "strip-ansi@npm:7.1.0" dependencies: @@ -1395,6 +4852,18 @@ __metadata: languageName: node linkType: hard +"supertap@npm:^3.0.1": + version: 3.0.1 + resolution: "supertap@npm:3.0.1" + dependencies: + indent-string: ^5.0.0 + js-yaml: ^3.14.1 + serialize-error: ^7.0.1 + strip-ansi: ^7.0.1 + checksum: ee3d71c1d25f7f15d4a849e72b0c5f430df7cd8f702cf082fdbec5642a9546be6557766745655fa3a3e9c88f7c7eed849f2d74457b5b72cb9d94a779c0c8a948 + languageName: node + linkType: hard + "supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -1420,14 +4889,51 @@ __metadata: languageName: node linkType: hard -"test-exclude@npm:^6.0.0": - version: 6.0.0 - resolution: "test-exclude@npm:6.0.0" +"tar@npm:^6.1.11, tar@npm:^6.1.2": + version: 6.2.1 + resolution: "tar@npm:6.2.1" + dependencies: + chownr: ^2.0.0 + fs-minipass: ^2.0.0 + minipass: ^5.0.0 + minizlib: ^2.1.1 + mkdirp: ^1.0.3 + yallist: ^4.0.0 + checksum: f1322768c9741a25356c11373bce918483f40fa9a25c69c59410c8a1247632487edef5fe76c5f12ac51a6356d2f1829e96d2bc34098668a2fc34d76050ac2b6c + languageName: node + linkType: hard + +"temp-dir@npm:^3.0.0": + version: 3.0.0 + resolution: "temp-dir@npm:3.0.0" + checksum: 577211e995d1d584dd60f1469351d45e8a5b4524e4a9e42d3bdd12cfde1d0bb8f5898311bef24e02aaafb69514c1feb58c7b4c33dcec7129da3b0861a4ca935b + languageName: node + linkType: hard + +"test-exclude@npm:^7.0.1": + version: 7.0.1 + resolution: "test-exclude@npm:7.0.1" dependencies: "@istanbuljs/schema": ^0.1.2 - glob: ^7.1.4 - minimatch: ^3.0.4 - checksum: 3b34a3d77165a2cb82b34014b3aba93b1c4637a5011807557dc2f3da826c59975a5ccad765721c4648b39817e3472789f9b0fa98fc854c5c1c7a1e632aacdc28 + glob: ^10.4.1 + minimatch: ^9.0.4 + checksum: e5a49a054bf2da74467dd8149b202166e36275c0dc2c9585f7d34de99c6d055d2287ac8d2a8e4c27c59b893acbc671af3fa869e8069a58ad117250e9c01c726b + languageName: node + linkType: hard + +"time-zone@npm:^1.0.0": + version: 1.0.0 + resolution: "time-zone@npm:1.0.0" + checksum: e46f5a69b8c236dcd8e91e29d40d4e7a3495ed4f59888c3f84ce1d9678e20461421a6ba41233509d47dd94bc18f1a4377764838b21b584663f942b3426dcbce8 + languageName: node + linkType: hard + +"tmp@npm:^0.0.33": + version: 0.0.33 + resolution: "tmp@npm:0.0.33" + dependencies: + os-tmpdir: ~1.0.2 + checksum: 902d7aceb74453ea02abbf58c203f4a8fc1cead89b60b31e354f74ed5b3fb09ea817f94fb310f884a5d16987dd9fa5a735412a7c2dd088dd3d415aa819ae3a28 languageName: node linkType: hard @@ -1440,41 +4946,61 @@ __metadata: languageName: node linkType: hard -"ts-node@npm:^10.9.2": - version: 10.9.2 - resolution: "ts-node@npm:10.9.2" - dependencies: - "@cspotcode/source-map-support": ^0.8.0 - "@tsconfig/node10": ^1.0.7 - "@tsconfig/node12": ^1.0.7 - "@tsconfig/node14": ^1.0.0 - "@tsconfig/node16": ^1.0.2 - acorn: ^8.4.1 - acorn-walk: ^8.1.1 - arg: ^4.1.0 - create-require: ^1.1.0 - diff: ^4.0.1 - make-error: ^1.1.1 - v8-compile-cache-lib: ^3.0.1 - yn: 3.1.1 - peerDependencies: - "@swc/core": ">=1.2.50" - "@swc/wasm": ">=1.2.50" - "@types/node": "*" - typescript: ">=2.7" - peerDependenciesMeta: - "@swc/core": - optional: true - "@swc/wasm": +"toml@npm:^3.0.0": + version: 3.0.0 + resolution: "toml@npm:3.0.0" + checksum: 5d7f1d8413ad7780e9bdecce8ea4c3f5130dd53b0a4f2e90b93340979a137739879d7b9ce2ce05c938b8cc828897fe9e95085197342a1377dd8850bf5125f15f + languageName: node + linkType: hard + +"tr46@npm:~0.0.3": + version: 0.0.3 + resolution: "tr46@npm:0.0.3" + checksum: 726321c5eaf41b5002e17ffbd1fb7245999a073e8979085dacd47c4b4e8068ff5777142fc6726d6ca1fd2ff16921b48788b87225cbc57c72636f6efa8efbffe3 + languageName: node + linkType: hard + +"tslib@npm:^2.1.0, tslib@npm:^2.4.0": + version: 2.7.0 + resolution: "tslib@npm:2.7.0" + checksum: 1606d5c89f88d466889def78653f3aab0f88692e80bb2066d090ca6112ae250ec1cfa9dbfaab0d17b60da15a4186e8ec4d893801c67896b277c17374e36e1d28 + languageName: node + linkType: hard + +"tsx@npm:^4.16.2": + version: 4.16.2 + resolution: "tsx@npm:4.16.2" + dependencies: + esbuild: ~0.21.5 + fsevents: ~2.3.3 + get-tsconfig: ^4.7.5 + dependenciesMeta: + fsevents: optional: true bin: - ts-node: dist/bin.js - ts-node-cwd: dist/bin-cwd.js - ts-node-esm: dist/bin-esm.js - ts-node-script: dist/bin-script.js - ts-node-transpile-only: dist/bin-transpile.js - ts-script: dist/bin-script-deprecated.js - checksum: fde256c9073969e234526e2cfead42591b9a2aec5222bac154b0de2fa9e4ceb30efcd717ee8bc785a56f3a119bdd5aa27b333d9dbec94ed254bd26f8944c67ac + tsx: dist/cli.mjs + checksum: bd481097d4614b9d40e7e2c44f7078d9f92b0050e959574a7a88ad8af33327d787f9d76c89689ee19b1275270038705fb9851055ae1a20e15d1c62a34d51a8fd + languageName: node + linkType: hard + +"typanion@npm:^3.14.0, typanion@npm:^3.8.0": + version: 3.14.0 + resolution: "typanion@npm:3.14.0" + checksum: fc0590d02c13c659eb1689e8adf7777e6c00dc911377e44cd36fe1b1271cfaca71547149f12cdc275058c0de5562a14e5273adbae66d47e6e0320e36007f5912 + languageName: node + linkType: hard + +"type-fest@npm:^0.13.1": + version: 0.13.1 + resolution: "type-fest@npm:0.13.1" + checksum: e6bf2e3c449f27d4ef5d56faf8b86feafbc3aec3025fc9a5fbe2db0a2587c44714521f9c30d8516a833c8c506d6263f5cc11267522b10c6ccdb6cc55b0a9d1c4 + languageName: node + linkType: hard + +"type-fest@npm:^0.21.3": + version: 0.21.3 + resolution: "type-fest@npm:0.21.3" + checksum: e6b32a3b3877f04339bae01c193b273c62ba7bfc9e325b8703c4ee1b32dc8fe4ef5dfa54bf78265e069f7667d058e360ae0f37be5af9f153b22382cd55a9afe0 languageName: node linkType: hard @@ -1505,10 +5031,49 @@ __metadata: languageName: node linkType: hard -"v8-compile-cache-lib@npm:^3.0.1": - version: 3.0.1 - resolution: "v8-compile-cache-lib@npm:3.0.1" - checksum: 78089ad549e21bcdbfca10c08850022b22024cdcc2da9b168bcf5a73a6ed7bf01a9cebb9eac28e03cd23a684d81e0502797e88f3ccd27a32aeab1cfc44c39da0 +"undici-types@npm:~6.19.2": + version: 6.19.8 + resolution: "undici-types@npm:6.19.8" + checksum: de51f1b447d22571cf155dfe14ff6d12c5bdaec237c765085b439c38ca8518fc360e88c70f99469162bf2e14188a7b0bcb06e1ed2dc031042b984b0bb9544017 + languageName: node + linkType: hard + +"unicorn-magic@npm:^0.1.0": + version: 0.1.0 + resolution: "unicorn-magic@npm:0.1.0" + checksum: 48c5882ca3378f380318c0b4eb1d73b7e3c5b728859b060276e0a490051d4180966beeb48962d850fd0c6816543bcdfc28629dcd030bb62a286a2ae2acb5acb6 + languageName: node + linkType: hard + +"unique-filename@npm:^3.0.0": + version: 3.0.0 + resolution: "unique-filename@npm:3.0.0" + dependencies: + unique-slug: ^4.0.0 + checksum: 8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df + languageName: node + linkType: hard + +"unique-slug@npm:^4.0.0": + version: 4.0.0 + resolution: "unique-slug@npm:4.0.0" + dependencies: + imurmurhash: ^0.1.4 + checksum: 0884b58365af59f89739e6f71e3feacb5b1b41f2df2d842d0757933620e6de08eff347d27e9d499b43c40476cbaf7988638d3acb2ffbcb9d35fd035591adfd15 + languageName: node + linkType: hard + +"universal-user-agent@npm:^7.0.0, universal-user-agent@npm:^7.0.2": + version: 7.0.2 + resolution: "universal-user-agent@npm:7.0.2" + checksum: 3f02cb6de0bb9fbaf379566bd0320d8e46af6e4358a2e88fce7e70687ed7b48b37f479d728bb22f4204a518e363f3038ac4841c033af1ee2253f6428a6c67e53 + languageName: node + linkType: hard + +"util-deprecate@npm:^1.0.1": + version: 1.0.2 + resolution: "util-deprecate@npm:1.0.2" + checksum: 474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 languageName: node linkType: hard @@ -1533,6 +5098,39 @@ __metadata: languageName: node linkType: hard +"wasm-sjlj@npm:^1.0.5": + version: 1.0.5 + resolution: "wasm-sjlj@npm:1.0.5" + dependencies: + node-gyp: latest + checksum: 3520b8fc201df62f1a90c4f636c85467bef81799deffa095245dd02594cb1f80840e89d9ce57c05e47b0b38b0ff27318b68a146871e310d00505c9d822f6f5fa + languageName: node + linkType: hard + +"webidl-conversions@npm:^3.0.0": + version: 3.0.1 + resolution: "webidl-conversions@npm:3.0.1" + checksum: c92a0a6ab95314bde9c32e1d0a6dfac83b578f8fa5f21e675bc2706ed6981bc26b7eb7e6a1fab158e5ce4adf9caa4a0aee49a52505d4d13c7be545f15021b17c + languageName: node + linkType: hard + +"well-known-symbols@npm:^2.0.0": + version: 2.0.0 + resolution: "well-known-symbols@npm:2.0.0" + checksum: 4f54bbc3012371cb4d228f436891b8e7536d34ac61a57541890257e96788608e096231e0121ac24d08ef2f908b3eb2dc0adba35023eaeb2a7df655da91415402 + languageName: node + linkType: hard + +"whatwg-url@npm:^5.0.0": + version: 5.0.0 + resolution: "whatwg-url@npm:5.0.0" + dependencies: + tr46: ~0.0.3 + webidl-conversions: ^3.0.0 + checksum: b8daed4ad3356cc4899048a15b2c143a9aed0dfae1f611ebd55073310c7b910f522ad75d727346ad64203d7e6c79ef25eafd465f4d12775ca44b90fa82ed9e2c + languageName: node + linkType: hard + "which@npm:^1.2.9": version: 1.3.1 resolution: "which@npm:1.3.1" @@ -1555,7 +5153,27 @@ __metadata: languageName: node linkType: hard -"wrap-ansi@npm:^7.0.0": +"which@npm:^4.0.0": + version: 4.0.0 + resolution: "which@npm:4.0.0" + dependencies: + isexe: ^3.1.1 + bin: + node-which: bin/which.js + checksum: f17e84c042592c21e23c8195108cff18c64050b9efb8459589116999ea9da6dd1509e6a1bac3aeebefd137be00fabbb61b5c2bc0aa0f8526f32b58ee2f545651 + languageName: node + linkType: hard + +"wide-align@npm:^1.1.2": + version: 1.1.5 + resolution: "wide-align@npm:1.1.5" + dependencies: + string-width: ^1.0.2 || 2 || 3 || 4 + checksum: d5fc37cd561f9daee3c80e03b92ed3e84d80dde3365a8767263d03dacfc8fa06b065ffe1df00d8c2a09f731482fcacae745abfbb478d4af36d0a891fad4834d3 + languageName: node + linkType: hard + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" dependencies: @@ -1566,6 +5184,17 @@ __metadata: languageName: node linkType: hard +"wrap-ansi@npm:^6.2.0": + version: 6.2.0 + resolution: "wrap-ansi@npm:6.2.0" + dependencies: + ansi-styles: ^4.0.0 + string-width: ^4.1.0 + strip-ansi: ^6.0.0 + checksum: 6cd96a410161ff617b63581a08376f0cb9162375adeb7956e10c8cd397821f7eb2a6de24eb22a0b28401300bf228c86e50617cd568209b5f6775b93c97d2fe3a + languageName: node + linkType: hard + "wrap-ansi@npm:^8.0.1, wrap-ansi@npm:^8.1.0": version: 8.1.0 resolution: "wrap-ansi@npm:8.1.0" @@ -1584,6 +5213,16 @@ __metadata: languageName: node linkType: hard +"write-file-atomic@npm:^5.0.1": + version: 5.0.1 + resolution: "write-file-atomic@npm:5.0.1" + dependencies: + imurmurhash: ^0.1.4 + signal-exit: ^4.0.1 + checksum: 8dbb0e2512c2f72ccc20ccedab9986c7d02d04039ed6e8780c987dc4940b793339c50172a1008eed7747001bfacc0ca47562668a069a7506c46c77d7ba3926a9 + languageName: node + linkType: hard + "y18n@npm:^5.0.5": version: 5.0.8 resolution: "y18n@npm:5.0.8" @@ -1627,19 +5266,12 @@ __metadata: languageName: node linkType: hard -"yjs@npm:^13.6.8": - version: 13.6.8 - resolution: "yjs@npm:13.6.8" +"yjs@npm:^13.6.18": + version: 13.6.18 + resolution: "yjs@npm:13.6.18" dependencies: - lib0: ^0.2.74 - checksum: a2a6fd17a2cce6461b64bedd69f66845b9dfd4702e285be0b5e382840337232e54ba5cf5d48f871263074de625d3902d17ab8a1766695af3fc05a0b4da8d95e0 - languageName: node - linkType: hard - -"yn@npm:3.1.1": - version: 3.1.1 - resolution: "yn@npm:3.1.1" - checksum: 2c487b0e149e746ef48cda9f8bad10fc83693cd69d7f9dcd8be4214e985de33a29c9e24f3c0d6bcf2288427040a8947406ab27f7af67ee9456e6b84854f02dd6 + lib0: ^0.2.86 + checksum: 5c9f8f31f5f9f30f17680a765b015e4274820fe10fb6bf6a7d39dee2ff0493a81ace02d11bff6f18c6799cade2bcfc9fc2d7b6ca8bc1eb167c4ac2f3789c0f01 languageName: node linkType: hard @@ -1649,3 +5281,10 @@ __metadata: checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 languageName: node linkType: hard + +"yoctocolors-cjs@npm:^2.1.2": + version: 2.1.2 + resolution: "yoctocolors-cjs@npm:2.1.2" + checksum: 1c474d4b30a8c130e679279c5c2c33a0d48eba9684ffa0252cc64846c121fb56c3f25457fef902edbe1e2d7a7872130073a9fc8e795299d75e13fa3f5f548f1b + languageName: node + linkType: hard