UNPKG

@intlayer/chokidar

Version:

Uses chokidar to scan and build Intlayer declaration files into dictionaries based on Intlayer configuration.

1 lines 25.1 kB
{"version":3,"file":"chunkJSON.mjs","names":[],"sources":["../../../src/utils/chunkJSON.ts"],"sourcesContent":["/**\n * Split & reassemble JSON by character budget.\n * - Measures serialized size using JSON.stringify(..).length (characters).\n * - Ensures each chunk is itself valid JSON.\n * - Very large strings are split into safe pieces using getChunk and re-concatenated on assemble.\n * - Protects against circular structures (JSON can't serialize those anyway).\n */\n\nimport { getChunk } from './getChunk';\n\ntype JSONPrimitive = string | number | boolean | null;\ntype JSONValue = JSONPrimitive | JSONObject | JSONArray;\n\nexport type JSONObject = {\n [k: string]: JSONValue;\n};\n\ntype JSONArray = JSONValue[];\n\ntype Path = Array<string | number>;\n\ntype SetPatch = { op: 'set'; path: Path; value: JSONValue };\ntype StrAppendPatch = {\n op: 'str-append';\n path: Path;\n value: string; // part of a longer string\n index: number;\n total: number;\n};\ntype Patch = SetPatch | StrAppendPatch;\n\ntype RootType = 'object' | 'array';\n\nexport type JsonChunk = {\n schemaVersion: 1;\n index: number;\n total: number;\n rootType: RootType;\n checksum: string; // hash of the full original JSON string\n entries: Patch[];\n};\n\nconst isObject = (val: unknown): val is Record<string, unknown> => {\n return typeof val === 'object' && val !== null && !Array.isArray(val);\n};\n\nconst computeDjb2 = (str: string): string => {\n // Simple 32-bit hash; deterministic & fast\n let hash = 5381;\n\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) + hash) ^ str.charCodeAt(i);\n }\n\n // convert to unsigned hex\n return (hash >>> 0).toString(16).padStart(8, '0');\n};\n\nconst setAtPath = (root: any, path: Path, value: JSONValue) => {\n let current = root;\n\n for (let i = 0; i < path.length - 1; i++) {\n const key = path[i];\n const nextKey = path[i + 1];\n const isNextIndex = typeof nextKey === 'number';\n\n if (typeof key === 'number') {\n if (!Array.isArray(current)) {\n throw new Error(`Expected array at path segment ${i}`);\n }\n\n if (current[key] === undefined) {\n current[key] = isNextIndex ? [] : {};\n }\n\n current = current[key];\n } else {\n if (!isObject(current)) {\n throw new Error(`Expected object at path segment ${i}`);\n }\n\n if (!(key in current)) {\n (current as any)[key] = isNextIndex ? [] : {};\n }\n\n current = (current as any)[key];\n }\n }\n\n const last = path[path.length - 1];\n\n if (typeof last === 'number') {\n if (!Array.isArray(current)) {\n throw new Error(`Expected array at final segment`);\n }\n\n current[last] = value as any;\n } else {\n if (!isObject(current)) {\n throw new Error(`Expected object at final segment`);\n }\n\n (current as any)[last] = value as any;\n }\n};\n\nconst pathKey = (path: Path): string => {\n // stable key for grouping string parts\n return JSON.stringify(path);\n};\n\n/**\n * Split a string into parts using getChunk with a charLength budget per part.\n */\nconst splitStringByBudget = (\n str: string,\n maxCharsPerPart: number\n): string[] => {\n if (maxCharsPerPart <= 0) {\n throw new Error('maxChars must be > 0');\n }\n\n const output: string[] = [];\n let offset = 0;\n\n while (offset < str.length) {\n const part = getChunk(str, {\n charStart: offset,\n charLength: maxCharsPerPart,\n });\n\n if (!part) break;\n\n output.push(part);\n offset += part.length;\n }\n\n return output;\n};\n\n/**\n * Flatten JSON into patches (leaf writes). Strings too large to fit in a single\n * chunk are yielded as multiple str-append patches.\n */\nconst flattenToPatches = (\n value: JSONValue,\n maxCharsPerChunk: number,\n path: Path = [],\n seen = new WeakSet<object>()\n): Patch[] => {\n // Conservative per-entry cap so a single entry fits into an empty chunk with envelope overhead.\n // (Envelope ~ a few hundred chars; we keep a comfortable margin.)\n const maxStringPiece = Math.max(\n 1,\n Math.floor((maxCharsPerChunk - 400) * 0.8)\n );\n\n const patches: Patch[] = [];\n\n const walk = (currentValue: JSONValue, currentPath: Path) => {\n if (typeof currentValue === 'string') {\n // If the serialized patch wouldn't fit, split the string into multiple parts\n // and encode as a split-node sentinel with numbered keys.\n const testPatch: SetPatch = {\n op: 'set',\n path: currentPath,\n value: currentValue,\n };\n const testLen = JSON.stringify(testPatch).length + 150; // margin\n\n if (testLen <= maxCharsPerChunk) {\n patches.push(testPatch);\n return;\n }\n\n // Use getChunk-based splitting to produce stable parts\n const parts = splitStringByBudget(currentValue, maxStringPiece);\n\n // Emit split-node metadata and parts as individual leaf writes\n patches.push({\n op: 'set',\n path: [...currentPath, '__splittedType'],\n value: 'string',\n });\n patches.push({\n op: 'set',\n path: [...currentPath, '__total'],\n value: parts.length,\n });\n\n for (let i = 0; i < parts.length; i++) {\n patches.push({\n op: 'set',\n path: [...currentPath, String(i + 1)],\n value: parts[i],\n });\n }\n\n return;\n }\n\n if (currentValue === null || typeof currentValue !== 'object') {\n patches.push({ op: 'set', path: currentPath, value: currentValue });\n return;\n }\n\n if (seen.has(currentValue as object)) {\n throw new Error('Cannot serialize circular structures to JSON.');\n }\n\n seen.add(currentValue as object);\n\n if (Array.isArray(currentValue)) {\n for (let i = 0; i < currentValue.length; i++) {\n walk(currentValue[i] as JSONValue, [...currentPath, i]);\n }\n } else {\n for (const key of Object.keys(currentValue)) {\n walk((currentValue as JSONObject)[key], [...currentPath, key]);\n }\n }\n\n seen.delete(currentValue as object);\n };\n\n walk(value, path);\n return patches;\n};\n\n/**\n * Split JSON into chunks constrained by character count of serialized chunk.\n */\nexport const chunkJSON = (\n value: JSONObject | JSONArray,\n maxChars: number\n): JsonChunk[] => {\n if (!isObject(value) && !Array.isArray(value)) {\n throw new Error('Root must be an object or array.');\n }\n\n if (maxChars < 500) {\n // You can lower this if you truly need; recommended to keep some envelope headroom.\n throw new Error('maxChars is too small. Use at least 500 characters.');\n }\n\n const rootType: RootType = Array.isArray(value) ? 'array' : 'object';\n let sourceString: string;\n\n try {\n sourceString = JSON.stringify(value);\n } catch {\n // Provide a deterministic error message for circular refs\n throw new Error('Cannot serialize circular structures to JSON.');\n }\n\n const checksum = computeDjb2(sourceString);\n const allPatches = flattenToPatches(value as JSONValue, maxChars);\n\n const chunks: JsonChunk[] = [];\n let currentChunk: JsonChunk = {\n schemaVersion: 1,\n index: 0, // provisional\n total: 0, // provisional\n rootType,\n checksum,\n entries: [],\n };\n\n const emptyEnvelopeSize = JSON.stringify({\n ...currentChunk,\n entries: [],\n }).length;\n\n const tryFlush = () => {\n if (currentChunk.entries.length > 0) {\n chunks.push(currentChunk);\n currentChunk = {\n schemaVersion: 1,\n index: 0,\n total: 0,\n rootType,\n checksum,\n entries: [],\n };\n }\n };\n\n for (const patch of allPatches) {\n // Would adding this patch exceed maxChars?\n const withPatchSize =\n emptyEnvelopeSize +\n JSON.stringify(currentChunk.entries).length + // current entries array\n (currentChunk.entries.length ? 1 : 0) + // possible comma\n JSON.stringify(patch).length;\n\n if (withPatchSize <= maxChars) {\n currentChunk.entries.push(patch);\n } else {\n // Start a new chunk if current has items\n if (currentChunk.entries.length > 0) {\n tryFlush();\n }\n\n // Ensure single patch fits into an empty chunk\n const singleSize = emptyEnvelopeSize + JSON.stringify([patch]).length;\n\n if (singleSize > maxChars) {\n // This should only happen for massive strings, which we pre-split;\n // if it happens for a non-string, we cannot split further.\n throw new Error(\n 'A single entry exceeds maxChars and cannot be split. Reduce entry size or increase maxChars.'\n );\n }\n\n currentChunk.entries.push(patch);\n }\n }\n\n tryFlush();\n\n // Ensure at least one chunk exists (even for empty root)\n if (chunks.length === 0) {\n chunks.push({\n schemaVersion: 1,\n index: 0,\n total: 0, // provisional\n rootType,\n checksum,\n entries: [],\n });\n }\n\n // Finalize indices & totals\n const totalChunks = chunks.length;\n\n chunks.forEach((chunk, index) => {\n chunk.index = index;\n chunk.total = totalChunks;\n });\n\n return chunks;\n};\n\n/**\n * Reassemble JSON from chunks.\n * - Validates checksums and indices.\n * - Applies 'set' patches and merges string pieces from 'str-append'.\n */\n/**\n * Reconstruct content from a single chunk without validation.\n * Useful for processing individual chunks in a pipeline where you don't have all chunks yet.\n * Note: This will only reconstruct the partial content contained in this chunk.\n */\nexport const reconstructFromSingleChunk = (\n chunk: JsonChunk\n): JSONObject | JSONArray => {\n const root: any = chunk.rootType === 'array' ? [] : {};\n\n // Apply all 'set' patches from this chunk\n for (const entry of chunk.entries) {\n if (entry.op === 'set') {\n setAtPath(root, entry.path, entry.value);\n }\n }\n\n // Reconcile split-node sentinels for strings/arrays\n // When reconstructing from a single chunk, we may have incomplete split nodes\n const reconcileSplitNodes = (node: any): any => {\n if (node === null || typeof node !== 'object') return node;\n\n if (Array.isArray(node)) {\n for (let i = 0; i < node.length; i++) {\n node[i] = reconcileSplitNodes(node[i]);\n }\n return node;\n }\n\n // string split-node\n if ((node as any)['__splittedType'] === 'string') {\n const total = (node as any)['__total'];\n\n if (typeof total !== 'number' || total <= 0) {\n // Invalid split node, return as-is\n return node;\n }\n\n const parts: string[] = [];\n let hasAllParts = true;\n\n for (let i = 1; i <= total; i++) {\n const piece = (node as any)[String(i)];\n\n if (typeof piece !== 'string') {\n hasAllParts = false;\n break;\n }\n\n parts.push(piece);\n }\n\n // Only reconstruct if we have all parts, otherwise return the node as-is\n if (hasAllParts) {\n return parts.join('');\n }\n\n return node;\n }\n\n // array split-node (optional support)\n if ((node as any)['__splittedType'] === 'array') {\n const total = (node as any)['__total'];\n\n if (typeof total !== 'number' || total < 0) {\n // Invalid split node, return as-is\n return node;\n }\n\n const output: any[] = [];\n let hasAllParts = true;\n\n for (let i = 1; i <= total; i++) {\n const slice = (node as any)[String(i)];\n\n if (!Array.isArray(slice)) {\n hasAllParts = false;\n break;\n }\n\n for (let j = 0; j < slice.length; j++) {\n output.push(reconcileSplitNodes(slice[j]));\n }\n }\n\n // Only reconstruct if we have all parts\n if (hasAllParts) {\n return output;\n }\n\n return node;\n }\n\n // walk normal object\n for (const key of Object.keys(node)) {\n node[key] = reconcileSplitNodes(node[key]);\n }\n\n return node;\n };\n\n return reconcileSplitNodes(root);\n};\n\nexport const assembleJSON = (chunks: JsonChunk[]): JSONObject | JSONArray => {\n if (!chunks || chunks.length === 0) {\n throw new Error('No chunks provided.');\n }\n\n // Basic validation & sort\n const sorted = [...chunks].sort((a, b) => a.index - b.index);\n const { checksum, rootType } = sorted[0];\n const schemaVersion = 1;\n\n for (let i = 0; i < sorted.length; i++) {\n const chunk = sorted[i];\n\n if (chunk.schemaVersion !== schemaVersion) {\n console.error('Unsupported schemaVersion.', {\n cause: chunk,\n schemaVersion,\n });\n throw new Error('Unsupported schemaVersion.');\n }\n\n if (chunk.rootType !== rootType) {\n console.error('Chunks rootType mismatch.', {\n cause: chunk,\n rootType,\n });\n throw new Error('Chunks rootType mismatch.');\n }\n\n if (chunk.checksum !== checksum) {\n console.error('Chunks checksum mismatch (different source objects?).', {\n cause: chunk,\n checksum,\n });\n throw new Error('Chunks checksum mismatch (different source objects?).');\n }\n\n if (chunk.index !== i) {\n console.error('Chunk indices are not contiguous or sorted.', {\n cause: chunk,\n index: chunk.index,\n i,\n });\n throw new Error('Chunk indices are not contiguous or sorted.');\n }\n\n // Defer total check until after reconstruction to prefer more specific errors\n }\n\n const root: any = rootType === 'array' ? [] : {};\n\n // Collect string parts by path\n const stringParts = new Map<\n string,\n { path: Path; total: number; received: StrAppendPatch[] }\n >();\n\n const applySet = (patch: SetPatch) =>\n setAtPath(root, patch.path, patch.value);\n\n for (const chunk of sorted) {\n for (const entry of chunk.entries) {\n if (entry.op === 'set') {\n applySet(entry);\n } else {\n const key = pathKey(entry.path);\n const record = stringParts.get(key) ?? {\n path: entry.path,\n total: entry.total,\n received: [],\n };\n\n if (record.total !== entry.total) {\n throw new Error('Inconsistent string part totals for a path.');\n }\n\n record.received.push(entry);\n stringParts.set(key, record);\n }\n }\n }\n\n // Stitch strings\n for (const { path, total, received } of stringParts.values()) {\n if (received.length !== total) {\n throw new Error('Missing string parts for a path; incomplete chunk set.');\n }\n\n received.sort((a, b) => a.index - b.index);\n const fullString = received.map((part) => part.value).join('');\n setAtPath(root, path, fullString);\n }\n\n // Reconcile split-node sentinels for strings/arrays after all patches applied\n const reconcileSplitNodes = (node: any): any => {\n if (node === null || typeof node !== 'object') return node;\n\n if (Array.isArray(node)) {\n for (let i = 0; i < node.length; i++) {\n node[i] = reconcileSplitNodes(node[i]);\n }\n return node;\n }\n\n // string split-node\n if ((node as any)['__splittedType'] === 'string') {\n const total = (node as any)['__total'];\n\n if (typeof total !== 'number' || total <= 0) {\n throw new Error('Invalid split-node total for a path.');\n }\n\n const parts: string[] = [];\n\n for (let i = 1; i <= total; i++) {\n const piece = (node as any)[String(i)];\n\n if (typeof piece !== 'string') {\n throw new Error(\n 'Missing string parts for a path; incomplete chunk set.'\n );\n }\n\n parts.push(piece);\n }\n\n return parts.join('');\n }\n\n // array split-node (optional support)\n if ((node as any)['__splittedType'] === 'array') {\n const total = (node as any)['__total'];\n\n if (typeof total !== 'number' || total < 0) {\n throw new Error('Invalid split-node total for a path.');\n }\n\n const output: any[] = [];\n\n for (let i = 1; i <= total; i++) {\n const slice = (node as any)[String(i)];\n\n if (!Array.isArray(slice)) {\n throw new Error(\n 'Missing string parts for a path; incomplete chunk set.'\n );\n }\n\n for (let j = 0; j < slice.length; j++) {\n output.push(reconcileSplitNodes(slice[j]));\n }\n }\n\n return output;\n }\n\n // walk normal object\n for (const key of Object.keys(node)) {\n node[key] = reconcileSplitNodes(node[key]);\n }\n\n return node;\n };\n\n const reconciled = reconcileSplitNodes(root);\n\n // Now validate totals match provided count\n for (let i = 0; i < sorted.length; i++) {\n const chunk = sorted[i];\n\n if (chunk.total !== sorted.length) {\n throw new Error(\n `Chunk total does not match provided count. Expected ${sorted.length}, but chunk ${i} has total=${chunk.total}`\n );\n }\n }\n\n return reconciled;\n};\n\n/* -------------------------------------------\n * Example usage\n * -------------------------------------------\nconst big: JSONObject = {\n title: \"Document\",\n content: \"…a very very long text…\",\n items: Array.from({ length: 2000 }, (_, i) => ({ id: i, label: `Item ${i}` }))\n};\n\n// Split to ~16k-char chunks\nconst chunks = chunkJSON(big, 16_000);\n\n// Send each `chunks[i]` as JSON to your backend.\n// Later, reassemble:\nconst restored = assembleJSON(chunks);\nconsole.log(JSON.stringify(restored) === JSON.stringify(big)); // true\n*/\n"],"mappings":"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"}