Highly ambitious ATProtocol AppView service and sdks

fix lexicon intellisense build

Changed files
+602 -633
packages
+1 -2
deno.json
··· 12 12 "dev:cli": "deno run --allow-all packages/cli/src/mod.ts", 13 13 "build:cli": "cd packages/cli && deno compile --allow-all --output bin/slices src/mod.ts", 14 14 "build:lexicon": "cd packages/lexicon && deno task build", 15 + "build:lexicon-intellisense": "cd ./packages/lexicon-rs && wasm-pack build --target web --features wasm && cp pkg/* ../lexicon-intellisense/wasm/", 15 16 "codegen:cli": "deno task dev:cli codegen --lexicons ./lexicons --slice at://did:plc:bcgltzqazw5tb6k2g3ttenbj/network.slices.slice/3lymhd4jhrd2z --output ./packages/cli/src/generated_client.ts --include-slices", 16 17 "codegen:frontend": "deno task dev:cli codegen --lexicons ./lexicons --slice at://did:plc:bcgltzqazw5tb6k2g3ttenbj/network.slices.slice/3lymhd4jhrd2z --output ./frontend/src/client.ts --include-slices", 17 18 "dev:frontend": "cd frontend && deno task dev", 18 - "build:lexicon-intellisense-wasm": "cd ./packages/lexicon-rs && wasm-pack build --target web --features wasm && cp pkg/* ../lexicon-intellisense/wasm/", 19 - "build:lexicon-intellisense-lexicon": "deno bundle ./packages/lexicon/mod.ts -o ./packages/lexicon-intellisense/src/slices_lexicon.js", 20 19 "test": "deno test --allow-all packages/*/tests/ packages/*/src/ frontend/src/", 21 20 "check": "deno check packages/*/src/ packages/*/mod.ts packages/*/src/mod.ts frontend/src/**/*.ts frontend/src/**/*.tsx", 22 21 "fmt": "deno fmt packages/ frontend/",
+2 -2
packages/lexicon-intellisense/package.json
··· 1 1 { 2 2 "name": "lexicon-intellisense", 3 - "version": "0.2.0", 3 + "version": "0.2.1", 4 4 "description": "VS Code IntelliSense support for AT Protocol lexicon JSON files", 5 5 "main": "./out/extension.js", 6 6 "license": "MIT", ··· 59 59 } 60 60 }, 61 61 "scripts": { 62 - "compile": "tsc -p ./", 62 + "compile": "rm -rf ./out && tsc -p ./", 63 63 "watch": "tsc -watch -p ./" 64 64 }, 65 65 "devDependencies": {
+29 -34
packages/lexicon-intellisense/src/language-server.ts
··· 7 7 ServerOptions, 8 8 TransportKind, 9 9 } from "vscode-languageclient/node"; 10 - // @ts-ignore - No declaration file for bundled module 11 10 import { 12 11 LexiconValidator, 13 12 ValidationError, 14 13 validate, 15 14 validateWithDetails, 16 - // @ts-ignore 17 - } from "./slices_lexicon.js"; 18 - 19 - // Type definitions for lexicon documents 20 - interface LexiconDoc { 21 - id: string; 22 - defs: Record<string, unknown>; 23 - lexicon?: number; 24 - } 15 + type LexiconDoc, 16 + } from "./lexicon"; 25 17 26 18 export class LexiconLanguageServer { 27 19 private client: LanguageClient | undefined; ··· 186 178 const lexicon = JSON.parse(content); 187 179 console.log(lexicon.id, "loaded from", filePath); 188 180 if (lexicon.id && lexicon.defs) { 189 - lexicons.push(lexicon as LexiconDoc); 181 + lexicons.push(lexicon); 190 182 idToFileMap.set(lexicon.id, filePath); 191 183 } 192 184 } catch (error) { ··· 204 196 // Attribute errors to specific files 205 197 if (errorsByLexiconId) { 206 198 for (const [lexiconId, errors] of Object.entries(errorsByLexiconId)) { 207 - const filePath = idToFileMap.get(lexiconId); 208 - if (filePath) { 209 - const uri = vscode.Uri.file(filePath); 210 - const existingDiagnostics = 211 - this.diagnosticCollection.get(uri) || []; 212 - const diagnostics = [...existingDiagnostics]; 199 + const filePath = idToFileMap.get(lexiconId); 200 + if (filePath) { 201 + const uri = vscode.Uri.file(filePath); 202 + const existingDiagnostics = 203 + this.diagnosticCollection.get(uri) || []; 204 + const diagnostics = [...existingDiagnostics]; 213 205 214 - // Add each error as a diagnostic 215 - for (const error of errors as string[]) { 216 - diagnostics.push( 217 - this.createDiagnostic( 218 - new vscode.Range(0, 0, 0, 0), 219 - error, 220 - vscode.DiagnosticSeverity.Error 221 - ) 222 - ); 206 + // Add each error as a diagnostic 207 + for (const error of errors as string[]) { 208 + diagnostics.push( 209 + this.createDiagnostic( 210 + new vscode.Range(0, 0, 0, 0), 211 + error, 212 + vscode.DiagnosticSeverity.Error 213 + ) 214 + ); 215 + } 216 + 217 + this.diagnosticCollection.set(uri, diagnostics); 223 218 } 224 - 225 - this.diagnosticCollection.set(uri, diagnostics); 226 - } 227 219 } 228 220 } 229 221 230 - const totalErrors = errorsByLexiconId ? Object.values(errorsByLexiconId).reduce( 231 - (sum: number, errors) => sum + (errors as string[]).length, 232 - 0 233 - ) : 0; 222 + const totalErrors = errorsByLexiconId 223 + ? Object.values(errorsByLexiconId).reduce( 224 + (sum: number, errors) => sum + (errors as string[]).length, 225 + 0 226 + ) 227 + : 0; 234 228 if (totalErrors === 0) { 235 229 console.log( 236 230 `Successfully validated ${lexicons.length} lexicon files` 237 231 ); 238 232 } else { 233 + const errorCount = errorsByLexiconId ? Object.keys(errorsByLexiconId).length : 0; 239 234 console.log( 240 - `Validation found ${totalErrors} errors across ${errorsByLexiconId.size} lexicons` 235 + `Validation found ${totalErrors} errors across ${errorCount} lexicons` 241 236 ); 242 237 } 243 238 } catch (error) {
+570
packages/lexicon-intellisense/src/lexicon.ts
··· 1 + /** 2 + * AT Protocol Lexicon Validation Library 3 + * 4 + * Core implementation for comprehensive validation of AT Protocol lexicon documents and data records. 5 + * Built on WebAssembly for high performance validation with full AT Protocol compliance. 6 + */ 7 + 8 + import init, { 9 + WasmLexiconValidator, 10 + validate_string_format, 11 + is_valid_nsid, 12 + validate_lexicons_and_get_errors, 13 + } from "../wasm/slices_lexicon.js"; 14 + 15 + // ============================================================================ 16 + // Module Initialization 17 + // ============================================================================ 18 + 19 + /** Global WASM initialization state */ 20 + let wasmInitialized = false; 21 + let wasmInitPromise: Promise<void> | null = null; 22 + 23 + /** 24 + * Ensures the WebAssembly module is properly initialized before use. 25 + * This is called automatically by all public methods. 26 + * 27 + * @internal 28 + */ 29 + export async function ensureWasmInit(): Promise<void> { 30 + if (!wasmInitialized) { 31 + if (!wasmInitPromise) { 32 + wasmInitPromise = (async () => { 33 + // Try to load WASM file - works in both Node.js and browser contexts 34 + try { 35 + // In Node.js (VS Code extension), use fs to load the file 36 + if (typeof process !== 'undefined' && process.versions && process.versions.node) { 37 + const fs = require('fs'); 38 + const path = require('path'); 39 + 40 + // Use __dirname which is available in CommonJS 41 + const wasmPath = path.join(__dirname, '../wasm/slices_lexicon_bg.wasm'); 42 + const wasmBuffer = fs.readFileSync(wasmPath); 43 + await init({ module_or_path: wasmBuffer }); 44 + } else { 45 + // In browser, fetch the WASM file 46 + const wasmPath = '../wasm/slices_lexicon_bg.wasm'; 47 + const response = await fetch(wasmPath); 48 + const wasmBuffer = await response.arrayBuffer(); 49 + await init({ module_or_path: wasmBuffer }); 50 + } 51 + wasmInitialized = true; 52 + } catch (error) { 53 + wasmInitPromise = null; // Reset so we can retry 54 + throw error; 55 + } 56 + })(); 57 + } 58 + await wasmInitPromise; 59 + } 60 + } 61 + 62 + // ============================================================================ 63 + // Types and Interfaces 64 + // ============================================================================ 65 + 66 + /** 67 + * Custom error class for lexicon validation failures. 68 + * Extends the native Error class with validation-specific context. 69 + */ 70 + export class ValidationError extends Error { 71 + /** 72 + * Creates a new ValidationError instance. 73 + * 74 + * @param message - Human-readable error description 75 + */ 76 + constructor(message: string) { 77 + super(message); 78 + this.name = "ValidationError"; 79 + } 80 + } 81 + 82 + /** 83 + * Represents a complete AT Protocol lexicon document. 84 + * Contains schema definitions and metadata for a specific collection or service. 85 + */ 86 + export interface LexiconDoc { 87 + /** Unique namespace identifier (NSID) for this lexicon */ 88 + id: string; 89 + 90 + /** Schema definitions mapping definition names to their schemas */ 91 + defs: Record<string, LexiconDefinition>; 92 + 93 + /** Lexicon format version (currently 1) */ 94 + lexicon?: number; 95 + } 96 + 97 + /** 98 + * Base lexicon definition interface 99 + */ 100 + export interface LexiconDefinition { 101 + type: string; 102 + description?: string; 103 + [key: string]: unknown; // Allow additional properties 104 + } 105 + 106 + /** 107 + * String format types supported by AT Protocol 108 + */ 109 + export type StringFormat = 110 + | "datetime" 111 + | "uri" 112 + | "at-uri" 113 + | "did" 114 + | "handle" 115 + | "at-identifier" 116 + | "nsid" 117 + | "cid" 118 + | "language" 119 + | "tid" 120 + | "record-key"; 121 + 122 + /** 123 + * Type alias for validation error results 124 + */ 125 + export type ValidationErrors = Record<string, string[]> | null; 126 + 127 + /** 128 + * Comprehensive validation result with error details and statistics. 129 + */ 130 + export interface ValidationResult { 131 + /** Whether all lexicons passed validation */ 132 + valid: boolean; 133 + 134 + /** Map of lexicon IDs to their error messages */ 135 + errors: Record<string, string[]>; 136 + 137 + /** Total count of all validation errors across all lexicons */ 138 + totalErrors: number; 139 + 140 + /** Number of lexicons that have validation errors */ 141 + lexiconsWithErrors: number; 142 + } 143 + 144 + /** 145 + * Detailed error context information for debugging validation failures. 146 + */ 147 + export interface ErrorContext { 148 + /** Current path in the schema being validated */ 149 + path: string; 150 + 151 + /** ID of the lexicon currently being validated */ 152 + current_lexicon: string | null; 153 + 154 + /** Whether a circular reference was detected */ 155 + has_circular_reference: boolean; 156 + 157 + /** Stack of references being resolved (for circular detection) */ 158 + reference_stack: string[]; 159 + } 160 + 161 + // ============================================================================ 162 + // Core Validator Class 163 + // ============================================================================ 164 + 165 + /** 166 + * High-performance AT Protocol lexicon validator with resource management. 167 + * 168 + * Provides comprehensive validation capabilities including: 169 + * - Schema structure validation 170 + * - Cross-reference resolution 171 + * - Data format validation 172 + * - Circular dependency detection 173 + * 174 + * Implements Disposable for automatic resource cleanup. 175 + */ 176 + export class LexiconValidator implements Disposable { 177 + private wasmValidator: WasmLexiconValidator; 178 + 179 + /** 180 + * Creates a new validator instance with the provided lexicon documents. 181 + * 182 + * Note: Prefer using the static `create()` method for async initialization. 183 + * 184 + * @param lexicons - Array of lexicon documents to validate 185 + */ 186 + constructor(lexicons: LexiconDoc[]) { 187 + const lexiconsJson = JSON.stringify(lexicons); 188 + this.wasmValidator = new WasmLexiconValidator(lexiconsJson); 189 + } 190 + 191 + /** 192 + * Creates a new validator instance with proper async initialization. 193 + * Ensures WASM module is loaded before creating the validator. 194 + * 195 + * @param lexicons - Array of lexicon documents to validate 196 + * @returns Promise resolving to a new validator instance 197 + * 198 + * @example 199 + * ```typescript 200 + * const lexicons = [{ id: "com.example.post", defs: {...} }]; 201 + * const validator = await LexiconValidator.create(lexicons); 202 + * ``` 203 + */ 204 + static async create(lexicons: LexiconDoc[]): Promise<LexiconValidator> { 205 + await ensureWasmInit(); 206 + return new LexiconValidator(lexicons); 207 + } 208 + 209 + /** 210 + * Validates a data record against its collection's lexicon schema. 211 + * 212 + * Performs comprehensive validation including: 213 + * - Type checking 214 + * - Constraint validation 215 + * - Format validation 216 + * - Required field checking 217 + * 218 + * @param collection - NSID of the collection (lexicon) to validate against 219 + * @param record - Data record to validate 220 + * @throws {ValidationError} If validation fails 221 + * 222 + * @example 223 + * ```typescript 224 + * validator.validateRecord("com.example.post", { 225 + * text: "Hello world!", 226 + * createdAt: "2024-01-01T12:00:00Z" 227 + * }); 228 + * ``` 229 + */ 230 + validateRecord(collection: string, record: Record<string, unknown>): void { 231 + try { 232 + const recordJson = JSON.stringify(record); 233 + this.wasmValidator.validate_record(collection, recordJson); 234 + } catch (error) { 235 + throw new ValidationError( 236 + error instanceof Error ? error.message : String(error) 237 + ); 238 + } 239 + } 240 + 241 + /** 242 + * Validates all lexicon documents and returns comprehensive error information. 243 + * 244 + * Uses the enhanced validation system that collects ALL errors for each lexicon, 245 + * not just the first error encountered. 246 + * 247 + * @returns Null if validation passes, or error map if validation fails 248 + * 249 + * @example 250 + * ```typescript 251 + * const errors = validator.validateLexicons(); 252 + * if (errors) { 253 + * console.log(`Found errors in ${Object.keys(errors).length} lexicons`); 254 + * } 255 + * ``` 256 + */ 257 + validateLexicons(): Record<string, string[]> | null { 258 + try { 259 + const result = this.wasmValidator.validate_lexicons(); 260 + const errorMap = JSON.parse(result); 261 + 262 + // Return null for success case (no errors) 263 + if (Object.keys(errorMap).length === 0) { 264 + return null; 265 + } 266 + 267 + return errorMap; 268 + } catch (error) { 269 + throw new ValidationError( 270 + error instanceof Error ? error.message : String(error) 271 + ); 272 + } 273 + } 274 + 275 + /** 276 + * Checks for unresolved references across the lexicon set. 277 + * 278 + * Identifies references (like "$ref": "com.example.collection#definition") 279 + * that point to non-existent lexicons or definitions. 280 + * 281 + * @returns Array of unresolved reference strings 282 + * 283 + * @example 284 + * ```typescript 285 + * const unresolved = validator.checkReferences(); 286 + * if (unresolved.length > 0) { 287 + * console.log("Unresolved references:", unresolved); 288 + * } 289 + * ``` 290 + */ 291 + checkReferences(): string[] { 292 + try { 293 + const result = this.wasmValidator.check_references(); 294 + return JSON.parse(result); 295 + } catch (error) { 296 + throw new ValidationError( 297 + error instanceof Error ? error.message : String(error) 298 + ); 299 + } 300 + } 301 + 302 + /** 303 + * Retrieves detailed error context for debugging validation failures. 304 + * 305 + * Provides path information, current lexicon context, and circular 306 + * reference detection state for enhanced debugging. 307 + * 308 + * @param path - Schema path to get context for 309 + * @returns Detailed error context information 310 + * 311 + * @example 312 + * ```typescript 313 + * const context = validator.getErrorContext("com.example.post#main"); 314 + * console.log(`Validating at path: ${context.path}`); 315 + * ``` 316 + */ 317 + getErrorContext(path: string): ErrorContext { 318 + try { 319 + const result = this.wasmValidator.get_error_context(path); 320 + return JSON.parse(result); 321 + } catch (error) { 322 + throw new ValidationError( 323 + error instanceof Error ? error.message : String(error) 324 + ); 325 + } 326 + } 327 + 328 + /** 329 + * Manually releases WASM resources. 330 + * 331 + * Call this when done with the validator to free memory. 332 + * Automatically called by dispose methods when using `using` syntax. 333 + */ 334 + free(): void { 335 + this.wasmValidator.free(); 336 + } 337 + 338 + /** 339 + * Synchronous dispose method for automatic resource cleanup. 340 + * Called automatically when using `using` keyword. 341 + * 342 + * @example 343 + * ```typescript 344 + * using validator = await LexiconValidator.create(lexicons); 345 + * // Automatically cleaned up at end of scope 346 + * ``` 347 + */ 348 + [Symbol.dispose](): void { 349 + this.free(); 350 + } 351 + 352 + /** 353 + * Asynchronous dispose method for automatic resource cleanup. 354 + * Called automatically when using `await using` keyword. 355 + */ 356 + async [Symbol.asyncDispose](): Promise<void> { 357 + await Promise.resolve(this.free()); 358 + } 359 + } 360 + 361 + // ============================================================================ 362 + // Standalone Validation Functions 363 + // ============================================================================ 364 + 365 + /** 366 + * Validates lexicon documents using the enhanced validation system. 367 + * 368 + * This is the primary validation function that collects ALL validation errors 369 + * for each lexicon, enabling comprehensive error reporting. 370 + * 371 + * @param lexicons - Array of lexicon documents to validate 372 + * @returns Null if validation succeeds, or error map if validation fails 373 + * 374 + * @example 375 + * ```typescript 376 + * const errors = await validate([ 377 + * { id: "com.example.post", defs: {...} }, 378 + * { id: "com.example.user", defs: {...} } 379 + * ]); 380 + * 381 + * if (errors) { 382 + * for (const [lexiconId, errorList] of Object.entries(errors)) { 383 + * console.log(`${lexiconId}: ${errorList.length} errors`); 384 + * } 385 + * } 386 + * ``` 387 + */ 388 + export async function validate( 389 + lexicons: LexiconDoc[] 390 + ): Promise<Record<string, string[]> | null> { 391 + await ensureWasmInit(); 392 + 393 + const lexiconsJson = JSON.stringify(lexicons); 394 + const result = validate_lexicons_and_get_errors(lexiconsJson); 395 + const errorMap = JSON.parse(result); 396 + 397 + // Success case: no errors found 398 + if (Object.keys(errorMap).length === 0) { 399 + return null; 400 + } 401 + 402 + // Return complete error map with all errors for each lexicon 403 + return errorMap; 404 + } 405 + 406 + /** 407 + * Enhanced validation function with comprehensive result statistics. 408 + * 409 + * Provides detailed validation results including error counts and statistics 410 + * for better reporting and debugging. 411 + * 412 + * @param lexicons - Array of lexicon documents to validate 413 + * @returns Detailed validation result with statistics 414 + * 415 + * @example 416 + * ```typescript 417 + * const result = await validateWithDetails(lexicons); 418 + * console.log(`Validation ${result.valid ? 'passed' : 'failed'}`); 419 + * console.log(`Total errors: ${result.totalErrors}`); 420 + * console.log(`Lexicons with errors: ${result.lexiconsWithErrors}`); 421 + * ``` 422 + */ 423 + export async function validateWithDetails( 424 + lexicons: LexiconDoc[] 425 + ): Promise<ValidationResult> { 426 + const errors = await validate(lexicons); 427 + 428 + if (errors === null) { 429 + return { 430 + valid: true, 431 + errors: {}, 432 + totalErrors: 0, 433 + lexiconsWithErrors: 0, 434 + }; 435 + } 436 + 437 + const totalErrors = Object.values(errors).reduce( 438 + (sum, errorArray) => sum + errorArray.length, 439 + 0 440 + ); 441 + 442 + return { 443 + valid: false, 444 + errors, 445 + totalErrors, 446 + lexiconsWithErrors: Object.keys(errors).length, 447 + }; 448 + } 449 + 450 + /** 451 + * Validates a single data record against lexicon schemas. 452 + * 453 + * Convenience function that creates a temporary validator instance 454 + * and automatically manages resources. 455 + * 456 + * @param lexicons - Array of lexicon documents containing the target schema 457 + * @param collection - NSID of the collection to validate against 458 + * @param record - Data record to validate 459 + * @throws {ValidationError} If validation fails 460 + * 461 + * @example 462 + * ```typescript 463 + * await validateRecord(lexicons, "com.example.post", { 464 + * text: "Hello world!", 465 + * createdAt: "2024-01-01T12:00:00Z" 466 + * }); 467 + * ``` 468 + */ 469 + export async function validateRecord( 470 + lexicons: LexiconDoc[], 471 + collection: string, 472 + record: Record<string, unknown> 473 + ): Promise<void> { 474 + return await withValidator(lexicons, (validator) => { 475 + validator.validateRecord(collection, record); 476 + }); 477 + } 478 + 479 + // ============================================================================ 480 + // Format and Utility Functions 481 + // ============================================================================ 482 + 483 + /** 484 + * Validates a string value against a specific AT Protocol format. 485 + * 486 + * Supports all AT Protocol string formats including: 487 + * - datetime (RFC 3339) 488 + * - uri, at-uri 489 + * - did, handle 490 + * - cid, tid 491 + * - language (BCP 47) 492 + * 493 + * @param value - String value to validate 494 + * @param format - AT Protocol format name 495 + * @throws {ValidationError} If format validation fails 496 + * 497 + * @example 498 + * ```typescript 499 + * await validateStringFormat("2024-01-01T12:00:00Z", "datetime"); 500 + * await validateStringFormat("did:plc:example123", "did"); 501 + * ``` 502 + */ 503 + export async function validateStringFormat( 504 + value: string, 505 + format: string 506 + ): Promise<void> { 507 + await ensureWasmInit(); 508 + try { 509 + validate_string_format(value, format); 510 + } catch (error) { 511 + throw new ValidationError( 512 + error instanceof Error ? error.message : String(error) 513 + ); 514 + } 515 + } 516 + 517 + /** 518 + * Checks if a string is a valid NSID (Namespaced Identifier). 519 + * 520 + * NSIDs are used throughout AT Protocol to identify lexicons, collections, 521 + * and procedures. They follow reverse-domain-name format with at least 522 + * 3 segments (e.g., "com.example.collection"). 523 + * 524 + * @param nsid - String to validate as NSID 525 + * @returns True if valid NSID, false otherwise 526 + * 527 + * @example 528 + * ```typescript 529 + * console.log(await isValidNsid("com.example.post")); // true 530 + * console.log(await isValidNsid("invalid-nsid")); // false 531 + * ``` 532 + */ 533 + export async function isValidNsid(nsid: string): Promise<boolean> { 534 + await ensureWasmInit(); 535 + return is_valid_nsid(nsid); 536 + } 537 + 538 + // ============================================================================ 539 + // Resource Management Utilities 540 + // ============================================================================ 541 + 542 + /** 543 + * Utility function for automatic validator lifecycle management. 544 + * 545 + * Uses the callback pattern to ensure WASM resources are properly 546 + * cleaned up, even if an exception occurs during validation. 547 + * 548 + * @param lexicons - Array of lexicon documents 549 + * @param callback - Function to execute with the validator 550 + * @returns Promise resolving to the callback's return value 551 + * 552 + * @example 553 + * ```typescript 554 + * const result = await withValidator(lexicons, (validator) => { 555 + * validator.validateRecord("com.example.post", record); 556 + * return "validation passed"; 557 + * }); 558 + * ``` 559 + */ 560 + export async function withValidator<T>( 561 + lexicons: LexiconDoc[], 562 + callback: (validator: LexiconValidator) => T | Promise<T> 563 + ): Promise<T> { 564 + const validator = await LexiconValidator.create(lexicons); 565 + try { 566 + return await callback(validator); 567 + } finally { 568 + validator.free(); 569 + } 570 + }
-595
packages/lexicon-intellisense/src/slices_lexicon.js
··· 1 - // packages/lexicon/wasm/slices_lexicon.js 2 - var wasm; 3 - var cachedUint8ArrayMemory0 = null; 4 - function getUint8ArrayMemory0() { 5 - if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) { 6 - cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); 7 - } 8 - return cachedUint8ArrayMemory0; 9 - } 10 - var cachedTextDecoder = typeof TextDecoder !== "undefined" ? new TextDecoder("utf-8", { 11 - ignoreBOM: true, 12 - fatal: true 13 - }) : { 14 - decode: () => { 15 - throw Error("TextDecoder not available"); 16 - } 17 - }; 18 - if (typeof TextDecoder !== "undefined") { 19 - cachedTextDecoder.decode(); 20 - } 21 - var MAX_SAFARI_DECODE_BYTES = 2146435072; 22 - var numBytesDecoded = 0; 23 - function decodeText(ptr, len) { 24 - numBytesDecoded += len; 25 - if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) { 26 - cachedTextDecoder = typeof TextDecoder !== "undefined" ? new TextDecoder("utf-8", { 27 - ignoreBOM: true, 28 - fatal: true 29 - }) : { 30 - decode: () => { 31 - throw Error("TextDecoder not available"); 32 - } 33 - }; 34 - cachedTextDecoder.decode(); 35 - numBytesDecoded = len; 36 - } 37 - return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len)); 38 - } 39 - function getStringFromWasm0(ptr, len) { 40 - ptr = ptr >>> 0; 41 - return decodeText(ptr, len); 42 - } 43 - var WASM_VECTOR_LEN = 0; 44 - var cachedTextEncoder = typeof TextEncoder !== "undefined" ? new TextEncoder("utf-8") : { 45 - encode: () => { 46 - throw Error("TextEncoder not available"); 47 - } 48 - }; 49 - var encodeString = typeof cachedTextEncoder.encodeInto === "function" ? function(arg, view) { 50 - return cachedTextEncoder.encodeInto(arg, view); 51 - } : function(arg, view) { 52 - const buf = cachedTextEncoder.encode(arg); 53 - view.set(buf); 54 - return { 55 - read: arg.length, 56 - written: buf.length 57 - }; 58 - }; 59 - function passStringToWasm0(arg, malloc, realloc) { 60 - if (realloc === void 0) { 61 - const buf = cachedTextEncoder.encode(arg); 62 - const ptr2 = malloc(buf.length, 1) >>> 0; 63 - getUint8ArrayMemory0().subarray(ptr2, ptr2 + buf.length).set(buf); 64 - WASM_VECTOR_LEN = buf.length; 65 - return ptr2; 66 - } 67 - let len = arg.length; 68 - let ptr = malloc(len, 1) >>> 0; 69 - const mem = getUint8ArrayMemory0(); 70 - let offset = 0; 71 - for (; offset < len; offset++) { 72 - const code = arg.charCodeAt(offset); 73 - if (code > 127) break; 74 - mem[ptr + offset] = code; 75 - } 76 - if (offset !== len) { 77 - if (offset !== 0) { 78 - arg = arg.slice(offset); 79 - } 80 - ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; 81 - const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); 82 - const ret = encodeString(arg, view); 83 - offset += ret.written; 84 - ptr = realloc(ptr, len, offset, 1) >>> 0; 85 - } 86 - WASM_VECTOR_LEN = offset; 87 - return ptr; 88 - } 89 - var cachedDataViewMemory0 = null; 90 - function getDataViewMemory0() { 91 - if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || cachedDataViewMemory0.buffer.detached === void 0 && cachedDataViewMemory0.buffer !== wasm.memory.buffer) { 92 - cachedDataViewMemory0 = new DataView(wasm.memory.buffer); 93 - } 94 - return cachedDataViewMemory0; 95 - } 96 - function takeFromExternrefTable0(idx) { 97 - const value = wasm.__wbindgen_export_3.get(idx); 98 - wasm.__externref_table_dealloc(idx); 99 - return value; 100 - } 101 - function validate_lexicons_and_get_errors(lexicons_json) { 102 - let deferred2_0; 103 - let deferred2_1; 104 - try { 105 - const ptr0 = passStringToWasm0(lexicons_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 106 - const len0 = WASM_VECTOR_LEN; 107 - const ret = wasm.validate_lexicons_and_get_errors(ptr0, len0); 108 - deferred2_0 = ret[0]; 109 - deferred2_1 = ret[1]; 110 - return getStringFromWasm0(ret[0], ret[1]); 111 - } finally { 112 - wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); 113 - } 114 - } 115 - function validate_string_format(value, format) { 116 - const ptr0 = passStringToWasm0(value, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 117 - const len0 = WASM_VECTOR_LEN; 118 - const ptr1 = passStringToWasm0(format, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 119 - const len1 = WASM_VECTOR_LEN; 120 - const ret = wasm.validate_string_format(ptr0, len0, ptr1, len1); 121 - if (ret[1]) { 122 - throw takeFromExternrefTable0(ret[0]); 123 - } 124 - } 125 - function is_valid_nsid(nsid) { 126 - const ptr0 = passStringToWasm0(nsid, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 127 - const len0 = WASM_VECTOR_LEN; 128 - const ret = wasm.is_valid_nsid(ptr0, len0); 129 - return ret !== 0; 130 - } 131 - var WasmLexiconValidatorFinalization = typeof FinalizationRegistry === "undefined" ? { 132 - register: () => { 133 - }, 134 - unregister: () => { 135 - } 136 - } : new FinalizationRegistry((ptr) => wasm.__wbg_wasmlexiconvalidator_free(ptr >>> 0, 1)); 137 - var WasmLexiconValidator = class { 138 - __destroy_into_raw() { 139 - const ptr = this.__wbg_ptr; 140 - this.__wbg_ptr = 0; 141 - WasmLexiconValidatorFinalization.unregister(this); 142 - return ptr; 143 - } 144 - free() { 145 - const ptr = this.__destroy_into_raw(); 146 - wasm.__wbg_wasmlexiconvalidator_free(ptr, 0); 147 - } 148 - /** 149 - * Create a new validator with the given lexicon documents 150 - * Takes a JSON string containing an array of lexicon documents 151 - * @param {string} lexicons_json 152 - */ 153 - constructor(lexicons_json) { 154 - const ptr0 = passStringToWasm0(lexicons_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 155 - const len0 = WASM_VECTOR_LEN; 156 - const ret = wasm.wasmlexiconvalidator_new(ptr0, len0); 157 - if (ret[2]) { 158 - throw takeFromExternrefTable0(ret[1]); 159 - } 160 - this.__wbg_ptr = ret[0] >>> 0; 161 - WasmLexiconValidatorFinalization.register(this, this.__wbg_ptr, this); 162 - return this; 163 - } 164 - /** 165 - * Validate a record against its collection's lexicon 166 - * Takes collection name and record as JSON strings 167 - * @param {string} collection 168 - * @param {string} record_json 169 - */ 170 - validate_record(collection, record_json) { 171 - const ptr0 = passStringToWasm0(collection, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 172 - const len0 = WASM_VECTOR_LEN; 173 - const ptr1 = passStringToWasm0(record_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 174 - const len1 = WASM_VECTOR_LEN; 175 - const ret = wasm.wasmlexiconvalidator_validate_record(this.__wbg_ptr, ptr0, len0, ptr1, len1); 176 - if (ret[1]) { 177 - throw takeFromExternrefTable0(ret[0]); 178 - } 179 - } 180 - /** 181 - * Validate lexicon documents and return detailed validation results 182 - * Returns a JSON string containing validation results with enhanced error context 183 - * @returns {string} 184 - */ 185 - validate_lexicons() { 186 - let deferred1_0; 187 - let deferred1_1; 188 - try { 189 - const ret = wasm.wasmlexiconvalidator_validate_lexicons(this.__wbg_ptr); 190 - deferred1_0 = ret[0]; 191 - deferred1_1 = ret[1]; 192 - return getStringFromWasm0(ret[0], ret[1]); 193 - } finally { 194 - wasm.__wbindgen_free(deferred1_0, deferred1_1, 1); 195 - } 196 - } 197 - /** 198 - * Check if all references in the lexicon set can be resolved 199 - * Returns a JSON string with any unresolved references 200 - * @returns {string} 201 - */ 202 - check_references() { 203 - let deferred1_0; 204 - let deferred1_1; 205 - try { 206 - const ret = wasm.wasmlexiconvalidator_check_references(this.__wbg_ptr); 207 - deferred1_0 = ret[0]; 208 - deferred1_1 = ret[1]; 209 - return getStringFromWasm0(ret[0], ret[1]); 210 - } finally { 211 - wasm.__wbindgen_free(deferred1_0, deferred1_1, 1); 212 - } 213 - } 214 - /** 215 - * Get detailed error context for validation failures 216 - * Returns enhanced error information with path context 217 - * @param {string} path 218 - * @returns {string} 219 - */ 220 - get_error_context(path) { 221 - let deferred2_0; 222 - let deferred2_1; 223 - try { 224 - const ptr0 = passStringToWasm0(path, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 225 - const len0 = WASM_VECTOR_LEN; 226 - const ret = wasm.wasmlexiconvalidator_get_error_context(this.__wbg_ptr, ptr0, len0); 227 - deferred2_0 = ret[0]; 228 - deferred2_1 = ret[1]; 229 - return getStringFromWasm0(ret[0], ret[1]); 230 - } finally { 231 - wasm.__wbindgen_free(deferred2_0, deferred2_1, 1); 232 - } 233 - } 234 - }; 235 - var EXPECTED_RESPONSE_TYPES = /* @__PURE__ */ new Set([ 236 - "basic", 237 - "cors", 238 - "default" 239 - ]); 240 - async function __wbg_load(module, imports) { 241 - if (typeof Response === "function" && module instanceof Response) { 242 - if (typeof WebAssembly.instantiateStreaming === "function") { 243 - try { 244 - return await WebAssembly.instantiateStreaming(module, imports); 245 - } catch (e) { 246 - const validResponse = module.ok && EXPECTED_RESPONSE_TYPES.has(module.type); 247 - if (validResponse && module.headers.get("Content-Type") !== "application/wasm") { 248 - console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e); 249 - } else { 250 - throw e; 251 - } 252 - } 253 - } 254 - const bytes = await module.arrayBuffer(); 255 - return await WebAssembly.instantiate(bytes, imports); 256 - } else { 257 - const instance = await WebAssembly.instantiate(module, imports); 258 - if (instance instanceof WebAssembly.Instance) { 259 - return { 260 - instance, 261 - module 262 - }; 263 - } else { 264 - return instance; 265 - } 266 - } 267 - } 268 - function __wbg_get_imports() { 269 - const imports = {}; 270 - imports.wbg = {}; 271 - imports.wbg.__wbg_error_7534b8e9a36f1ab4 = function(arg0, arg1) { 272 - let deferred0_0; 273 - let deferred0_1; 274 - try { 275 - deferred0_0 = arg0; 276 - deferred0_1 = arg1; 277 - console.error(getStringFromWasm0(arg0, arg1)); 278 - } finally { 279 - wasm.__wbindgen_free(deferred0_0, deferred0_1, 1); 280 - } 281 - }; 282 - imports.wbg.__wbg_new_8a6f238a6ece86ea = function() { 283 - const ret = new Error(); 284 - return ret; 285 - }; 286 - imports.wbg.__wbg_stack_0ed75d68575b0f3c = function(arg0, arg1) { 287 - const ret = arg1.stack; 288 - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 289 - const len1 = WASM_VECTOR_LEN; 290 - getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); 291 - getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); 292 - }; 293 - imports.wbg.__wbg_wbindgenthrow_4c11a24fca429ccf = function(arg0, arg1) { 294 - throw new Error(getStringFromWasm0(arg0, arg1)); 295 - }; 296 - imports.wbg.__wbindgen_cast_2241b6af4c4b2941 = function(arg0, arg1) { 297 - const ret = getStringFromWasm0(arg0, arg1); 298 - return ret; 299 - }; 300 - imports.wbg.__wbindgen_init_externref_table = function() { 301 - const table = wasm.__wbindgen_export_3; 302 - const offset = table.grow(4); 303 - table.set(0, void 0); 304 - table.set(offset + 0, void 0); 305 - table.set(offset + 1, null); 306 - table.set(offset + 2, true); 307 - table.set(offset + 3, false); 308 - ; 309 - }; 310 - return imports; 311 - } 312 - function __wbg_init_memory(imports, memory) { 313 - } 314 - function __wbg_finalize_init(instance, module) { 315 - wasm = instance.exports; 316 - __wbg_init.__wbindgen_wasm_module = module; 317 - cachedDataViewMemory0 = null; 318 - cachedUint8ArrayMemory0 = null; 319 - wasm.__wbindgen_start(); 320 - return wasm; 321 - } 322 - async function __wbg_init(module_or_path) { 323 - if (wasm !== void 0) return wasm; 324 - if (typeof module_or_path !== "undefined") { 325 - if (Object.getPrototypeOf(module_or_path) === Object.prototype) { 326 - ({ module_or_path } = module_or_path); 327 - } else { 328 - console.warn("using deprecated parameters for the initialization function; pass a single object instead"); 329 - } 330 - } 331 - if (typeof module_or_path === "undefined") { 332 - module_or_path = new URL("slices_lexicon_bg.wasm", import.meta.url); 333 - } 334 - const imports = __wbg_get_imports(); 335 - if (typeof module_or_path === "string" || typeof Request === "function" && module_or_path instanceof Request || typeof URL === "function" && module_or_path instanceof URL) { 336 - module_or_path = fetch(module_or_path); 337 - } 338 - __wbg_init_memory(imports); 339 - const { instance, module } = await __wbg_load(await module_or_path, imports); 340 - return __wbg_finalize_init(instance, module); 341 - } 342 - var slices_lexicon_default = __wbg_init; 343 - 344 - // packages/lexicon/lexicon.ts 345 - var _computedKey; 346 - var _computedKey1; 347 - var wasmInitialized = false; 348 - async function ensureWasmInit() { 349 - if (!wasmInitialized) { 350 - const wasmUrl = new URL("./wasm/slices_lexicon_bg.wasm", import.meta.url); 351 - await slices_lexicon_default({ 352 - module_or_path: wasmUrl 353 - }); 354 - wasmInitialized = true; 355 - } 356 - } 357 - var ValidationError = class extends Error { 358 - /** 359 - * Creates a new ValidationError instance. 360 - * 361 - * @param message - Human-readable error description 362 - */ 363 - constructor(message) { 364 - super(message); 365 - this.name = "ValidationError"; 366 - } 367 - }; 368 - _computedKey = Symbol.dispose, _computedKey1 = Symbol.asyncDispose; 369 - var LexiconValidator = class _LexiconValidator { 370 - wasmValidator; 371 - /** 372 - * Creates a new validator instance with the provided lexicon documents. 373 - * 374 - * Note: Prefer using the static `create()` method for async initialization. 375 - * 376 - * @param lexicons - Array of lexicon documents to validate 377 - */ 378 - constructor(lexicons) { 379 - const lexiconsJson = JSON.stringify(lexicons); 380 - this.wasmValidator = new WasmLexiconValidator(lexiconsJson); 381 - } 382 - /** 383 - * Creates a new validator instance with proper async initialization. 384 - * Ensures WASM module is loaded before creating the validator. 385 - * 386 - * @param lexicons - Array of lexicon documents to validate 387 - * @returns Promise resolving to a new validator instance 388 - * 389 - * @example 390 - * ```typescript 391 - * const lexicons = [{ id: "com.example.post", defs: {...} }]; 392 - * const validator = await LexiconValidator.create(lexicons); 393 - * ``` 394 - */ 395 - static async create(lexicons) { 396 - await ensureWasmInit(); 397 - return new _LexiconValidator(lexicons); 398 - } 399 - /** 400 - * Validates a data record against its collection's lexicon schema. 401 - * 402 - * Performs comprehensive validation including: 403 - * - Type checking 404 - * - Constraint validation 405 - * - Format validation 406 - * - Required field checking 407 - * 408 - * @param collection - NSID of the collection (lexicon) to validate against 409 - * @param record - Data record to validate 410 - * @throws {ValidationError} If validation fails 411 - * 412 - * @example 413 - * ```typescript 414 - * validator.validateRecord("com.example.post", { 415 - * text: "Hello world!", 416 - * createdAt: "2024-01-01T12:00:00Z" 417 - * }); 418 - * ``` 419 - */ 420 - validateRecord(collection, record) { 421 - try { 422 - const recordJson = JSON.stringify(record); 423 - this.wasmValidator.validate_record(collection, recordJson); 424 - } catch (error) { 425 - throw new ValidationError(error instanceof Error ? error.message : String(error)); 426 - } 427 - } 428 - /** 429 - * Validates all lexicon documents and returns comprehensive error information. 430 - * 431 - * Uses the enhanced validation system that collects ALL errors for each lexicon, 432 - * not just the first error encountered. 433 - * 434 - * @returns Null if validation passes, or error map if validation fails 435 - * 436 - * @example 437 - * ```typescript 438 - * const errors = validator.validateLexicons(); 439 - * if (errors) { 440 - * console.log(`Found errors in ${Object.keys(errors).length} lexicons`); 441 - * } 442 - * ``` 443 - */ 444 - validateLexicons() { 445 - try { 446 - const result = this.wasmValidator.validate_lexicons(); 447 - const errorMap = JSON.parse(result); 448 - if (Object.keys(errorMap).length === 0) { 449 - return null; 450 - } 451 - return errorMap; 452 - } catch (error) { 453 - throw new ValidationError(error instanceof Error ? error.message : String(error)); 454 - } 455 - } 456 - /** 457 - * Checks for unresolved references across the lexicon set. 458 - * 459 - * Identifies references (like "$ref": "com.example.collection#definition") 460 - * that point to non-existent lexicons or definitions. 461 - * 462 - * @returns Array of unresolved reference strings 463 - * 464 - * @example 465 - * ```typescript 466 - * const unresolved = validator.checkReferences(); 467 - * if (unresolved.length > 0) { 468 - * console.log("Unresolved references:", unresolved); 469 - * } 470 - * ``` 471 - */ 472 - checkReferences() { 473 - try { 474 - const result = this.wasmValidator.check_references(); 475 - return JSON.parse(result); 476 - } catch (error) { 477 - throw new ValidationError(error instanceof Error ? error.message : String(error)); 478 - } 479 - } 480 - /** 481 - * Retrieves detailed error context for debugging validation failures. 482 - * 483 - * Provides path information, current lexicon context, and circular 484 - * reference detection state for enhanced debugging. 485 - * 486 - * @param path - Schema path to get context for 487 - * @returns Detailed error context information 488 - * 489 - * @example 490 - * ```typescript 491 - * const context = validator.getErrorContext("com.example.post#main"); 492 - * console.log(`Validating at path: ${context.path}`); 493 - * ``` 494 - */ 495 - getErrorContext(path) { 496 - try { 497 - const result = this.wasmValidator.get_error_context(path); 498 - return JSON.parse(result); 499 - } catch (error) { 500 - throw new ValidationError(error instanceof Error ? error.message : String(error)); 501 - } 502 - } 503 - /** 504 - * Manually releases WASM resources. 505 - * 506 - * Call this when done with the validator to free memory. 507 - * Automatically called by dispose methods when using `using` syntax. 508 - */ 509 - free() { 510 - this.wasmValidator.free(); 511 - } 512 - /** 513 - * Synchronous dispose method for automatic resource cleanup. 514 - * Called automatically when using `using` keyword. 515 - * 516 - * @example 517 - * ```typescript 518 - * using validator = await LexiconValidator.create(lexicons); 519 - * // Automatically cleaned up at end of scope 520 - * ``` 521 - */ 522 - [_computedKey]() { 523 - this.free(); 524 - } 525 - /** 526 - * Asynchronous dispose method for automatic resource cleanup. 527 - * Called automatically when using `await using` keyword. 528 - */ 529 - async [_computedKey1]() { 530 - await Promise.resolve(this.free()); 531 - } 532 - }; 533 - async function validate(lexicons) { 534 - await ensureWasmInit(); 535 - const lexiconsJson = JSON.stringify(lexicons); 536 - const result = validate_lexicons_and_get_errors(lexiconsJson); 537 - const errorMap = JSON.parse(result); 538 - if (Object.keys(errorMap).length === 0) { 539 - return null; 540 - } 541 - return errorMap; 542 - } 543 - async function validateWithDetails(lexicons) { 544 - const errors = await validate(lexicons); 545 - if (errors === null) { 546 - return { 547 - valid: true, 548 - errors: {}, 549 - totalErrors: 0, 550 - lexiconsWithErrors: 0 551 - }; 552 - } 553 - const totalErrors = Object.values(errors).reduce((sum, errorArray) => sum + errorArray.length, 0); 554 - return { 555 - valid: false, 556 - errors, 557 - totalErrors, 558 - lexiconsWithErrors: Object.keys(errors).length 559 - }; 560 - } 561 - async function validateRecord(lexicons, collection, record) { 562 - return await withValidator(lexicons, (validator) => { 563 - validator.validateRecord(collection, record); 564 - }); 565 - } 566 - async function validateStringFormat(value, format) { 567 - await ensureWasmInit(); 568 - try { 569 - validate_string_format(value, format); 570 - } catch (error) { 571 - throw new ValidationError(error instanceof Error ? error.message : String(error)); 572 - } 573 - } 574 - async function isValidNsid(nsid) { 575 - await ensureWasmInit(); 576 - return is_valid_nsid(nsid); 577 - } 578 - async function withValidator(lexicons, callback) { 579 - const validator = await LexiconValidator.create(lexicons); 580 - try { 581 - return await callback(validator); 582 - } finally { 583 - validator.free(); 584 - } 585 - } 586 - export { 587 - LexiconValidator, 588 - ValidationError, 589 - isValidNsid, 590 - validate, 591 - validateRecord, 592 - validateStringFormat, 593 - validateWithDetails, 594 - withValidator 595 - };
packages/lexicon-intellisense/wasm/slices_lexicon_bg.wasm

This is a binary file and will not be displayed.