@pixerate/editor 0.16.1 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-YQCI4CCN.cjs","../src/spreadsheet/formula/lexer.ts","../src/spreadsheet/formula/parser.ts","../src/spreadsheet/formula/evaluator.ts","../src/spreadsheet/formula/dependency-graph.ts","../src/spreadsheet/formula/references.ts","../src/spreadsheet/datasource/index.ts","../src/spreadsheet/controller.ts"],"names":[],"mappings":"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AA;AACA,cAAA;AACzB,cAAA;AACO,cAAA;AACA,cAAA;AACD,cAAA;AACE,cAAA;AACT,YAAA;AACH,UAAA;AACgE,UAAA;AACjE,QAAA;AACF,MAAA;AACD,IAAA;AACgB,MAAA;AAClB,IAAA;AAEoB,IAAA;AACF,IAAA;AACG,IAAA;AACE,IAAA;AACoB,IAAA;AACmC,sBAAA;AAC9E,IAAA;AACF,EAAA;AAAA;AAI+B,EAAA;AACgB,IAAA;AACI,IAAA;AACI,IAAA;AACnC,IAAA;AACpB,EAAA;AAEoB,EAAA;AACe,IAAA;AACR,IAAA;AACrB,IAAA;AAC+C,MAAA;AACD,MAAA;AAC5B,MAAA;AACF,MAAA;AAClB,IAAA;AACyB,MAAA;AAC3B,IAAA;AACF,EAAA;AAEoB,EAAA;AACe,IAAA;AACR,IAAA;AACrB,IAAA;AAC+C,MAAA;AACD,MAAA;AAC5B,MAAA;AACF,MAAA;AAClB,IAAA;AACyB,MAAA;AAC3B,IAAA;AACF,EAAA;AAE6B,EAAA;AACU,oBAAA;AACvC,EAAA;AACF;APw8BmF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-YQCI4CCN.cjs","sourcesContent":[null,"export type FormulaTokenType =\n | 'NUMBER'\n | 'STRING'\n | 'BOOLEAN'\n | 'ERROR'\n | 'CELL_REF'\n | 'RANGE'\n | 'PROPERTY_REF'\n | 'IDENTIFIER'\n | 'OPERATOR'\n | 'LPAREN'\n | 'RPAREN'\n | 'COMMA'\n | 'EOF';\n\nexport interface FormulaToken {\n type: FormulaTokenType;\n value: string;\n position: number;\n}\n\nexport function tokenizeFormula(formula: string): FormulaToken[] {\n const tokens: FormulaToken[] = [];\n // Strip leading '=' if present\n let input = formula.trim();\n let offset = 0;\n if (input.startsWith('=')) {\n input = input.slice(1);\n offset = 1;\n }\n\n let i = 0;\n while (i < input.length) {\n const char = input[i];\n\n // Skip whitespace\n if (/\\s/.test(char)) {\n i++;\n continue;\n }\n\n // Number literal (int or float)\n if (/\\d/.test(char) || (char === '.' && i + 1 < input.length && /\\d/.test(input[i + 1]))) {\n const start = i;\n let hasDot = char === '.';\n i++;\n while (i < input.length && (/\\d/.test(input[i]) || (input[i] === '.' && !hasDot))) {\n if (input[i] === '.') hasDot = true;\n i++;\n }\n tokens.push({\n type: 'NUMBER',\n value: input.slice(start, i),\n position: start + offset\n });\n continue;\n }\n\n // String literal (\"...\" or '...')\n if (char === '\"' || char === \"'\") {\n const quote = char;\n const start = i;\n i++;\n let str = '';\n while (i < input.length && input[i] !== quote) {\n if (input[i] === '\\\\' && i + 1 < input.length) {\n i++;\n }\n str += input[i];\n i++;\n }\n if (i >= input.length) {\n throw new Error(`Unterminated string starting at position ${start + offset}`);\n }\n i++; // skip closing quote\n tokens.push({\n type: 'STRING',\n value: str,\n position: start + offset\n });\n continue;\n }\n\n // Error literal, e.g. #REF! left behind by deleting a referenced row\n if (char === '#') {\n const match = /^#(?:REF!|DIV\\/0!|VALUE!|NAME\\?|N\\/A|NUM!|CYCLE!|ERROR!)/.exec(input.slice(i));\n if (!match) {\n throw new Error(`Unexpected character '#' at position ${i + offset}`);\n }\n tokens.push({ type: 'ERROR', value: match[0], position: i + offset });\n i += match[0].length;\n continue;\n }\n\n // Property reference: [property_name] e.g. [status], [title], [effortHours]\n if (char === '[') {\n const start = i;\n i++;\n let prop = '';\n while (i < input.length && input[i] !== ']') {\n prop += input[i];\n i++;\n }\n if (i < input.length && input[i] === ']') {\n i++;\n }\n tokens.push({\n type: 'PROPERTY_REF',\n value: prop.trim(),\n position: start + offset\n });\n continue;\n }\n\n // Single character delimiters\n if (char === '(') {\n tokens.push({ type: 'LPAREN', value: '(', position: i + offset });\n i++;\n continue;\n }\n if (char === ')') {\n tokens.push({ type: 'RPAREN', value: ')', position: i + offset });\n i++;\n continue;\n }\n if (char === ',') {\n tokens.push({ type: 'COMMA', value: ',', position: i + offset });\n i++;\n continue;\n }\n\n // Multi-character comparison operators: <=, >=, <>, !=\n const twoChars = input.slice(i, i + 2);\n if (['<=', '>=', '<>', '!='].includes(twoChars)) {\n tokens.push({\n type: 'OPERATOR',\n value: twoChars === '!=' ? '<>' : twoChars,\n position: i + offset\n });\n i += 2;\n continue;\n }\n\n // Single character operators: +, -, *, /, ^, &, =, <, >\n if (['+', '-', '*', '/', '^', '&', '=', '<', '>'].includes(char)) {\n tokens.push({ type: 'OPERATOR', value: char, position: i + offset });\n i++;\n continue;\n }\n\n // Identifiers, Cell references, and Ranges (e.g. SUM, A1, B2:B10, A:A)\n if (/[a-zA-Z_$]/.test(char)) {\n const start = i;\n while (i < input.length && /[a-zA-Z0-9_$.]/.test(input[i])) {\n i++;\n }\n const rawWord = input.slice(start, i);\n\n // Check if followed by colon indicating a range e.g. A1:B10 or A:A\n if (i < input.length && input[i] === ':') {\n const colonPos = i;\n i++; // skip colon\n const secondStart = i;\n while (i < input.length && /[a-zA-Z0-9_$.]/.test(input[i])) {\n i++;\n }\n const secondWord = input.slice(secondStart, i);\n if (secondWord.length > 0) {\n tokens.push({\n type: 'RANGE',\n value: `${rawWord}:${secondWord}`.toUpperCase(),\n position: start + offset\n });\n continue;\n } else {\n // Revert back\n i = colonPos;\n }\n }\n\n // Check for boolean literal\n const upper = rawWord.toUpperCase();\n if (upper === 'TRUE' || upper === 'FALSE') {\n tokens.push({\n type: 'BOOLEAN',\n value: upper,\n position: start + offset\n });\n continue;\n }\n\n // Check for Cell Reference (e.g. A1, $B$12, AA100)\n if (/^\\$?[A-Za-z]+\\$?[0-9]+$/.test(rawWord)) {\n tokens.push({\n type: 'CELL_REF',\n value: upper.replace(/\\$/g, ''),\n position: start + offset\n });\n continue;\n }\n\n // Function or generic identifier\n tokens.push({\n type: 'IDENTIFIER',\n value: upper,\n position: start + offset\n });\n continue;\n }\n\n throw new Error(`Unexpected character '${char}' at position ${i + offset}`);\n }\n\n tokens.push({ type: 'EOF', value: '', position: input.length + offset });\n return tokens;\n}\n","import { FormulaToken, tokenizeFormula, FormulaTokenType } from './lexer';\n\n/** Row number used for the open end of whole-column ranges such as `A:A`. */\nexport const WHOLE_COLUMN_END_ROW = 1048576;\n\nexport type ASTNode =\n | LiteralNode\n | CellRefNode\n | RangeNode\n | PropertyRefNode\n | BinaryOpNode\n | UnaryOpNode\n | FunctionCallNode;\n\nexport interface LiteralNode {\n type: 'Literal';\n value: number | string | boolean;\n}\n\nexport interface CellRefNode {\n type: 'CellRef';\n ref: string;\n col: string;\n row: number;\n}\n\nexport interface RangeNode {\n type: 'Range';\n raw: string;\n startCol: string;\n startRow: number;\n endCol: string;\n endRow: number;\n}\n\nexport interface PropertyRefNode {\n type: 'PropertyRef';\n property: string;\n}\n\nexport interface BinaryOpNode {\n type: 'BinaryOp';\n op: string;\n left: ASTNode;\n right: ASTNode;\n}\n\nexport interface UnaryOpNode {\n type: 'UnaryOp';\n op: string;\n argument: ASTNode;\n}\n\nexport interface FunctionCallNode {\n type: 'FunctionCall';\n name: string;\n args: ASTNode[];\n}\n\nexport function parseCellReference(ref: string): { col: string; row: number } {\n const match = ref.match(/^([A-Za-z]+)(\\d+)$/);\n if (!match) {\n throw new Error(`Invalid cell reference: ${ref}`);\n }\n return {\n col: match[1].toUpperCase(),\n row: parseInt(match[2], 10)\n };\n}\n\nexport function parseRange(rangeStr: string): RangeNode {\n const [start, end] = rangeStr.replace(/\\$/g, '').split(':');\n const raw = rangeStr.toUpperCase();\n\n // Whole-column range, e.g. A:A or B:D\n if (/^[A-Za-z]+$/.test(start) && /^[A-Za-z]+$/.test(end)) {\n return {\n type: 'Range',\n raw,\n startCol: start.toUpperCase(),\n startRow: 1,\n endCol: end.toUpperCase(),\n endRow: WHOLE_COLUMN_END_ROW\n };\n }\n\n const startRef = parseCellReference(start);\n const endRef = parseCellReference(end);\n return {\n type: 'Range',\n raw,\n startCol: startRef.col,\n startRow: startRef.row,\n endCol: endRef.col,\n endRow: endRef.row\n };\n}\n\nexport class FormulaParser {\n private tokens: FormulaToken[] = [];\n private current = 0;\n\n constructor(tokens: FormulaToken[]) {\n this.tokens = tokens;\n }\n\n public parse(): ASTNode {\n if (this.peek().type === 'EOF') {\n return { type: 'Literal', value: '' };\n }\n const expr = this.expression();\n if (this.peek().type !== 'EOF') {\n throw new Error(`Unexpected token at position ${this.peek().position}: ${this.peek().value}`);\n }\n return expr;\n }\n\n private expression(): ASTNode {\n return this.comparison();\n }\n\n private comparison(): ASTNode {\n let expr = this.concatenation();\n\n while (\n this.matchOperator('=', '<>', '<', '>', '<=', '>=')\n ) {\n const op = this.previous().value;\n const right = this.concatenation();\n expr = { type: 'BinaryOp', op, left: expr, right };\n }\n\n return expr;\n }\n\n private concatenation(): ASTNode {\n let expr = this.addition();\n\n while (this.matchOperator('&')) {\n const op = this.previous().value;\n const right = this.addition();\n expr = { type: 'BinaryOp', op, left: expr, right };\n }\n\n return expr;\n }\n\n private addition(): ASTNode {\n let expr = this.multiplication();\n\n while (this.matchOperator('+', '-')) {\n const op = this.previous().value;\n const right = this.multiplication();\n expr = { type: 'BinaryOp', op, left: expr, right };\n }\n\n return expr;\n }\n\n private multiplication(): ASTNode {\n let expr = this.exponentiation();\n\n while (this.matchOperator('*', '/')) {\n const op = this.previous().value;\n const right = this.exponentiation();\n expr = { type: 'BinaryOp', op, left: expr, right };\n }\n\n return expr;\n }\n\n private exponentiation(): ASTNode {\n let expr = this.unary();\n\n while (this.matchOperator('^')) {\n const op = this.previous().value;\n const right = this.unary();\n expr = { type: 'BinaryOp', op, left: expr, right };\n }\n\n return expr;\n }\n\n private unary(): ASTNode {\n if (this.matchOperator('-', '+')) {\n const op = this.previous().value;\n const argument = this.unary();\n return { type: 'UnaryOp', op, argument };\n }\n return this.primary();\n }\n\n private primary(): ASTNode {\n const token = this.peek();\n\n if (token.type === 'NUMBER') {\n this.advance();\n return { type: 'Literal', value: parseFloat(token.value) };\n }\n\n if (token.type === 'STRING') {\n this.advance();\n return { type: 'Literal', value: token.value };\n }\n\n if (token.type === 'BOOLEAN') {\n this.advance();\n return { type: 'Literal', value: token.value === 'TRUE' };\n }\n\n if (token.type === 'ERROR') {\n this.advance();\n return { type: 'Literal', value: token.value };\n }\n\n if (token.type === 'CELL_REF') {\n this.advance();\n const parsed = parseCellReference(token.value);\n return {\n type: 'CellRef',\n ref: token.value,\n col: parsed.col,\n row: parsed.row\n };\n }\n\n if (token.type === 'RANGE') {\n this.advance();\n return parseRange(token.value);\n }\n\n if (token.type === 'PROPERTY_REF') {\n this.advance();\n return {\n type: 'PropertyRef',\n property: token.value\n };\n }\n\n // Function call e.g. SUM(...)\n if (token.type === 'IDENTIFIER') {\n const name = token.value;\n this.advance();\n\n if (this.check('LPAREN')) {\n this.consume('LPAREN', `Expected '(' after function ${name}`);\n const args: ASTNode[] = [];\n if (!this.check('RPAREN')) {\n do {\n args.push(this.expression());\n } while (this.match('COMMA'));\n }\n this.consume('RPAREN', `Expected ')' after function arguments`);\n return {\n type: 'FunctionCall',\n name,\n args\n };\n }\n\n // Unknown bare names are #NAME? errors, as in spreadsheet apps.\n return { type: 'Literal', value: '#NAME?' };\n }\n\n if (this.match('LPAREN')) {\n const expr = this.expression();\n this.consume('RPAREN', `Expected ')' after expression`);\n return expr;\n }\n\n throw new Error(`Unexpected token at position ${token.position}: ${token.value || token.type}`);\n }\n\n private match(...types: string[]): boolean {\n for (const type of types) {\n if (this.check(type)) {\n this.advance();\n return true;\n }\n }\n return false;\n }\n\n private matchOperator(...ops: string[]): boolean {\n if (this.check('OPERATOR') && ops.includes(this.peek().value)) {\n this.advance();\n return true;\n }\n return false;\n }\n\n private check(type: string): boolean {\n if (this.isAtEnd()) return false;\n return this.peek().type === type;\n }\n\n private advance(): FormulaToken {\n if (!this.isAtEnd()) this.current++;\n return this.previous();\n }\n\n private isAtEnd(): boolean {\n return this.peek().type === 'EOF';\n }\n\n private peek(): FormulaToken {\n return this.tokens[this.current];\n }\n\n private previous(): FormulaToken {\n return this.tokens[this.current - 1];\n }\n\n private consume(type: string, message: string): FormulaToken {\n if (this.check(type)) return this.advance();\n throw new Error(message);\n }\n}\n\nexport function parseFormula(formula: string): ASTNode {\n const tokens = tokenizeFormula(formula);\n const parser = new FormulaParser(tokens);\n return parser.parse();\n}\n","import { ASTNode, parseFormula } from './parser';\n\nexport interface EvaluationContext {\n resolveCell?: (col: string, row: number) => any;\n resolveRange?: (startCol: string, startRow: number, endCol: string, endRow: number) => any[];\n resolveProperty?: (property: string) => any;\n}\n\n/** Spreadsheet error values. They propagate through operators and functions. */\nexport const FORMULA_ERRORS = new Set([\n '#DIV/0!',\n '#VALUE!',\n '#REF!',\n '#NAME?',\n '#N/A',\n '#NUM!',\n '#CYCLE!',\n '#ERROR!'\n]);\n\nexport function isFormulaError(value: unknown): value is string {\n return typeof value === 'string' && FORMULA_ERRORS.has(value);\n}\n\nconst isBlank = (value: unknown) => value === '' || value === null || value === undefined;\n\n/** Coerces to a number like a spreadsheet: blanks are 0, booleans 1/0, other text is #VALUE!. */\nfunction toNumber(value: unknown): number | string {\n if (isFormulaError(value)) return value;\n if (isBlank(value)) return 0;\n if (typeof value === 'boolean') return value ? 1 : 0;\n if (typeof value === 'number') return value;\n const trimmed = String(value).trim();\n const num = trimmed === '' ? NaN : Number(trimmed);\n return isNaN(num) ? '#VALUE!' : num;\n}\n\n/** Coerces to a boolean: numbers are non-zero, \"TRUE\"/\"FALSE\" text is parsed, other text is #VALUE!. */\nfunction toBoolean(value: unknown): boolean | string {\n if (isFormulaError(value)) return value;\n if (isBlank(value)) return false;\n if (typeof value === 'boolean') return value;\n if (typeof value === 'number') return value !== 0;\n const upper = String(value).trim().toUpperCase();\n if (upper === 'TRUE') return true;\n if (upper === 'FALSE') return false;\n return '#VALUE!';\n}\n\nconst toText = (value: unknown): string =>\n isBlank(value) ? '' : typeof value === 'boolean' ? (value ? 'TRUE' : 'FALSE') : String(value);\n\n/** Orders values like spreadsheets: numbers < text < booleans; text is case-insensitive. */\nfunction compareValues(left: unknown, right: unknown): number {\n const rank = (v: unknown) => (typeof v === 'boolean' ? 2 : typeof v === 'string' ? 1 : 0);\n // A blank compares as 0 against numbers/booleans and as \"\" against text.\n const l = isBlank(left) ? (typeof right === 'string' ? '' : 0) : left;\n const r = isBlank(right) ? (typeof l === 'string' ? '' : 0) : right;\n if (rank(l) !== rank(r)) return rank(l) - rank(r);\n if (typeof l === 'string') {\n const a = l.toLowerCase();\n const b = (r as string).toLowerCase();\n return a < b ? -1 : a > b ? 1 : 0;\n }\n return Number(l) - Number(r);\n}\n\n/** Rounds half away from zero, compensating for binary floating point (ROUND(1.005, 2) = 1.01). */\nfunction roundHalfAwayFromZero(value: number, decimals: number): number {\n const factor = Math.pow(10, decimals);\n const scaled = Number((Math.abs(value) * factor).toPrecision(15));\n return (Math.sign(value) * Math.round(scaled)) / factor;\n}\n\nexport function colNameToIndex(col: string): number {\n let index = 0;\n const upper = col.toUpperCase();\n for (let i = 0; i < upper.length; i++) {\n index = index * 26 + (upper.charCodeAt(i) - 65 + 1);\n }\n return index - 1;\n}\n\nexport function indexToColName(index: number): string {\n let num = index + 1;\n let name = '';\n while (num > 0) {\n const mod = (num - 1) % 26;\n name = String.fromCharCode(65 + mod) + name;\n num = Math.floor((num - mod) / 26);\n }\n return name;\n}\n\nexport class FormulaEvaluator {\n private context: EvaluationContext;\n\n constructor(context: EvaluationContext = {}) {\n this.context = context;\n }\n\n public evaluate(astOrFormula: ASTNode | string): any {\n const ast = typeof astOrFormula === 'string' ? parseFormula(astOrFormula) : astOrFormula;\n return this.evaluateNode(ast);\n }\n\n private evaluateNode(node: ASTNode): any {\n switch (node.type) {\n case 'Literal':\n return node.value;\n\n case 'CellRef': {\n if (!this.context.resolveCell) {\n throw new Error(`Cannot resolve cell reference ${node.ref}: no cell resolver provided`);\n }\n return this.context.resolveCell(node.col, node.row);\n }\n\n case 'Range': {\n if (!this.context.resolveRange) {\n throw new Error(`Cannot resolve range ${node.raw}: no range resolver provided`);\n }\n return this.context.resolveRange(node.startCol, node.startRow, node.endCol, node.endRow);\n }\n\n case 'PropertyRef': {\n if (!this.context.resolveProperty) {\n throw new Error(`Cannot resolve property [${node.property}]: no property resolver provided`);\n }\n return this.context.resolveProperty(node.property);\n }\n\n case 'UnaryOp': {\n const val = toNumber(this.evaluateNode(node.argument));\n if (isFormulaError(val)) return val;\n if (node.op === '-') return -(val as number);\n if (node.op === '+') return val;\n throw new Error(`Unsupported unary operator: ${node.op}`);\n }\n\n case 'BinaryOp': {\n const left = this.evaluateNode(node.left);\n if (isFormulaError(left)) return left;\n const right = this.evaluateNode(node.right);\n if (isFormulaError(right)) return right;\n\n if (['+', '-', '*', '/', '^'].includes(node.op)) {\n const a = toNumber(left);\n if (isFormulaError(a)) return a;\n const b = toNumber(right);\n if (isFormulaError(b)) return b;\n const x = a as number;\n const y = b as number;\n let result: number;\n switch (node.op) {\n case '+':\n result = x + y;\n break;\n case '-':\n result = x - y;\n break;\n case '*':\n result = x * y;\n break;\n case '/':\n if (y === 0) return '#DIV/0!';\n result = x / y;\n break;\n default:\n result = Math.pow(x, y);\n }\n return Number.isFinite(result) ? result : '#NUM!';\n }\n\n switch (node.op) {\n case '&':\n return toText(left) + toText(right);\n case '=':\n return compareValues(left, right) === 0;\n case '<>':\n return compareValues(left, right) !== 0;\n case '<':\n return compareValues(left, right) < 0;\n case '<=':\n return compareValues(left, right) <= 0;\n case '>':\n return compareValues(left, right) > 0;\n case '>=':\n return compareValues(left, right) >= 0;\n default:\n throw new Error(`Unsupported binary operator: ${node.op}`);\n }\n }\n\n case 'FunctionCall': {\n return this.callFunction(node.name, node.args);\n }\n\n default:\n throw new Error(`Unknown AST node: ${(node as any).type}`);\n }\n }\n\n private callFunction(name: string, args: ASTNode[]): any {\n const fnName = name.toUpperCase();\n\n // Flatten helper for range/array args\n const evaluateAndFlatten = (): any[] => {\n const items: any[] = [];\n for (const arg of args) {\n const val = this.evaluateNode(arg);\n if (Array.isArray(val)) {\n // No spread: push(...val) overflows the stack for large ranges.\n for (const item of val) items.push(item);\n } else {\n items.push(val);\n }\n }\n return items;\n };\n\n // Numbers among the arguments (text and blanks are skipped, as in SUM);\n // the first error found is returned instead.\n const numericArgs = (): number[] | string => {\n const nums: number[] = [];\n for (const item of evaluateAndFlatten()) {\n if (isFormulaError(item)) return item;\n if (isBlank(item) || typeof item === 'boolean') continue;\n const num = typeof item === 'number' ? item : Number(String(item).trim());\n if (String(item).trim() !== '' && !isNaN(num)) nums.push(num);\n }\n return nums;\n };\n const evaluateArg = (index: number) => this.evaluateNode(args[index]);\n\n switch (fnName) {\n case 'SUM': {\n const nums = numericArgs();\n if (typeof nums === 'string') return nums;\n let total = 0;\n for (const num of nums) total += num;\n return total;\n }\n\n case 'AVERAGE': {\n const items = evaluateAndFlatten();\n const error = items.find(isFormulaError);\n if (error) return error;\n let total = 0;\n let count = 0;\n for (const item of items) {\n const num = Number(item);\n if (!isNaN(num) && item !== '' && item !== null && item !== undefined) {\n total += num;\n count++;\n }\n }\n return count === 0 ? 0 : total / count;\n }\n\n case 'COUNT': {\n const items = evaluateAndFlatten();\n let count = 0;\n for (const item of items) {\n const num = Number(item);\n if (!isNaN(num) && item !== '' && item !== null && item !== undefined) {\n count++;\n }\n }\n return count;\n }\n\n case 'COUNTA': {\n const items = evaluateAndFlatten();\n let count = 0;\n for (const item of items) {\n if (item !== '' && item !== null && item !== undefined) {\n count++;\n }\n }\n return count;\n }\n\n case 'MIN':\n case 'MAX': {\n const nums = numericArgs();\n if (typeof nums === 'string') return nums;\n if (nums.length === 0) return 0;\n // Loop instead of Math.min(...nums), which overflows the stack on large ranges.\n let result = nums[0];\n for (const num of nums) {\n result = fnName === 'MIN' ? Math.min(result, num) : Math.max(result, num);\n }\n return result;\n }\n\n case 'IF': {\n if (args.length < 2) throw new Error('IF requires at least 2 arguments');\n const condition = toBoolean(evaluateArg(0));\n if (isFormulaError(condition)) return condition;\n if (condition) {\n return this.evaluateNode(args[1]);\n } else {\n return args.length > 2 ? this.evaluateNode(args[2]) : false;\n }\n }\n\n case 'CONCAT': {\n const items = evaluateAndFlatten();\n const error = items.find(isFormulaError);\n if (error) return error;\n return items.map(toText).join('');\n }\n\n case 'UPPER': {\n if (args.length !== 1) throw new Error('UPPER requires 1 argument');\n const val = evaluateArg(0);\n if (isFormulaError(val)) return val;\n return toText(val).toUpperCase();\n }\n\n case 'LOWER': {\n if (args.length !== 1) throw new Error('LOWER requires 1 argument');\n const val = evaluateArg(0);\n if (isFormulaError(val)) return val;\n return toText(val).toLowerCase();\n }\n\n case 'TRIM': {\n if (args.length !== 1) throw new Error('TRIM requires 1 argument');\n const val = evaluateArg(0);\n if (isFormulaError(val)) return val;\n return toText(val).trim();\n }\n\n case 'LEN': {\n if (args.length !== 1) throw new Error('LEN requires 1 argument');\n const val = evaluateArg(0);\n if (isFormulaError(val)) return val;\n return toText(val).length;\n }\n\n case 'ROUND': {\n if (args.length < 1) throw new Error('ROUND requires at least 1 argument');\n const num = toNumber(evaluateArg(0));\n if (isFormulaError(num)) return num;\n const decimals = args.length > 1 ? toNumber(evaluateArg(1)) : 0;\n if (isFormulaError(decimals)) return decimals;\n return roundHalfAwayFromZero(num as number, Math.trunc(decimals as number));\n }\n\n case 'ABS': {\n if (args.length !== 1) throw new Error('ABS requires 1 argument');\n const num = toNumber(evaluateArg(0));\n return isFormulaError(num) ? num : Math.abs(num as number);\n }\n\n case 'TODAY': {\n // Local calendar date (toISOString would give the UTC date).\n const now = new Date();\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;\n }\n\n case 'DAYS': {\n if (args.length !== 2) throw new Error('DAYS requires 2 arguments (end_date, start_date)');\n const d1 = new Date(this.evaluateNode(args[0]));\n const d2 = new Date(this.evaluateNode(args[1]));\n const diffTime = d1.getTime() - d2.getTime();\n return Math.round(diffTime / (1000 * 60 * 60 * 24));\n }\n\n default:\n return '#NAME?';\n }\n }\n}\n","import { ASTNode, parseFormula, WHOLE_COLUMN_END_ROW } from './parser';\nimport { colNameToIndex, indexToColName } from './evaluator';\n\nexport interface CellDep {\n col: string;\n row: number;\n}\n\n/**\n * Dependency key for \"every cell in column `col`\", used by whole-column ranges\n * (`A:A`) instead of expanding a million cell keys.\n */\nexport const columnDependencyKey = (col: string): string => `${col.toUpperCase()}:`;\n\nexport function extractCellDependencies(node: ASTNode): CellDep[] {\n const deps: CellDep[] = [];\n\n const visit = (curr: ASTNode) => {\n if (curr.type === 'CellRef') {\n deps.push({ col: curr.col, row: curr.row });\n } else if (curr.type === 'Range' && curr.endRow >= WHOLE_COLUMN_END_ROW) {\n // Whole-column range: depend on the columns, not on every cell.\n const startC = colNameToIndex(curr.startCol);\n const endC = colNameToIndex(curr.endCol);\n for (let c = Math.min(startC, endC); c <= Math.max(startC, endC); c++) {\n deps.push({ col: indexToColName(c), row: 0 });\n }\n } else if (curr.type === 'Range') {\n const startC = colNameToIndex(curr.startCol);\n const endC = colNameToIndex(curr.endCol);\n const minC = Math.min(startC, endC);\n const maxC = Math.max(startC, endC);\n const minR = Math.min(curr.startRow, curr.endRow);\n const maxR = Math.max(curr.startRow, curr.endRow);\n\n for (let c = minC; c <= maxC; c++) {\n for (let r = minR; r <= maxR; r++) {\n deps.push({ col: indexToColName(c), row: r });\n }\n }\n } else if (curr.type === 'BinaryOp') {\n visit(curr.left);\n visit(curr.right);\n } else if (curr.type === 'UnaryOp') {\n visit(curr.argument);\n } else if (curr.type === 'FunctionCall') {\n curr.args.forEach(visit);\n }\n };\n\n visit(node);\n return deps;\n}\n\nexport class DependencyGraph {\n // Map of cellKey (e.g. \"B2\") -> Set of cellKeys that this cell depends ON\n private dependencies = new Map<string, Set<string>>();\n // Map of cellKey (e.g. \"A1\") -> Set of cellKeys that depend ON this cell (dependents)\n private dependents = new Map<string, Set<string>>();\n\n public setCellFormula(cellKey: string, formulaStr: string | null): void {\n const key = cellKey.toUpperCase();\n\n // Clear existing dependencies\n const oldDeps = this.dependencies.get(key) || new Set();\n for (const dep of oldDeps) {\n this.dependents.get(dep)?.delete(key);\n }\n this.dependencies.delete(key);\n\n if (!formulaStr || !formulaStr.startsWith('=')) {\n return;\n }\n\n try {\n const ast = parseFormula(formulaStr);\n const deps = extractCellDependencies(ast);\n const newDeps = new Set<string>();\n\n for (const d of deps) {\n const depKey = d.row === 0 ? columnDependencyKey(d.col) : `${d.col}${d.row}`.toUpperCase();\n newDeps.add(depKey);\n\n if (!this.dependents.has(depKey)) {\n this.dependents.set(depKey, new Set());\n }\n this.dependents.get(depKey)!.add(key);\n }\n\n this.dependencies.set(key, newDeps);\n } catch {\n // Syntax errors in formula have no valid dependencies\n }\n }\n\n /** Removes every registered formula and dependency. */\n public clear(): void {\n this.dependencies.clear();\n this.dependents.clear();\n }\n\n public getDependencies(cellKey: string): string[] {\n return Array.from(this.dependencies.get(cellKey.toUpperCase()) || []);\n }\n\n public getDependents(cellKey: string): string[] {\n return Array.from(this.dependents.get(cellKey.toUpperCase()) || []);\n }\n\n /**\n * Detects if there is a cycle containing cellKey.\n */\n public hasCycle(cellKey: string): boolean {\n const key = cellKey.toUpperCase();\n const visited = new Set<string>();\n const recStack = new Set<string>();\n\n const dfs = (node: string): boolean => {\n visited.add(node);\n recStack.add(node);\n\n const deps = this.dependencies.get(node) || new Set();\n for (const neighbor of deps) {\n if (!visited.has(neighbor)) {\n if (dfs(neighbor)) return true;\n } else if (recStack.has(neighbor)) {\n return true;\n }\n }\n\n recStack.delete(node);\n return false;\n };\n\n return dfs(key);\n }\n\n /**\n * Returns cells affected by updating cellKey in topological order.\n */\n public getEvaluationOrder(startCellKey: string): { order: string[]; hasCycle: boolean } {\n const start = startCellKey.toUpperCase();\n const visited = new Set<string>();\n const recStack = new Set<string>();\n const order: string[] = [];\n let cycleDetected = false;\n\n // Collect all downstream affected cells (reachability via dependents)\n const affected = new Set<string>();\n const collectAffected = (node: string) => {\n affected.add(node);\n const directDependents = this.dependents.get(node) || new Set();\n for (const dep of directDependents) {\n if (!affected.has(dep)) {\n collectAffected(dep);\n }\n }\n };\n collectAffected(start);\n\n // Topological sort among affected cells\n const visit = (node: string) => {\n if (recStack.has(node)) {\n cycleDetected = true;\n return;\n }\n if (visited.has(node)) return;\n\n recStack.add(node);\n visited.add(node);\n\n // Visit nodes that this node depends on, IF they are in the affected set\n const deps = this.dependencies.get(node) || new Set();\n for (const neighbor of deps) {\n if (affected.has(neighbor)) {\n visit(neighbor);\n }\n }\n\n recStack.delete(node);\n order.push(node);\n };\n\n for (const node of affected) {\n if (!visited.has(node)) {\n visit(node);\n }\n }\n\n return { order, hasCycle: cycleDetected };\n }\n\n /**\n * Plans a recalculation over `cellKeys` (and, with `includeDependents`, every\n * cell that transitively depends on them). Returns the keys in evaluation\n * order (dependencies first) and the set of keys that are part of a cycle,\n * which must be marked `#CYCLE!` instead of evaluated. Every member of a\n * cycle is reported, not just the cell that closed it.\n */\n public getEvaluationPlan(\n cellKeys: Iterable<string>,\n options: { includeDependents?: boolean } = {},\n ): { order: string[]; cyclic: Set<string> } {\n const nodes = new Set<string>();\n const queue: string[] = [];\n for (const key of cellKeys) {\n const upper = key.toUpperCase();\n if (!nodes.has(upper)) {\n nodes.add(upper);\n queue.push(upper);\n }\n }\n if (options.includeDependents) {\n while (queue.length > 0) {\n const node = queue.pop()!;\n const direct = [\n ...(this.dependents.get(node) ?? []),\n ...(this.dependents.get(columnDependencyKey(node.replace(/\\d+$/, ''))) ?? []),\n ];\n for (const dep of direct) {\n if (!nodes.has(dep)) {\n nodes.add(dep);\n queue.push(dep);\n }\n }\n }\n }\n\n // Edges point from a cell to the cells it depends on, restricted to `nodes`.\n // Whole-column dependencies expand to the planned cells in that column.\n const neighbors = (node: string): string[] => {\n const result: string[] = [];\n for (const dep of this.dependencies.get(node) ?? []) {\n if (dep.endsWith(':')) {\n const col = dep.slice(0, -1);\n for (const candidate of nodes) {\n if (candidate.replace(/\\d+$/, '') === col) result.push(candidate);\n }\n } else if (nodes.has(dep)) {\n result.push(dep);\n }\n }\n return result;\n };\n\n // Iterative Tarjan: SCCs are emitted dependencies-first.\n const order: string[] = [];\n const cyclic = new Set<string>();\n const index = new Map<string, number>();\n const low = new Map<string, number>();\n const stack: string[] = [];\n const onStack = new Set<string>();\n let counter = 0;\n\n for (const root of nodes) {\n if (index.has(root)) continue;\n const work: Array<{ node: string; edges: string[]; next: number }> = [];\n const enter = (node: string) => {\n index.set(node, counter);\n low.set(node, counter);\n counter++;\n stack.push(node);\n onStack.add(node);\n work.push({ node, edges: neighbors(node), next: 0 });\n };\n enter(root);\n\n while (work.length > 0) {\n const frame = work[work.length - 1];\n if (frame.next < frame.edges.length) {\n const target = frame.edges[frame.next++];\n if (!index.has(target)) {\n enter(target);\n } else if (onStack.has(target)) {\n low.set(frame.node, Math.min(low.get(frame.node)!, index.get(target)!));\n }\n continue;\n }\n\n work.pop();\n if (work.length > 0) {\n const parent = work[work.length - 1].node;\n low.set(parent, Math.min(low.get(parent)!, low.get(frame.node)!));\n }\n\n if (low.get(frame.node) === index.get(frame.node)) {\n const component: string[] = [];\n let member: string;\n do {\n member = stack.pop()!;\n onStack.delete(member);\n component.push(member);\n } while (member !== frame.node);\n\n const isCycle = component.length > 1 || frame.edges.includes(frame.node);\n for (const key of component) {\n order.push(key);\n if (isCycle) cyclic.add(key);\n }\n }\n }\n }\n\n return { order, cyclic };\n }\n}\n","import { tokenizeFormula } from './lexer';\nimport { colNameToIndex, indexToColName } from './evaluator';\n\n/**\n * A row or column insertion/deletion. `index` is the 0-based position of the\n * inserted or deleted row/column.\n */\nexport interface StructuralChange {\n axis: 'row' | 'col';\n index: number;\n type: 'insert' | 'delete';\n}\n\nconst CELL_PART = /^(\\$?)([A-Za-z]+)(\\$?)(\\d+)$/;\nconst COLUMN_PART = /^(\\$?)([A-Za-z]+)$/;\nconst REF_CHAR = /[A-Za-z0-9_$.:]/;\n\ninterface RefPart {\n colAbs: string;\n col: number; // 0-based column index\n rowAbs: string;\n row: number | null; // 0-based row index; null for whole-column parts (A:A)\n}\n\nfunction parsePart(text: string): RefPart | null {\n const cell = CELL_PART.exec(text);\n if (cell) {\n return {\n colAbs: cell[1],\n col: colNameToIndex(cell[2]),\n rowAbs: cell[3],\n row: parseInt(cell[4], 10) - 1,\n };\n }\n const column = COLUMN_PART.exec(text);\n if (column) {\n return { colAbs: column[1], col: colNameToIndex(column[2]), rowAbs: '', row: null };\n }\n return null;\n}\n\nfunction formatPart(part: RefPart): string {\n const col = `${part.colAbs}${indexToColName(part.col)}`;\n return part.row === null ? col : `${col}${part.rowAbs}${part.row + 1}`;\n}\n\n/** Shifts one coordinate; returns null when it points at a deleted row/column. */\nfunction shiftCoordinate(value: number, change: StructuralChange): number | null {\n if (change.type === 'insert') {\n return value >= change.index ? value + 1 : value;\n }\n if (value === change.index) return null;\n return value > change.index ? value - 1 : value;\n}\n\n/** Shifts a range's [lo, hi] bounds; returns null when the whole span is deleted. */\nfunction shiftSpan(lo: number, hi: number, change: StructuralChange): [number, number] | null {\n if (change.type === 'insert') {\n return [lo >= change.index ? lo + 1 : lo, hi >= change.index ? hi + 1 : hi];\n }\n if (lo === change.index && hi === change.index) return null;\n // Deleting inside or at the edge of a range shrinks it, like spreadsheets do.\n return [lo > change.index ? lo - 1 : lo, hi >= change.index ? hi - 1 : hi];\n}\n\nfunction rewriteReference(text: string, change: StructuralChange): string {\n const [startText, endText] = text.split(':');\n const start = parsePart(startText);\n if (!start) return text;\n\n const key = change.axis === 'row' ? 'row' : 'col';\n\n if (endText === undefined) {\n if (start[key] === null) return text;\n const shifted = shiftCoordinate(start[key] as number, change);\n if (shifted === null) return '#REF!';\n return formatPart({ ...start, [key]: shifted });\n }\n\n const end = parsePart(endText);\n if (!end) return text;\n if (start[key] === null || end[key] === null) return text; // e.g. rows of A:A\n\n const startValue = start[key] as number;\n const endValue = end[key] as number;\n const span = shiftSpan(Math.min(startValue, endValue), Math.max(startValue, endValue), change);\n if (span === null) return '#REF!';\n const [lo, hi] = span;\n const newStart = { ...start, [key]: startValue <= endValue ? lo : hi };\n const newEnd = { ...end, [key]: startValue <= endValue ? hi : lo };\n return `${formatPart(newStart)}:${formatPart(newEnd)}`;\n}\n\n/**\n * Rewrites the cell and range references in `formula` after a row or column\n * is inserted or deleted, the way spreadsheet apps do: references after the\n * change shift, ranges grow or shrink, and references to a deleted row/column\n * become `#REF!`. Absolute (`$`) markers are kept. String literals, property\n * references and function names are left untouched.\n */\nexport function shiftFormulaReferences(formula: string, change: StructuralChange): string {\n if (!formula.startsWith('=')) return formula;\n\n let tokens;\n try {\n tokens = tokenizeFormula(formula);\n } catch {\n return formula;\n }\n\n let result = '';\n let cursor = 0;\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n if (token.type !== 'CELL_REF' && token.type !== 'RANGE') continue;\n // Function names that look like cell references (e.g. LOG10) are calls.\n if (tokens[i + 1]?.type === 'LPAREN') continue;\n\n let end = token.position;\n while (end < formula.length && REF_CHAR.test(formula[end])) end++;\n const original = formula.slice(token.position, end);\n\n result += formula.slice(cursor, token.position) + rewriteReference(original, change);\n cursor = end;\n }\n return result + formula.slice(cursor);\n}\n","import { SpreadsheetDataSource, SpreadsheetRow, SpreadsheetColumn } from '../types';\n\nexport class DataSourceBinder {\n private dataSources = new Map<string, SpreadsheetDataSource>();\n\n public register(dataSource: SpreadsheetDataSource): void {\n this.dataSources.set(dataSource.id, dataSource);\n }\n\n public unregister(dataSourceId: string): void {\n this.dataSources.delete(dataSourceId);\n }\n\n public getDataSource(id: string): SpreadsheetDataSource | undefined {\n return this.dataSources.get(id);\n }\n\n /**\n * Generates or reconciles spreadsheet rows from a primary data source.\n */\n public syncRows(\n currentRows: SpreadsheetRow[],\n dataSourceId: string\n ): SpreadsheetRow[] {\n const ds = this.dataSources.get(dataSourceId);\n if (!ds) return currentRows;\n\n const records = ds.getRecords();\n const existingRecordRowMap = new Map<string, SpreadsheetRow>();\n const freeformRows: SpreadsheetRow[] = [];\n\n for (const row of currentRows) {\n if (row.type === 'record' && row.recordId) {\n existingRecordRowMap.set(row.recordId, row);\n } else {\n freeformRows.push(row);\n }\n }\n\n const nextRows: SpreadsheetRow[] = [];\n let rowIndex = 0;\n\n for (const record of records) {\n const existing = existingRecordRowMap.get(record.id);\n nextRows.push({\n id: existing?.id || `row_${record.id}`,\n index: rowIndex++,\n height: existing?.height || 32,\n recordId: record.id,\n type: 'record'\n });\n existingRecordRowMap.delete(record.id);\n }\n\n // Append preserved freeform rows\n for (const freeform of freeformRows) {\n nextRows.push({\n ...freeform,\n index: rowIndex++\n });\n }\n\n return nextRows;\n }\n\n /**\n * Resolves a record's bound field value.\n */\n public resolveBoundValue(\n dataSourceId: string,\n recordId: string,\n field: string\n ): any {\n const ds = this.dataSources.get(dataSourceId);\n if (!ds) return undefined;\n\n const records = ds.getRecords();\n const record = records.find((r) => r.id === recordId);\n return record ? record[field] : undefined;\n }\n\n /**\n * Dispatches an update to the underlying data source.\n */\n public async commitBoundValue(\n dataSourceId: string,\n recordId: string,\n field: string,\n value: any\n ): Promise<void> {\n const ds = this.dataSources.get(dataSourceId);\n if (!ds) return;\n await ds.updateRecord(recordId, field, value);\n }\n}\n","import {\n SpreadsheetDocument,\n SpreadsheetColumn,\n SpreadsheetRow,\n CellCoordinate,\n CellRange,\n CellData,\n SpreadsheetDataSource\n} from './types';\nimport {\n FormulaEvaluator,\n colNameToIndex,\n indexToColName,\n DependencyGraph,\n shiftFormulaReferences,\n WHOLE_COLUMN_END_ROW,\n type StructuralChange\n} from './formula';\nimport { DataSourceBinder } from './datasource';\n\nexport interface SpreadsheetControllerOptions {\n document?: Partial<SpreadsheetDocument>;\n dataSources?: SpreadsheetDataSource[];\n primaryDataSourceId?: string;\n onDocumentChange?: (doc: SpreadsheetDocument) => void;\n onSelectionChange?: (activeCell: CellCoordinate | null, range: CellRange | null) => void;\n onCellCommit?: (rowId: string, colId: string, raw: string, value: any) => void;\n}\n\nexport class SpreadsheetController {\n public document: SpreadsheetDocument;\n public activeCell: CellCoordinate | null = null;\n public selectedRange: CellRange | null = null;\n public editingCell: CellCoordinate | null = null;\n public draftValue = '';\n\n public readonly binder = new DataSourceBinder();\n public readonly depGraph = new DependencyGraph();\n public readonly evaluator: FormulaEvaluator;\n\n private primaryDataSourceId?: string;\n private onDocumentChange?: (doc: SpreadsheetDocument) => void;\n private onSelectionChange?: (activeCell: CellCoordinate | null, range: CellRange | null) => void;\n private onCellCommit?: (rowId: string, colId: string, raw: string, value: any) => void;\n\n // History stack for undo/redo\n private undoStack: string[] = [];\n private redoStack: string[] = [];\n private isApplyingHistory = false;\n // Set while importing TSV: history and recalculation are done once at the end.\n private batching = false;\n private pendingCommits: Array<[string, string, string]> = [];\n // Row being evaluated, so [property] references resolve per row.\n private evaluatingRowIndex: number | null = null;\n\n constructor(options: SpreadsheetControllerOptions = {}) {\n const defaultCols: SpreadsheetColumn[] = [\n { id: 'col_a', key: 'A', title: 'A', width: 120, type: 'freeform' },\n { id: 'col_b', key: 'B', title: 'B', width: 120, type: 'freeform' },\n { id: 'col_c', key: 'C', title: 'C', width: 120, type: 'freeform' },\n { id: 'col_d', key: 'D', title: 'D', width: 120, type: 'freeform' }\n ];\n\n const defaultRows: SpreadsheetRow[] = options.primaryDataSourceId ? [] : Array.from({ length: 10 }, (_, i) => ({\n id: `row_${i + 1}`,\n index: i,\n height: 32,\n type: 'freeform'\n }));\n\n this.document = {\n id: options.document?.id || `sheet_${Date.now()}`,\n name: options.document?.name || 'Sheet 1',\n columns: options.document?.columns || defaultCols,\n rows: options.document?.rows || defaultRows,\n cells: options.document?.cells || {},\n createdAt: options.document?.createdAt || Date.now(),\n updatedAt: options.document?.updatedAt || Date.now()\n };\n\n this.primaryDataSourceId = options.primaryDataSourceId;\n this.onDocumentChange = options.onDocumentChange;\n this.onSelectionChange = options.onSelectionChange;\n this.onCellCommit = options.onCellCommit;\n\n if (options.dataSources) {\n options.dataSources.forEach((ds) => this.binder.register(ds));\n }\n\n this.evaluator = new FormulaEvaluator({\n resolveCell: (colStr, rowNum) => this.resolveCellByCoord(colStr, rowNum),\n resolveRange: (sCol, sRow, eCol, eRow) => this.resolveRangeByCoords(sCol, sRow, eCol, eRow),\n resolveProperty: (prop) => this.resolveCurrentRowProperty(prop)\n });\n\n this.syncWithDataSource();\n this.recalculateAll();\n }\n\n public loadDocument(document: SpreadsheetDocument): void {\n this.document = JSON.parse(JSON.stringify(document));\n this.activeCell = null;\n this.selectedRange = null;\n this.editingCell = null;\n this.draftValue = '';\n this.undoStack = [];\n this.redoStack = [];\n this.syncWithDataSource();\n this.recalculateAll();\n this.notifyChange();\n }\n\n public registerDataSource(ds: SpreadsheetDataSource): void {\n this.binder.register(ds);\n this.syncWithDataSource();\n this.recalculateAll();\n }\n\n public setPrimaryDataSource(dataSourceId: string | undefined): void {\n this.primaryDataSourceId = dataSourceId;\n this.syncWithDataSource();\n this.recalculateAll();\n }\n\n public syncWithDataSource(): void {\n if (!this.primaryDataSourceId) return;\n this.document.rows = this.binder.syncRows(this.document.rows, this.primaryDataSourceId);\n this.recomputeRowIndices();\n }\n\n private recomputeRowIndices(): void {\n this.document.rows.forEach((r, idx) => {\n r.index = idx;\n });\n this.document.columns.forEach((c, idx) => {\n c.key = indexToColName(idx);\n });\n }\n\n public getColumn(colIdOrKey: string): SpreadsheetColumn | undefined {\n return this.document.columns.find(\n (c) => c.id === colIdOrKey || c.key.toUpperCase() === colIdOrKey.toUpperCase()\n );\n }\n\n public getRow(rowIdOrIndex: string | number): SpreadsheetRow | undefined {\n if (typeof rowIdOrIndex === 'number') {\n return this.document.rows[rowIdOrIndex];\n }\n return this.document.rows.find((r) => r.id === rowIdOrIndex);\n }\n\n public getCell(rowId: string, colId: string): CellData {\n const existing = this.document.cells[rowId]?.[colId];\n if (existing) return existing;\n\n const col = this.document.columns.find((c) => c.id === colId);\n const row = this.document.rows.find((r) => r.id === rowId);\n return this.getDerivedCell(row, col);\n }\n\n /** Value of a cell with no stored data: bound record value, column formula, or blank. */\n private getDerivedCell(row: SpreadsheetRow | undefined, col: SpreadsheetColumn | undefined): CellData {\n // Check if column is bound to record\n if (col && row && col.type === 'bound' && col.binding && row.recordId) {\n const boundVal = this.binder.resolveBoundValue(\n col.binding.dataSource,\n row.recordId,\n col.binding.field\n );\n return {\n raw: boundVal !== undefined ? String(boundVal) : '',\n value: boundVal ?? '',\n format: col.format\n };\n }\n\n // Check if column has a column-level formula\n if (col && col.type === 'formula' && col.formula) {\n return {\n raw: col.formula,\n value: '',\n format: col.format\n };\n }\n\n return { raw: '', value: '', format: col?.format };\n }\n\n public setCellValue(rowId: string, colId: string, raw: string): void {\n this.recordSnapshot();\n\n if (!this.document.cells[rowId]) {\n this.document.cells[rowId] = {};\n }\n\n const col = this.document.columns.find((c) => c.id === colId);\n const row = this.document.rows.find((r) => r.id === rowId);\n\n // If this is a bound column and row is bound to record, dispatch back to data source\n if (col?.type === 'bound' && col.binding && row?.recordId) {\n this.binder.commitBoundValue(\n col.binding.dataSource,\n row.recordId,\n col.binding.field,\n raw\n );\n }\n\n const cellKey = this.getCellKey(rowId, colId);\n this.depGraph.setCellFormula(cellKey, raw.startsWith('=') ? raw : null);\n\n this.document.cells[rowId][colId] = {\n raw,\n value: raw,\n format: col?.format\n };\n\n this.document.updatedAt = Date.now();\n if (this.batching) {\n this.pendingCommits.push([rowId, colId, raw]);\n return;\n }\n this.recalculateCell(rowId, colId);\n this.notifyChange();\n\n const evaluatedVal = this.document.cells[rowId][colId]?.value;\n this.onCellCommit?.(rowId, colId, raw, evaluatedVal);\n }\n\n private getCellKey(rowId: string, colId: string): string {\n const row = this.document.rows.find((r) => r.id === rowId);\n const col = this.document.columns.find((c) => c.id === colId);\n if (!row || !col) return `${colId}_${rowId}`;\n return `${col.key}${row.index + 1}`.toUpperCase();\n }\n\n /**\n * Recalculates a cell and everything that depends on it, in dependency\n * order. Every cell in a reference cycle is marked `#CYCLE!`.\n */\n public recalculateCell(rowId: string, colId: string): void {\n const cellKey = this.getCellKey(rowId, colId);\n this.runEvaluationPlan(this.depGraph.getEvaluationPlan([cellKey], { includeDependents: true }));\n }\n\n /**\n * Rebuilds the dependency graph from scratch and recalculates every formula\n * in dependency order.\n */\n public recalculateAll(): void {\n this.depGraph.clear();\n const formulaKeys: string[] = [];\n for (const row of this.document.rows) {\n for (const col of this.document.columns) {\n // Avoid getCell's id lookups: this loop visits every cell.\n const cell = this.document.cells[row.id]?.[col.id] ?? this.getDerivedCell(row, col);\n if (cell.raw.startsWith('=')) {\n const cellKey = `${col.key}${row.index + 1}`.toUpperCase();\n this.depGraph.setCellFormula(cellKey, cell.raw);\n formulaKeys.push(cellKey);\n }\n }\n }\n this.runEvaluationPlan(this.depGraph.getEvaluationPlan(formulaKeys));\n }\n\n private runEvaluationPlan(plan: { order: string[]; cyclic: Set<string> }): void {\n for (const key of plan.order) {\n if (plan.cyclic.has(key)) {\n this.markCycle(key);\n } else {\n this.evalSingleCellByKey(key);\n }\n }\n }\n\n private locateCellKey(cellKey: string): { row: SpreadsheetRow; col: SpreadsheetColumn } | null {\n const match = cellKey.match(/^([A-Za-z]+)(\\d+)$/);\n if (!match) return null;\n const col = this.document.columns.find((c) => c.key.toUpperCase() === match[1].toUpperCase());\n const row = this.document.rows[parseInt(match[2], 10) - 1];\n return col && row ? { row, col } : null;\n }\n\n private markCycle(cellKey: string): void {\n const located = this.locateCellKey(cellKey);\n if (!located) return;\n const { row, col } = located;\n const cell = this.getCell(row.id, col.id);\n if (!cell.raw.startsWith('=')) return;\n if (!this.document.cells[row.id]) this.document.cells[row.id] = {};\n this.document.cells[row.id][col.id] = { ...cell, value: '#CYCLE!', error: '#CYCLE!' };\n }\n\n private evalSingleCellByKey(cellKey: string): void {\n const match = cellKey.match(/^([A-Za-z]+)(\\d+)$/);\n if (!match) return;\n const colName = match[1].toUpperCase();\n const rowNum = parseInt(match[2], 10);\n\n const col = this.document.columns.find((c) => c.key.toUpperCase() === colName);\n const row = this.document.rows[rowNum - 1];\n if (!col || !row) return;\n\n const cell = this.getCell(row.id, col.id);\n if (!cell.raw.startsWith('=')) {\n if (cell.error === '#CYCLE!') {\n cell.error = undefined;\n }\n return;\n }\n\n try {\n this.evaluatingRowIndex = rowNum - 1;\n const computed = this.evaluator.evaluate(cell.raw);\n if (!this.document.cells[row.id]) {\n this.document.cells[row.id] = {};\n }\n this.document.cells[row.id][col.id] = {\n ...cell,\n value: computed,\n error: undefined\n };\n } catch (err: any) {\n if (!this.document.cells[row.id]) {\n this.document.cells[row.id] = {};\n }\n this.document.cells[row.id][col.id] = {\n ...cell,\n value: '#ERROR!',\n error: err?.message || 'Formula error'\n };\n } finally {\n this.evaluatingRowIndex = null;\n }\n }\n\n private resolveCellByCoord(colStr: string, rowNum: number): any {\n const col = this.document.columns.find((c) => c.key.toUpperCase() === colStr.toUpperCase());\n const row = this.document.rows[rowNum - 1];\n if (!col || !row) return 0;\n\n // Blank cells resolve to '' (0 in arithmetic, \"\" in text), as in spreadsheets.\n return this.getCell(row.id, col.id).value ?? '';\n }\n\n private resolveRangeByCoords(sCol: string, sRow: number, eCol: string, eRow: number): any[] {\n const startC = colNameToIndex(sCol);\n const endC = colNameToIndex(eCol);\n const minC = Math.min(startC, endC);\n const maxC = Math.max(startC, endC);\n const minR = Math.min(sRow, eRow);\n // Whole-column ranges (A:A) stop at the last row.\n const maxR = Math.min(Math.max(sRow, eRow), WHOLE_COLUMN_END_ROW, this.document.rows.length);\n\n const results: any[] = [];\n for (let c = minC; c <= maxC; c++) {\n const colName = indexToColName(c);\n const col = this.document.columns.find((colDef) => colDef.key.toUpperCase() === colName);\n if (!col) continue;\n\n for (let r = minR; r <= maxR; r++) {\n const row = this.document.rows[r - 1];\n if (!row) continue;\n results.push(this.getCell(row.id, col.id).value ?? '');\n }\n }\n return results;\n }\n\n private resolveCurrentRowProperty(prop: string): any {\n // Resolve against the row being evaluated, not the selected cell's row.\n const rowIndex = this.evaluatingRowIndex ?? this.activeCell?.row;\n if (rowIndex === undefined || rowIndex === null) return 0;\n const row = this.document.rows[rowIndex];\n if (!row || !row.recordId || !this.primaryDataSourceId) return 0;\n return this.binder.resolveBoundValue(this.primaryDataSourceId, row.recordId, prop) ?? 0;\n }\n\n // --- Selection and Navigation ---\n\n public selectCell(row: number, col: number, extendSelection = false): void {\n const clampedRow = Math.max(0, Math.min(row, this.document.rows.length - 1));\n const clampedCol = Math.max(0, Math.min(col, this.document.columns.length - 1));\n\n const rowObj = this.document.rows[clampedRow];\n const colObj = this.document.columns[clampedCol];\n\n this.activeCell = {\n row: clampedRow,\n col: clampedCol,\n rowId: rowObj?.id,\n colId: colObj?.id\n };\n\n if (extendSelection && this.selectedRange) {\n this.selectedRange = {\n startRow: this.selectedRange.startRow,\n startCol: this.selectedRange.startCol,\n endRow: clampedRow,\n endCol: clampedCol\n };\n } else {\n this.selectedRange = {\n startRow: clampedRow,\n startCol: clampedCol,\n endRow: clampedRow,\n endCol: clampedCol\n };\n }\n\n this.onSelectionChange?.(this.activeCell, this.selectedRange);\n }\n\n public selectRange(range: CellRange): void {\n this.selectedRange = range;\n this.onSelectionChange?.(this.activeCell, this.selectedRange);\n }\n\n public startEditing(row?: number, col?: number, initialValue?: string): void {\n const targetRow = row ?? this.activeCell?.row ?? 0;\n const targetCol = col ?? this.activeCell?.col ?? 0;\n this.selectCell(targetRow, targetCol);\n\n const rowObj = this.document.rows[targetRow];\n const colObj = this.document.columns[targetCol];\n if (!rowObj || !colObj) return;\n\n this.editingCell = {\n row: targetRow,\n col: targetCol,\n rowId: rowObj.id,\n colId: colObj.id\n };\n\n const cell = this.getCell(rowObj.id, colObj.id);\n this.draftValue = initialValue !== undefined ? initialValue : cell.raw;\n }\n\n public commitEditing(valueToCommit?: string): void {\n if (!this.editingCell) return;\n const val = valueToCommit !== undefined ? valueToCommit : this.draftValue;\n if (this.editingCell.rowId && this.editingCell.colId) {\n this.setCellValue(this.editingCell.rowId, this.editingCell.colId, val);\n }\n this.editingCell = null;\n this.draftValue = '';\n }\n\n public cancelEditing(): void {\n this.editingCell = null;\n this.draftValue = '';\n }\n\n public moveCursor(\n direction: 'up' | 'down' | 'left' | 'right',\n extendSelection = false\n ): void {\n if (!this.activeCell) {\n this.selectCell(0, 0);\n return;\n }\n\n let nextRow = this.activeCell.row;\n let nextCol = this.activeCell.col;\n\n switch (direction) {\n case 'up':\n nextRow = Math.max(0, nextRow - 1);\n break;\n case 'down':\n nextRow = Math.min(this.document.rows.length - 1, nextRow + 1);\n break;\n case 'left':\n nextCol = Math.max(0, nextCol - 1);\n break;\n case 'right':\n nextCol = Math.min(this.document.columns.length - 1, nextCol + 1);\n break;\n }\n\n this.selectCell(nextRow, nextCol, extendSelection);\n }\n\n // --- Grid Structure Mutations ---\n\n public insertColumn(index: number, config?: Partial<SpreadsheetColumn>): void {\n this.recordSnapshot();\n const newId = config?.id || this.generateId('col');\n const newCol: SpreadsheetColumn = {\n id: newId,\n key: indexToColName(index),\n title: config?.title || indexToColName(index),\n width: config?.width || 130,\n type: config?.type || 'freeform',\n binding: config?.binding,\n formula: config?.formula,\n format: config?.format || 'text',\n readOnly: config?.readOnly\n };\n\n this.shiftReferences({ axis: 'col', index, type: 'insert' });\n this.document.columns.splice(index, 0, newCol);\n this.recomputeRowIndices();\n this.recalculateAll();\n this.notifyChange();\n }\n\n public deleteColumn(colId: string): void {\n this.recordSnapshot();\n const colIndex = this.document.columns.findIndex((c) => c.id === colId);\n if (colIndex === -1) return;\n this.shiftReferences({ axis: 'col', index: colIndex, type: 'delete' });\n this.document.columns = this.document.columns.filter((c) => c.id !== colId);\n for (const rowId of Object.keys(this.document.cells)) {\n delete this.document.cells[rowId][colId];\n }\n this.recomputeRowIndices();\n this.recalculateAll();\n this.notifyChange();\n }\n\n public insertRow(index: number, config?: Partial<SpreadsheetRow>): void {\n this.recordSnapshot();\n const newId = config?.id || this.generateId('row');\n const newRow: SpreadsheetRow = {\n id: newId,\n index,\n height: config?.height || 32,\n recordId: config?.recordId,\n type: config?.type || 'freeform'\n };\n\n this.shiftReferences({ axis: 'row', index, type: 'insert' });\n this.document.rows.splice(index, 0, newRow);\n this.recomputeRowIndices();\n this.recalculateAll();\n this.notifyChange();\n }\n\n public deleteRow(rowId: string): void {\n this.recordSnapshot();\n const rowIndex = this.document.rows.findIndex((r) => r.id === rowId);\n if (rowIndex === -1) return;\n this.shiftReferences({ axis: 'row', index: rowIndex, type: 'delete' });\n this.document.rows = this.document.rows.filter((r) => r.id !== rowId);\n delete this.document.cells[rowId];\n this.recomputeRowIndices();\n this.recalculateAll();\n this.notifyChange();\n }\n\n private generateId(prefix: 'row' | 'col'): string {\n return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;\n }\n\n /**\n * Rewrites references in every cell formula (and, for column changes, every\n * column formula) so they keep pointing at the same cells.\n */\n private shiftReferences(change: StructuralChange): void {\n for (const rowCells of Object.values(this.document.cells)) {\n for (const cell of Object.values(rowCells)) {\n if (cell.raw?.startsWith('=')) {\n cell.raw = shiftFormulaReferences(cell.raw, change);\n }\n }\n }\n if (change.axis === 'col') {\n for (const col of this.document.columns) {\n if (col.formula?.startsWith('=')) {\n col.formula = shiftFormulaReferences(col.formula, change);\n }\n }\n }\n }\n\n public setColumnWidth(colId: string, width: number): void {\n const col = this.document.columns.find((c) => c.id === colId);\n if (col) {\n col.width = Math.max(30, width);\n this.notifyChange();\n }\n }\n\n public autoFitColumnWidth(colId: string, customWidth?: number): void {\n if (customWidth !== undefined) {\n this.setColumnWidth(colId, customWidth);\n return;\n }\n const col = this.document.columns.find((c) => c.id === colId);\n if (!col) return;\n\n let maxLen = (col.title || '').length + (col.key ? col.key.length + 3 : 0);\n for (const row of this.document.rows) {\n const cell = this.getCell(row.id, col.id);\n const valStr = cell.value != null ? String(cell.value) : '';\n if (valStr.length > maxLen) {\n maxLen = valStr.length;\n }\n }\n const estimatedWidth = Math.min(600, Math.max(50, Math.ceil(maxLen * 8.5 + 32)));\n this.setColumnWidth(colId, estimatedWidth);\n }\n\n // --- Clipboard TSV/CSV ---\n\n /**\n * Exports cell values as TSV: the whole sheet, or only `range` (e.g. the\n * current selection) when given.\n */\n public exportToTsv(range?: CellRange | null): string {\n const rows = range\n ? this.document.rows.slice(\n Math.min(range.startRow, range.endRow),\n Math.max(range.startRow, range.endRow) + 1,\n )\n : this.document.rows;\n const columns = range\n ? this.document.columns.slice(\n Math.min(range.startCol, range.endCol),\n Math.max(range.startCol, range.endCol) + 1,\n )\n : this.document.columns;\n return rows\n .map((row) =>\n columns\n .map((col) => {\n const cell = this.getCell(row.id, col.id);\n return String(cell.value ?? '').replace(/\\t/g, ' ');\n })\n .join('\\t')\n )\n .join('\\n');\n }\n\n /**\n * Pastes tab-separated values starting at (startRow, startCol), adding rows\n * and columns as needed. The whole paste is a single undo step.\n */\n public importFromTsv(tsvData: string, startRow = 0, startCol = 0): void {\n // Only drop the final line break: leading tabs are empty cells.\n const normalized = tsvData.replace(/\\r\\n?/g, '\\n').replace(/\\n$/, '');\n if (normalized === '') return;\n\n this.recordSnapshot();\n this.batching = true;\n this.pendingCommits = [];\n try {\n normalized.split('\\n').forEach((line, rIdx) => {\n const targetR = startRow + rIdx;\n // Growing the grid is not an insertion: no references shift.\n while (targetR >= this.document.rows.length) {\n const index = this.document.rows.length;\n this.document.rows.push({ id: this.generateId('row'), index, height: 32, type: 'freeform' });\n }\n const row = this.document.rows[targetR];\n\n line.split('\\t').forEach((val, cIdx) => {\n const targetC = startCol + cIdx;\n while (targetC >= this.document.columns.length) {\n const key = indexToColName(this.document.columns.length);\n this.document.columns.push({\n id: this.generateId('col'),\n key,\n title: key,\n width: 130,\n type: 'freeform',\n format: 'text'\n });\n }\n this.setCellValue(row.id, this.document.columns[targetC].id, val);\n });\n });\n } finally {\n this.batching = false;\n }\n\n this.recalculateAll();\n this.notifyChange();\n const commits = this.pendingCommits;\n this.pendingCommits = [];\n for (const [rowId, colId, raw] of commits) {\n this.onCellCommit?.(rowId, colId, raw, this.document.cells[rowId]?.[colId]?.value);\n }\n }\n\n // --- Undo/Redo Snapshots ---\n\n private recordSnapshot(): void {\n if (this.isApplyingHistory || this.batching) return;\n this.undoStack.push(JSON.stringify(this.document));\n if (this.undoStack.length > 50) this.undoStack.shift();\n this.redoStack = [];\n }\n\n public undo(): void {\n if (this.undoStack.length === 0) return;\n this.isApplyingHistory = true;\n try {\n this.redoStack.push(JSON.stringify(this.document));\n this.document = JSON.parse(this.undoStack.pop()!);\n this.recalculateAll();\n this.notifyChange();\n } finally {\n this.isApplyingHistory = false;\n }\n }\n\n public redo(): void {\n if (this.redoStack.length === 0) return;\n this.isApplyingHistory = true;\n try {\n this.undoStack.push(JSON.stringify(this.document));\n this.document = JSON.parse(this.redoStack.pop()!);\n this.recalculateAll();\n this.notifyChange();\n } finally {\n this.isApplyingHistory = false;\n }\n }\n\n private notifyChange(): void {\n this.onDocumentChange?.(this.document);\n }\n}\n"]}
package/dist/index.cjs CHANGED
@@ -71,7 +71,12 @@ var _chunkLLUAKTLWcjs = require('./chunk-LLUAKTLW.cjs');
71
71
 
72
72
 
73
73
 
74
- var _chunkCYKQLDYHcjs = require('./chunk-CYKQLDYH.cjs');
74
+
75
+
76
+
77
+
78
+
79
+ var _chunkYQCI4CCNcjs = require('./chunk-YQCI4CCN.cjs');
75
80
 
76
81
 
77
82
 
@@ -363,5 +368,10 @@ function createDirtyTracker(initialBaseline, options) {
363
368
 
364
369
 
365
370
 
366
- exports.ColorHighlighter = _chunkLDES3EOScjs.ColorHighlighter; exports.DataSourceBinder = _chunkCYKQLDYHcjs.DataSourceBinder; exports.DependencyGraph = _chunkCYKQLDYHcjs.DependencyGraph; exports.DirtyTracker = DirtyTracker; exports.EditorController = EditorController; exports.FontSize = _chunkLDES3EOScjs.FontSize; exports.FormulaEvaluator = _chunkCYKQLDYHcjs.FormulaEvaluator; exports.FormulaParser = _chunkCYKQLDYHcjs.FormulaParser; exports.GradientText = _chunkLDES3EOScjs.GradientText; exports.HistoryManager = _chunk33UVEDOScjs.HistoryManager; exports.INSTRUCTION_REGEX = _chunkSEDR75VHcjs.INSTRUCTION_REGEX; exports.Image = _chunkLDES3EOScjs.Image; exports.LoadingNode = _chunkLDES3EOScjs.LoadingNode; exports.MARKDOWN_MENTION_SPLIT_REGEX = _chunkLLUAKTLWcjs.MARKDOWN_MENTION_SPLIT_REGEX; exports.MENTION_REGEX = _chunkLLUAKTLWcjs.MENTION_REGEX; exports.Markdown = _chunkLDES3EOScjs.Markdown; exports.Mention = _chunkLDES3EOScjs.Mention; exports.SlashCommands = _chunkLDES3EOScjs.SlashCommands; exports.SmilieReplacer = _chunkLDES3EOScjs.SmilieReplacer; exports.SpreadsheetController = _chunkCYKQLDYHcjs.SpreadsheetController; exports.TEMPLATE_DEPTH_ERROR = _chunkMPPXH7U5cjs.TEMPLATE_DEPTH_ERROR; exports.TEMPLATE_LOOP_ERROR = _chunkMPPXH7U5cjs.TEMPLATE_LOOP_ERROR; exports.TEMPLATE_REGEX = _chunkSEDR75VHcjs.TEMPLATE_REGEX; exports.TemplateSuggestions = _chunkLDES3EOScjs.TemplateSuggestions; exports.VARIABLE_REGEX = _chunkSEDR75VHcjs.VARIABLE_REGEX; exports.colNameToIndex = _chunkCYKQLDYHcjs.colNameToIndex; exports.createDirtyTracker = createDirtyTracker; exports.createEditor = createEditor; exports.createHistoryManager = _chunk33UVEDOScjs.createHistoryManager; exports.createMentionExtension = _chunkLDES3EOScjs.createMentionExtension; exports.createRichTextPreset = _chunkLDES3EOScjs.createRichTextPreset; exports.defaultIsEqual = defaultIsEqual; exports.escapeHtml = _chunkLLUAKTLWcjs.escapeHtml; exports.extractCellDependencies = _chunkCYKQLDYHcjs.extractCellDependencies; exports.extractInstructionNames = _chunkMPPXH7U5cjs.extractInstructionNames; exports.extractMentions = _chunkLLUAKTLWcjs.extractMentions; exports.extractMentionsFromDoc = _chunkLLUAKTLWcjs.extractMentionsFromDoc; exports.extractTemplateNames = _chunkMPPXH7U5cjs.extractTemplateNames; exports.extractVariableNames = _chunkMPPXH7U5cjs.extractVariableNames; exports.findHexColors = _chunkLDES3EOScjs.findHexColors; exports.getEditorMarkdown = _chunkLLUAKTLWcjs.getEditorMarkdown; exports.getEditorText = _chunkLLUAKTLWcjs.getEditorText; exports.getLatestVersion = _chunkMPPXH7U5cjs.getLatestVersion; exports.getTemplateBody = _chunkMPPXH7U5cjs.getTemplateBody; exports.handleImageInsertion = _chunkLDES3EOScjs.handleImageInsertion; exports.htmlToPlainText = _chunkLLUAKTLWcjs.htmlToPlainText; exports.imagePastePluginKey = _chunkLDES3EOScjs.imagePastePluginKey; exports.indexToColName = _chunkCYKQLDYHcjs.indexToColName; exports.insertImageNode = _chunkLDES3EOScjs.insertImageNode; exports.instructionRegex = _chunkSEDR75VHcjs.instructionRegex; exports.mapRawOffsetToResolved = _chunkMPPXH7U5cjs.mapRawOffsetToResolved; exports.mapResolvedOffsetToRaw = _chunkMPPXH7U5cjs.mapResolvedOffsetToRaw; exports.markdownToTipTapHtml = _chunkLLUAKTLWcjs.markdownToTipTapHtml; exports.parseCellReference = _chunkCYKQLDYHcjs.parseCellReference; exports.parseFormula = _chunkCYKQLDYHcjs.parseFormula; exports.parseMentionSegments = _chunkLLUAKTLWcjs.parseMentionSegments; exports.parseRange = _chunkCYKQLDYHcjs.parseRange; exports.plainTextToSlice = _chunkLLUAKTLWcjs.plainTextToSlice; exports.plainTextToTipTapHtml = _chunkLLUAKTLWcjs.plainTextToTipTapHtml; exports.preprocessMarkdownFileLinks = _chunkLLUAKTLWcjs.preprocessMarkdownFileLinks; exports.preprocessMarkdownMentions = _chunkLLUAKTLWcjs.preprocessMarkdownMentions; exports.removeImageNode = _chunkLDES3EOScjs.removeImageNode; exports.resolveTemplates = _chunkMPPXH7U5cjs.resolveTemplates; exports.resolveTemplatesWithMapping = _chunkMPPXH7U5cjs.resolveTemplatesWithMapping; exports.resolveVariables = _chunkMPPXH7U5cjs.resolveVariables; exports.stripMarkdownCode = _chunkLLUAKTLWcjs.stripMarkdownCode; exports.templateRegex = _chunkSEDR75VHcjs.templateRegex; exports.tokenizeFormula = _chunkCYKQLDYHcjs.tokenizeFormula; exports.tokenizePrompt = _chunkMPPXH7U5cjs.tokenizePrompt; exports.updateImageSrc = _chunkLDES3EOScjs.updateImageSrc; exports.variableRegex = _chunkSEDR75VHcjs.variableRegex;
371
+
372
+
373
+
374
+
375
+
376
+ exports.ColorHighlighter = _chunkLDES3EOScjs.ColorHighlighter; exports.DataSourceBinder = _chunkYQCI4CCNcjs.DataSourceBinder; exports.DependencyGraph = _chunkYQCI4CCNcjs.DependencyGraph; exports.DirtyTracker = DirtyTracker; exports.EditorController = EditorController; exports.FORMULA_ERRORS = _chunkYQCI4CCNcjs.FORMULA_ERRORS; exports.FontSize = _chunkLDES3EOScjs.FontSize; exports.FormulaEvaluator = _chunkYQCI4CCNcjs.FormulaEvaluator; exports.FormulaParser = _chunkYQCI4CCNcjs.FormulaParser; exports.GradientText = _chunkLDES3EOScjs.GradientText; exports.HistoryManager = _chunk33UVEDOScjs.HistoryManager; exports.INSTRUCTION_REGEX = _chunkSEDR75VHcjs.INSTRUCTION_REGEX; exports.Image = _chunkLDES3EOScjs.Image; exports.LoadingNode = _chunkLDES3EOScjs.LoadingNode; exports.MARKDOWN_MENTION_SPLIT_REGEX = _chunkLLUAKTLWcjs.MARKDOWN_MENTION_SPLIT_REGEX; exports.MENTION_REGEX = _chunkLLUAKTLWcjs.MENTION_REGEX; exports.Markdown = _chunkLDES3EOScjs.Markdown; exports.Mention = _chunkLDES3EOScjs.Mention; exports.SlashCommands = _chunkLDES3EOScjs.SlashCommands; exports.SmilieReplacer = _chunkLDES3EOScjs.SmilieReplacer; exports.SpreadsheetController = _chunkYQCI4CCNcjs.SpreadsheetController; exports.TEMPLATE_DEPTH_ERROR = _chunkMPPXH7U5cjs.TEMPLATE_DEPTH_ERROR; exports.TEMPLATE_LOOP_ERROR = _chunkMPPXH7U5cjs.TEMPLATE_LOOP_ERROR; exports.TEMPLATE_REGEX = _chunkSEDR75VHcjs.TEMPLATE_REGEX; exports.TemplateSuggestions = _chunkLDES3EOScjs.TemplateSuggestions; exports.VARIABLE_REGEX = _chunkSEDR75VHcjs.VARIABLE_REGEX; exports.WHOLE_COLUMN_END_ROW = _chunkYQCI4CCNcjs.WHOLE_COLUMN_END_ROW; exports.colNameToIndex = _chunkYQCI4CCNcjs.colNameToIndex; exports.columnDependencyKey = _chunkYQCI4CCNcjs.columnDependencyKey; exports.createDirtyTracker = createDirtyTracker; exports.createEditor = createEditor; exports.createHistoryManager = _chunk33UVEDOScjs.createHistoryManager; exports.createMentionExtension = _chunkLDES3EOScjs.createMentionExtension; exports.createRichTextPreset = _chunkLDES3EOScjs.createRichTextPreset; exports.defaultIsEqual = defaultIsEqual; exports.escapeHtml = _chunkLLUAKTLWcjs.escapeHtml; exports.extractCellDependencies = _chunkYQCI4CCNcjs.extractCellDependencies; exports.extractInstructionNames = _chunkMPPXH7U5cjs.extractInstructionNames; exports.extractMentions = _chunkLLUAKTLWcjs.extractMentions; exports.extractMentionsFromDoc = _chunkLLUAKTLWcjs.extractMentionsFromDoc; exports.extractTemplateNames = _chunkMPPXH7U5cjs.extractTemplateNames; exports.extractVariableNames = _chunkMPPXH7U5cjs.extractVariableNames; exports.findHexColors = _chunkLDES3EOScjs.findHexColors; exports.getEditorMarkdown = _chunkLLUAKTLWcjs.getEditorMarkdown; exports.getEditorText = _chunkLLUAKTLWcjs.getEditorText; exports.getLatestVersion = _chunkMPPXH7U5cjs.getLatestVersion; exports.getTemplateBody = _chunkMPPXH7U5cjs.getTemplateBody; exports.handleImageInsertion = _chunkLDES3EOScjs.handleImageInsertion; exports.htmlToPlainText = _chunkLLUAKTLWcjs.htmlToPlainText; exports.imagePastePluginKey = _chunkLDES3EOScjs.imagePastePluginKey; exports.indexToColName = _chunkYQCI4CCNcjs.indexToColName; exports.insertImageNode = _chunkLDES3EOScjs.insertImageNode; exports.instructionRegex = _chunkSEDR75VHcjs.instructionRegex; exports.isFormulaError = _chunkYQCI4CCNcjs.isFormulaError; exports.mapRawOffsetToResolved = _chunkMPPXH7U5cjs.mapRawOffsetToResolved; exports.mapResolvedOffsetToRaw = _chunkMPPXH7U5cjs.mapResolvedOffsetToRaw; exports.markdownToTipTapHtml = _chunkLLUAKTLWcjs.markdownToTipTapHtml; exports.parseCellReference = _chunkYQCI4CCNcjs.parseCellReference; exports.parseFormula = _chunkYQCI4CCNcjs.parseFormula; exports.parseMentionSegments = _chunkLLUAKTLWcjs.parseMentionSegments; exports.parseRange = _chunkYQCI4CCNcjs.parseRange; exports.plainTextToSlice = _chunkLLUAKTLWcjs.plainTextToSlice; exports.plainTextToTipTapHtml = _chunkLLUAKTLWcjs.plainTextToTipTapHtml; exports.preprocessMarkdownFileLinks = _chunkLLUAKTLWcjs.preprocessMarkdownFileLinks; exports.preprocessMarkdownMentions = _chunkLLUAKTLWcjs.preprocessMarkdownMentions; exports.removeImageNode = _chunkLDES3EOScjs.removeImageNode; exports.resolveTemplates = _chunkMPPXH7U5cjs.resolveTemplates; exports.resolveTemplatesWithMapping = _chunkMPPXH7U5cjs.resolveTemplatesWithMapping; exports.resolveVariables = _chunkMPPXH7U5cjs.resolveVariables; exports.shiftFormulaReferences = _chunkYQCI4CCNcjs.shiftFormulaReferences; exports.stripMarkdownCode = _chunkLLUAKTLWcjs.stripMarkdownCode; exports.templateRegex = _chunkSEDR75VHcjs.templateRegex; exports.tokenizeFormula = _chunkYQCI4CCNcjs.tokenizeFormula; exports.tokenizePrompt = _chunkMPPXH7U5cjs.tokenizePrompt; exports.updateImageSrc = _chunkLDES3EOScjs.updateImageSrc; exports.variableRegex = _chunkSEDR75VHcjs.variableRegex;
367
377
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/index.cjs","../src/controller.ts","../src/dirty.ts"],"names":[],"mappings":"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SAAA,UAAW,gBAAA;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKO,WAAA,CAAA,EAAiB;AACtB,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,WAAA,CAAY,KAAA,EAAgB;AACjC,IAAA,IAAA,CAAK,SAAA,EAAW,KAAA;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKO,OAAA,CAAQ,OAAA,EAAqB;AAClC,IAAA,OAAO,CAAC,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,QAAA,EAAU,OAAO,CAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKO,KAAA,CAAM,OAAA,EAAkB;AAC7B,IAAA,IAAA,CAAK,SAAA,EAAW,OAAA;AAAA,EAClB;AACF,CAAA;AAKO,SAAS,kBAAA,CACd,eAAA,EACA,OAAA,EACiB;AACjB,EAAA,OAAO,IAAI,YAAA,CAAa,eAAA,EAAiB,OAAO,CAAA;AAClD;AFiMA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,g1IAAC","file":"/home/runner/work/editor/editor/packages/core/dist/index.cjs","sourcesContent":[null,"import { Editor, EditorOptions, Content, Extensions } from \"@tiptap/core\";\nimport { Slice } from \"@tiptap/pm/model\";\nimport { Token, tokenizePrompt } from \"./grammar\";\nimport {\n plainTextToTipTapHtml,\n plainTextToSlice,\n getEditorText,\n markdownToTipTapHtml,\n getEditorMarkdown,\n} from \"./serializers\";\n\nexport interface EditorControllerOptions extends Partial<\n Omit<EditorOptions, \"element\" | \"content\">\n> {\n element?: Element | HTMLElement | null;\n content?: string | Content;\n plainTextMode?: boolean;\n markdownMode?: boolean;\n extensions?: Extensions;\n onPlainTextChange?: (text: string) => void;\n onMarkdownChange?: (markdown: string) => void;\n onTokensChange?: (tokens: Token[]) => void;\n onSelectionChange?: (range: { from: number; to: number } | null) => void;\n}\n\n/**\n * UI-agnostic controller managing the lifecycle, commands, and plain-text/token\n * synchronization of a rich text or prompt editor.\n */\nexport class EditorController {\n public readonly editor: Editor;\n private readonly plainTextMode: boolean;\n private readonly markdownMode: boolean;\n private readonly onPlainTextChange?: (text: string) => void;\n private readonly onMarkdownChange?: (markdown: string) => void;\n private readonly onTokensChange?: (tokens: Token[]) => void;\n private readonly onSelectionChange?: (\n range: { from: number; to: number } | null,\n ) => void;\n private baselineContent: string;\n\n constructor(options: EditorControllerOptions = {}) {\n const {\n element,\n content,\n plainTextMode = false,\n markdownMode = false,\n extensions = [],\n onPlainTextChange,\n onMarkdownChange,\n onTokensChange,\n onSelectionChange,\n ...editorOptions\n } = options;\n\n this.plainTextMode = plainTextMode;\n this.markdownMode = markdownMode;\n this.onPlainTextChange = onPlainTextChange;\n this.onMarkdownChange = onMarkdownChange;\n this.onTokensChange = onTokensChange;\n this.onSelectionChange = onSelectionChange;\n\n const initialContent =\n plainTextMode && typeof content === \"string\"\n ? plainTextToTipTapHtml(content)\n : markdownMode && typeof content === \"string\"\n ? markdownToTipTapHtml(content)\n : content;\n\n this.editor = new Editor({\n element: element || undefined,\n content: initialContent,\n extensions,\n ...editorOptions,\n onUpdate: (props) => {\n editorOptions.onUpdate?.(props);\n this.handleUpdate();\n },\n onSelectionUpdate: (props) => {\n editorOptions.onSelectionUpdate?.(props);\n this.handleSelectionUpdate();\n },\n });\n\n if (plainTextMode) {\n this.enforcePlainTextClipboard();\n }\n\n this.baselineContent = this.getCurrentContentString();\n }\n\n private enforcePlainTextClipboard() {\n this.editor.setOptions({\n editorProps: {\n ...this.editor.options.editorProps,\n clipboardTextParser: (\n text: string,\n context: any,\n _plain: boolean,\n view?: any,\n ) => {\n const schema =\n context?.doc?.type?.schema ||\n context?.schema ||\n view?.state?.schema ||\n this.editor.schema;\n\n if (!schema) return Slice.empty;\n\n return plainTextToSlice(text, schema);\n },\n },\n });\n }\n\n private handleUpdate() {\n if (this.plainTextMode || this.onPlainTextChange || this.onTokensChange) {\n const text = this.getPlainText();\n this.onPlainTextChange?.(text);\n\n if (this.onTokensChange) {\n const tokens = tokenizePrompt(text);\n this.onTokensChange(tokens);\n }\n }\n\n if (this.markdownMode || this.onMarkdownChange) {\n const markdown = this.getMarkdown();\n this.onMarkdownChange?.(markdown);\n }\n }\n\n private handleSelectionUpdate() {\n if (this.onSelectionChange) {\n const { from, to } = this.editor.state.selection;\n this.onSelectionChange({ from, to });\n }\n }\n\n public getPlainText(): string {\n return getEditorText(this.editor);\n }\n\n public setPlainText(text: string, emitUpdate = true) {\n const html = plainTextToTipTapHtml(text);\n this.editor.commands.setContent(html, emitUpdate);\n }\n\n public getMarkdown(): string {\n return getEditorMarkdown(this.editor);\n }\n\n public setMarkdown(markdown: string, emitUpdate = true) {\n if (this.editor.storage?.markdown?.parser) {\n this.editor.commands.setContent(markdown, emitUpdate);\n } else {\n const html = markdownToTipTapHtml(markdown);\n this.editor.commands.setContent(html, emitUpdate);\n }\n }\n\n /**\n * Replaces `from`..`to` with literal text: HTML in `text` is not parsed, and\n * newlines split paragraphs.\n */\n private insertPlainText(from: number, to: number, text: string) {\n const { state, view } = this.editor;\n const tr = text.includes(\"\\n\") || text.includes(\"\\r\")\n ? state.tr.replace(from, to, plainTextToSlice(text, state.schema))\n : text\n ? state.tr.insertText(text, from, to)\n : state.tr.delete(from, to);\n view.dispatch(tr.scrollIntoView());\n }\n\n /** Inserts text literally at the selection; HTML in `text` is not parsed. */\n public insertText(text: string) {\n const { from, to } = this.editor.state.selection;\n this.insertPlainText(from, to, text);\n }\n\n /** Inserts text literally at `pos`; HTML in `text` is not parsed. */\n public insertTextAt(pos: number, text: string) {\n this.insertPlainText(pos, pos, text);\n this.editor.commands.focus();\n }\n\n /** Replaces a range with literal text; HTML in `text` is not parsed. */\n public replaceRange(from: number, to: number, text: string) {\n this.insertPlainText(from, to, text);\n this.editor.commands.focus();\n }\n\n public getCurrentContentString(): string {\n if (this.plainTextMode) return this.getPlainText();\n if (this.markdownMode) return this.getMarkdown();\n return this.editor.getHTML();\n }\n\n public isDirty(): boolean {\n return this.getCurrentContentString() !== this.baselineContent;\n }\n\n public setCheckpoint(content?: string): void {\n this.baselineContent =\n content !== undefined ? content : this.getCurrentContentString();\n }\n\n public resetDirty(): void {\n this.setCheckpoint();\n }\n\n public getBaselineContent(): string {\n return this.baselineContent;\n }\n\n public destroy() {\n this.editor.destroy();\n }\n}\n\n/**\n * Creates and initializes an EditorController instance.\n */\nexport function createEditor(\n options: EditorControllerOptions = {},\n): EditorController {\n return new EditorController(options);\n}\n","/**\n * Compares two values for structural equality.\n * Handles primitives, objects, arrays, and null/undefined.\n */\nexport function defaultIsEqual<T>(a: T, b: T): boolean {\n if (Object.is(a, b)) return true;\n if (\n typeof a !== \"object\" ||\n a === null ||\n typeof b !== \"object\" ||\n b === null\n ) {\n return false;\n }\n\n // Fast path for arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!defaultIsEqual(a[i], b[i])) return false;\n }\n return true;\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n\n const keysA = Object.keys(a) as (keyof T)[];\n const keysB = Object.keys(b) as (keyof T)[];\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false;\n if (!defaultIsEqual(a[key], b[key])) return false;\n }\n\n return true;\n}\n\nexport interface DirtyTrackerOptions<T> {\n isEqual?: (a: T, b: T) => boolean;\n}\n\n/**\n * Tracks a baseline value and determines if the current state is dirty (modified).\n */\nexport class DirtyTracker<T = unknown> {\n private baseline: T;\n private readonly isEqual: (a: T, b: T) => boolean;\n\n constructor(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n ) {\n this.baseline = initialBaseline;\n if (typeof options === \"function\") {\n this.isEqual = options;\n } else {\n this.isEqual = options?.isEqual ?? defaultIsEqual;\n }\n }\n\n /**\n * Returns current baseline value.\n */\n public getBaseline(): T {\n return this.baseline;\n }\n\n /**\n * Sets a new baseline value without triggering any dirty state.\n */\n public setBaseline(value: T): void {\n this.baseline = value;\n }\n\n /**\n * Checks whether the given value differs from the baseline.\n */\n public isDirty(current: T): boolean {\n return !this.isEqual(this.baseline, current);\n }\n\n /**\n * Resets the baseline to the provided current value (or clears dirty status).\n */\n public reset(current: T): void {\n this.baseline = current;\n }\n}\n\n/**\n * Creates a DirtyTracker instance.\n */\nexport function createDirtyTracker<T>(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n): DirtyTracker<T> {\n return new DirtyTracker(initialBaseline, options);\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/index.cjs","../src/controller.ts","../src/dirty.ts"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACF,wDAA6B;AAC7B;AACA;ACpFA,oCAA2D;AAC3D,yCAAsB;AA4Bf,IAAM,iBAAA,EAAN,MAAuB;AAAA,EACZ;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGT;AAAA,EAER,WAAA,CAAY,QAAA,EAAmC,CAAC,CAAA,EAAG;AACjD,IAAA,MAAM;AAAA,MACJ,OAAA;AAAA,MACA,OAAA;AAAA,MACA,cAAA,EAAgB,KAAA;AAAA,MAChB,aAAA,EAAe,KAAA;AAAA,MACf,WAAA,EAAa,CAAC,CAAA;AAAA,MACd,iBAAA;AAAA,MACA,gBAAA;AAAA,MACA,cAAA;AAAA,MACA,iBAAA;AAAA,MACA,GAAG;AAAA,IACL,EAAA,EAAI,OAAA;AAEJ,IAAA,IAAA,CAAK,cAAA,EAAgB,aAAA;AACrB,IAAA,IAAA,CAAK,aAAA,EAAe,YAAA;AACpB,IAAA,IAAA,CAAK,kBAAA,EAAoB,iBAAA;AACzB,IAAA,IAAA,CAAK,iBAAA,EAAmB,gBAAA;AACxB,IAAA,IAAA,CAAK,eAAA,EAAiB,cAAA;AACtB,IAAA,IAAA,CAAK,kBAAA,EAAoB,iBAAA;AAEzB,IAAA,MAAM,eAAA,EACJ,cAAA,GAAiB,OAAO,QAAA,IAAY,SAAA,EAChC,qDAAA,OAA6B,EAAA,EAC7B,aAAA,GAAgB,OAAO,QAAA,IAAY,SAAA,EACjC,oDAAA,OAA4B,EAAA,EAC5B,OAAA;AAER,IAAA,IAAA,CAAK,OAAA,EAAS,IAAI,iBAAA,CAAO;AAAA,MACvB,OAAA,EAAS,QAAA,GAAW,KAAA,CAAA;AAAA,MACpB,OAAA,EAAS,cAAA;AAAA,MACT,UAAA;AAAA,MACA,GAAG,aAAA;AAAA,MACH,QAAA,EAAU,CAAC,KAAA,EAAA,GAAU;AACnB,wBAAA,aAAA,mBAAc,QAAA,0BAAA,CAAW,KAAK,GAAA;AAC9B,QAAA,IAAA,CAAK,YAAA,CAAa,CAAA;AAAA,MACpB,CAAA;AAAA,MACA,iBAAA,EAAmB,CAAC,KAAA,EAAA,GAAU;AAC5B,wBAAA,aAAA,qBAAc,iBAAA,0BAAA,CAAoB,KAAK,GAAA;AACvC,QAAA,IAAA,CAAK,qBAAA,CAAsB,CAAA;AAAA,MAC7B;AAAA,IACF,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,aAAA,EAAe;AACjB,MAAA,IAAA,CAAK,yBAAA,CAA0B,CAAA;AAAA,IACjC;AAEA,IAAA,IAAA,CAAK,gBAAA,EAAkB,IAAA,CAAK,uBAAA,CAAwB,CAAA;AAAA,EACtD;AAAA,EAEQ,yBAAA,CAAA,EAA4B;AAClC,IAAA,IAAA,CAAK,MAAA,CAAO,UAAA,CAAW;AAAA,MACrB,WAAA,EAAa;AAAA,QACX,GAAG,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,WAAA;AAAA,QACvB,mBAAA,EAAqB,CACnB,IAAA,EACA,OAAA,EACA,MAAA,EACA,IAAA,EAAA,GACG;AACH,UAAA,MAAM,OAAA,kBACJ,OAAA,6BAAS,GAAA,6BAAK,IAAA,6BAAM,SAAA,mBACpB,OAAA,6BAAS,SAAA,mBACT,IAAA,6BAAM,KAAA,+BAAO,SAAA,GACb,IAAA,CAAK,MAAA,CAAO,MAAA;AAEd,UAAA,GAAA,CAAI,CAAC,MAAA,EAAQ,OAAO,YAAA,CAAM,KAAA;AAE1B,UAAA,OAAO,gDAAA,IAAiB,EAAM,MAAM,CAAA;AAAA,QACtC;AAAA,MACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA,EAEQ,YAAA,CAAA,EAAe;AACrB,IAAA,GAAA,CAAI,IAAA,CAAK,cAAA,GAAiB,IAAA,CAAK,kBAAA,GAAqB,IAAA,CAAK,cAAA,EAAgB;AACvE,MAAA,MAAM,KAAA,EAAO,IAAA,CAAK,YAAA,CAAa,CAAA;AAC/B,sBAAA,IAAA,uBAAK,iBAAA,4BAAA,CAAoB,IAAI,GAAA;AAE7B,MAAA,GAAA,CAAI,IAAA,CAAK,cAAA,EAAgB;AACvB,QAAA,MAAM,OAAA,EAAS,8CAAA,IAAmB,CAAA;AAClC,QAAA,IAAA,CAAK,cAAA,CAAe,MAAM,CAAA;AAAA,MAC5B;AAAA,IACF;AAEA,IAAA,GAAA,CAAI,IAAA,CAAK,aAAA,GAAgB,IAAA,CAAK,gBAAA,EAAkB;AAC9C,MAAA,MAAM,SAAA,EAAW,IAAA,CAAK,WAAA,CAAY,CAAA;AAClC,sBAAA,IAAA,uBAAK,gBAAA,4BAAA,CAAmB,QAAQ,GAAA;AAAA,IAClC;AAAA,EACF;AAAA,EAEQ,qBAAA,CAAA,EAAwB;AAC9B,IAAA,GAAA,CAAI,IAAA,CAAK,iBAAA,EAAmB;AAC1B,MAAA,MAAM,EAAE,IAAA,EAAM,GAAG,EAAA,EAAI,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,SAAA;AACvC,MAAA,IAAA,CAAK,iBAAA,CAAkB,EAAE,IAAA,EAAM,GAAG,CAAC,CAAA;AAAA,IACrC;AAAA,EACF;AAAA,EAEO,YAAA,CAAA,EAAuB;AAC5B,IAAA,OAAO,6CAAA,IAAc,CAAK,MAAM,CAAA;AAAA,EAClC;AAAA,EAEO,YAAA,CAAa,IAAA,EAAc,WAAA,EAAa,IAAA,EAAM;AACnD,IAAA,MAAM,KAAA,EAAO,qDAAA,IAA0B,CAAA;AACvC,IAAA,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,UAAA,CAAW,IAAA,EAAM,UAAU,CAAA;AAAA,EAClD;AAAA,EAEO,WAAA,CAAA,EAAsB;AAC3B,IAAA,OAAO,iDAAA,IAAkB,CAAK,MAAM,CAAA;AAAA,EACtC;AAAA,EAEO,WAAA,CAAY,QAAA,EAAkB,WAAA,EAAa,IAAA,EAAM;AACtD,IAAA,GAAA,iBAAI,IAAA,uBAAK,MAAA,uBAAO,OAAA,+BAAS,QAAA,+BAAU,QAAA,EAAQ;AACzC,MAAA,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,UAAA,CAAW,QAAA,EAAU,UAAU,CAAA;AAAA,IACtD,EAAA,KAAO;AACL,MAAA,MAAM,KAAA,EAAO,oDAAA,QAA6B,CAAA;AAC1C,MAAA,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,UAAA,CAAW,IAAA,EAAM,UAAU,CAAA;AAAA,IAClD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAA,CAAgB,IAAA,EAAc,EAAA,EAAY,IAAA,EAAc;AAC9D,IAAA,MAAM,EAAE,KAAA,EAAO,KAAK,EAAA,EAAI,IAAA,CAAK,MAAA;AAC7B,IAAA,MAAM,GAAA,EAAK,IAAA,CAAK,QAAA,CAAS,IAAI,EAAA,GAAK,IAAA,CAAK,QAAA,CAAS,IAAI,EAAA,EAChD,KAAA,CAAM,EAAA,CAAG,OAAA,CAAQ,IAAA,EAAM,EAAA,EAAI,gDAAA,IAAiB,EAAM,KAAA,CAAM,MAAM,CAAC,EAAA,EAC/D,KAAA,EACE,KAAA,CAAM,EAAA,CAAG,UAAA,CAAW,IAAA,EAAM,IAAA,EAAM,EAAE,EAAA,EAClC,KAAA,CAAM,EAAA,CAAG,MAAA,CAAO,IAAA,EAAM,EAAE,CAAA;AAC9B,IAAA,IAAA,CAAK,QAAA,CAAS,EAAA,CAAG,cAAA,CAAe,CAAC,CAAA;AAAA,EACnC;AAAA;AAAA,EAGO,UAAA,CAAW,IAAA,EAAc;AAC9B,IAAA,MAAM,EAAE,IAAA,EAAM,GAAG,EAAA,EAAI,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,SAAA;AACvC,IAAA,IAAA,CAAK,eAAA,CAAgB,IAAA,EAAM,EAAA,EAAI,IAAI,CAAA;AAAA,EACrC;AAAA;AAAA,EAGO,YAAA,CAAa,GAAA,EAAa,IAAA,EAAc;AAC7C,IAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,EAAK,GAAA,EAAK,IAAI,CAAA;AACnC,IAAA,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,KAAA,CAAM,CAAA;AAAA,EAC7B;AAAA;AAAA,EAGO,YAAA,CAAa,IAAA,EAAc,EAAA,EAAY,IAAA,EAAc;AAC1D,IAAA,IAAA,CAAK,eAAA,CAAgB,IAAA,EAAM,EAAA,EAAI,IAAI,CAAA;AACnC,IAAA,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,KAAA,CAAM,CAAA;AAAA,EAC7B;AAAA,EAEO,uBAAA,CAAA,EAAkC;AACvC,IAAA,GAAA,CAAI,IAAA,CAAK,aAAA,EAAe,OAAO,IAAA,CAAK,YAAA,CAAa,CAAA;AACjD,IAAA,GAAA,CAAI,IAAA,CAAK,YAAA,EAAc,OAAO,IAAA,CAAK,WAAA,CAAY,CAAA;AAC/C,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,CAAA;AAAA,EAC7B;AAAA,EAEO,OAAA,CAAA,EAAmB;AACxB,IAAA,OAAO,IAAA,CAAK,uBAAA,CAAwB,EAAA,IAAM,IAAA,CAAK,eAAA;AAAA,EACjD;AAAA,EAEO,aAAA,CAAc,OAAA,EAAwB;AAC3C,IAAA,IAAA,CAAK,gBAAA,EACH,QAAA,IAAY,KAAA,EAAA,EAAY,QAAA,EAAU,IAAA,CAAK,uBAAA,CAAwB,CAAA;AAAA,EACnE;AAAA,EAEO,UAAA,CAAA,EAAmB;AACxB,IAAA,IAAA,CAAK,aAAA,CAAc,CAAA;AAAA,EACrB;AAAA,EAEO,kBAAA,CAAA,EAA6B;AAClC,IAAA,OAAO,IAAA,CAAK,eAAA;AAAA,EACd;AAAA,EAEO,OAAA,CAAA,EAAU;AACf,IAAA,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,CAAA;AAAA,EACtB;AACF,CAAA;AAKO,SAAS,YAAA,CACd,QAAA,EAAmC,CAAC,CAAA,EAClB;AAClB,EAAA,OAAO,IAAI,gBAAA,CAAiB,OAAO,CAAA;AACrC;ADKA;AACA;AEtOO,SAAS,cAAA,CAAkB,CAAA,EAAM,CAAA,EAAe;AACrD,EAAA,GAAA,CAAI,MAAA,CAAO,EAAA,CAAG,CAAA,EAAG,CAAC,CAAA,EAAG,OAAO,IAAA;AAC5B,EAAA,GAAA,CACE,OAAO,EAAA,IAAM,SAAA,GACb,EAAA,IAAM,KAAA,GACN,OAAO,EAAA,IAAM,SAAA,GACb,EAAA,IAAM,IAAA,EACN;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAGA,EAAA,GAAA,CAAI,KAAA,CAAM,OAAA,CAAQ,CAAC,EAAA,GAAK,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG;AACxC,IAAA,GAAA,CAAI,CAAA,CAAE,OAAA,IAAW,CAAA,CAAE,MAAA,EAAQ,OAAO,KAAA;AAClC,IAAA,IAAA,CAAA,IAAS,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,CAAA,CAAE,MAAA,EAAQ,CAAA,EAAA,EAAK;AACjC,MAAA,GAAA,CAAI,CAAC,cAAA,CAAe,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAC,CAAA,EAAG,OAAO,KAAA;AAAA,IAC1C;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,GAAA,CAAI,KAAA,CAAM,OAAA,CAAQ,CAAC,EAAA,IAAM,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG;AACzC,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,MAAA,EAAQ,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA;AAC3B,EAAA,MAAM,MAAA,EAAQ,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA;AAE3B,EAAA,GAAA,CAAI,KAAA,CAAM,OAAA,IAAW,KAAA,CAAM,MAAA,EAAQ,OAAO,KAAA;AAE1C,EAAA,IAAA,CAAA,MAAW,IAAA,GAAO,KAAA,EAAO;AACvB,IAAA,GAAA,CAAI,CAAC,MAAA,CAAO,SAAA,CAAU,cAAA,CAAe,IAAA,CAAK,CAAA,EAAG,GAAG,CAAA,EAAG,OAAO,KAAA;AAC1D,IAAA,GAAA,CAAI,CAAC,cAAA,CAAe,CAAA,CAAE,GAAG,CAAA,EAAG,CAAA,CAAE,GAAG,CAAC,CAAA,EAAG,OAAO,KAAA;AAAA,EAC9C;AAEA,EAAA,OAAO,IAAA;AACT;AASO,IAAM,aAAA,EAAN,MAAgC;AAAA,EAC7B;AAAA,EACS;AAAA,EAEjB,WAAA,CACE,eAAA,EACA,OAAA,EACA;AACA,IAAA,IAAA,CAAK,SAAA,EAAW,eAAA;AAChB,IAAA,GAAA,CAAI,OAAO,QAAA,IAAY,UAAA,EAAY;AACjC,MAAA,IAAA,CAAK,QAAA,EAAU,OAAA;AAAA,IACjB,EAAA,KAAO;AACL,MAAA,IAAA,CAAK,QAAA,mCAAU,OAAA,+BAAS,SAAA,UAAW,gBAAA;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKO,WAAA,CAAA,EAAiB;AACtB,IAAA,OAAO,IAAA,CAAK,QAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,WAAA,CAAY,KAAA,EAAgB;AACjC,IAAA,IAAA,CAAK,SAAA,EAAW,KAAA;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKO,OAAA,CAAQ,OAAA,EAAqB;AAClC,IAAA,OAAO,CAAC,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,QAAA,EAAU,OAAO,CAAA;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKO,KAAA,CAAM,OAAA,EAAkB;AAC7B,IAAA,IAAA,CAAK,SAAA,EAAW,OAAA;AAAA,EAClB;AACF,CAAA;AAKO,SAAS,kBAAA,CACd,eAAA,EACA,OAAA,EACiB;AACjB,EAAA,OAAO,IAAI,YAAA,CAAa,eAAA,EAAiB,OAAO,CAAA;AAClD;AFsMA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,6pJAAC","file":"/home/runner/work/editor/editor/packages/core/dist/index.cjs","sourcesContent":[null,"import { Editor, EditorOptions, Content, Extensions } from \"@tiptap/core\";\nimport { Slice } from \"@tiptap/pm/model\";\nimport { Token, tokenizePrompt } from \"./grammar\";\nimport {\n plainTextToTipTapHtml,\n plainTextToSlice,\n getEditorText,\n markdownToTipTapHtml,\n getEditorMarkdown,\n} from \"./serializers\";\n\nexport interface EditorControllerOptions extends Partial<\n Omit<EditorOptions, \"element\" | \"content\">\n> {\n element?: Element | HTMLElement | null;\n content?: string | Content;\n plainTextMode?: boolean;\n markdownMode?: boolean;\n extensions?: Extensions;\n onPlainTextChange?: (text: string) => void;\n onMarkdownChange?: (markdown: string) => void;\n onTokensChange?: (tokens: Token[]) => void;\n onSelectionChange?: (range: { from: number; to: number } | null) => void;\n}\n\n/**\n * UI-agnostic controller managing the lifecycle, commands, and plain-text/token\n * synchronization of a rich text or prompt editor.\n */\nexport class EditorController {\n public readonly editor: Editor;\n private readonly plainTextMode: boolean;\n private readonly markdownMode: boolean;\n private readonly onPlainTextChange?: (text: string) => void;\n private readonly onMarkdownChange?: (markdown: string) => void;\n private readonly onTokensChange?: (tokens: Token[]) => void;\n private readonly onSelectionChange?: (\n range: { from: number; to: number } | null,\n ) => void;\n private baselineContent: string;\n\n constructor(options: EditorControllerOptions = {}) {\n const {\n element,\n content,\n plainTextMode = false,\n markdownMode = false,\n extensions = [],\n onPlainTextChange,\n onMarkdownChange,\n onTokensChange,\n onSelectionChange,\n ...editorOptions\n } = options;\n\n this.plainTextMode = plainTextMode;\n this.markdownMode = markdownMode;\n this.onPlainTextChange = onPlainTextChange;\n this.onMarkdownChange = onMarkdownChange;\n this.onTokensChange = onTokensChange;\n this.onSelectionChange = onSelectionChange;\n\n const initialContent =\n plainTextMode && typeof content === \"string\"\n ? plainTextToTipTapHtml(content)\n : markdownMode && typeof content === \"string\"\n ? markdownToTipTapHtml(content)\n : content;\n\n this.editor = new Editor({\n element: element || undefined,\n content: initialContent,\n extensions,\n ...editorOptions,\n onUpdate: (props) => {\n editorOptions.onUpdate?.(props);\n this.handleUpdate();\n },\n onSelectionUpdate: (props) => {\n editorOptions.onSelectionUpdate?.(props);\n this.handleSelectionUpdate();\n },\n });\n\n if (plainTextMode) {\n this.enforcePlainTextClipboard();\n }\n\n this.baselineContent = this.getCurrentContentString();\n }\n\n private enforcePlainTextClipboard() {\n this.editor.setOptions({\n editorProps: {\n ...this.editor.options.editorProps,\n clipboardTextParser: (\n text: string,\n context: any,\n _plain: boolean,\n view?: any,\n ) => {\n const schema =\n context?.doc?.type?.schema ||\n context?.schema ||\n view?.state?.schema ||\n this.editor.schema;\n\n if (!schema) return Slice.empty;\n\n return plainTextToSlice(text, schema);\n },\n },\n });\n }\n\n private handleUpdate() {\n if (this.plainTextMode || this.onPlainTextChange || this.onTokensChange) {\n const text = this.getPlainText();\n this.onPlainTextChange?.(text);\n\n if (this.onTokensChange) {\n const tokens = tokenizePrompt(text);\n this.onTokensChange(tokens);\n }\n }\n\n if (this.markdownMode || this.onMarkdownChange) {\n const markdown = this.getMarkdown();\n this.onMarkdownChange?.(markdown);\n }\n }\n\n private handleSelectionUpdate() {\n if (this.onSelectionChange) {\n const { from, to } = this.editor.state.selection;\n this.onSelectionChange({ from, to });\n }\n }\n\n public getPlainText(): string {\n return getEditorText(this.editor);\n }\n\n public setPlainText(text: string, emitUpdate = true) {\n const html = plainTextToTipTapHtml(text);\n this.editor.commands.setContent(html, emitUpdate);\n }\n\n public getMarkdown(): string {\n return getEditorMarkdown(this.editor);\n }\n\n public setMarkdown(markdown: string, emitUpdate = true) {\n if (this.editor.storage?.markdown?.parser) {\n this.editor.commands.setContent(markdown, emitUpdate);\n } else {\n const html = markdownToTipTapHtml(markdown);\n this.editor.commands.setContent(html, emitUpdate);\n }\n }\n\n /**\n * Replaces `from`..`to` with literal text: HTML in `text` is not parsed, and\n * newlines split paragraphs.\n */\n private insertPlainText(from: number, to: number, text: string) {\n const { state, view } = this.editor;\n const tr = text.includes(\"\\n\") || text.includes(\"\\r\")\n ? state.tr.replace(from, to, plainTextToSlice(text, state.schema))\n : text\n ? state.tr.insertText(text, from, to)\n : state.tr.delete(from, to);\n view.dispatch(tr.scrollIntoView());\n }\n\n /** Inserts text literally at the selection; HTML in `text` is not parsed. */\n public insertText(text: string) {\n const { from, to } = this.editor.state.selection;\n this.insertPlainText(from, to, text);\n }\n\n /** Inserts text literally at `pos`; HTML in `text` is not parsed. */\n public insertTextAt(pos: number, text: string) {\n this.insertPlainText(pos, pos, text);\n this.editor.commands.focus();\n }\n\n /** Replaces a range with literal text; HTML in `text` is not parsed. */\n public replaceRange(from: number, to: number, text: string) {\n this.insertPlainText(from, to, text);\n this.editor.commands.focus();\n }\n\n public getCurrentContentString(): string {\n if (this.plainTextMode) return this.getPlainText();\n if (this.markdownMode) return this.getMarkdown();\n return this.editor.getHTML();\n }\n\n public isDirty(): boolean {\n return this.getCurrentContentString() !== this.baselineContent;\n }\n\n public setCheckpoint(content?: string): void {\n this.baselineContent =\n content !== undefined ? content : this.getCurrentContentString();\n }\n\n public resetDirty(): void {\n this.setCheckpoint();\n }\n\n public getBaselineContent(): string {\n return this.baselineContent;\n }\n\n public destroy() {\n this.editor.destroy();\n }\n}\n\n/**\n * Creates and initializes an EditorController instance.\n */\nexport function createEditor(\n options: EditorControllerOptions = {},\n): EditorController {\n return new EditorController(options);\n}\n","/**\n * Compares two values for structural equality.\n * Handles primitives, objects, arrays, and null/undefined.\n */\nexport function defaultIsEqual<T>(a: T, b: T): boolean {\n if (Object.is(a, b)) return true;\n if (\n typeof a !== \"object\" ||\n a === null ||\n typeof b !== \"object\" ||\n b === null\n ) {\n return false;\n }\n\n // Fast path for arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!defaultIsEqual(a[i], b[i])) return false;\n }\n return true;\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n\n const keysA = Object.keys(a) as (keyof T)[];\n const keysB = Object.keys(b) as (keyof T)[];\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false;\n if (!defaultIsEqual(a[key], b[key])) return false;\n }\n\n return true;\n}\n\nexport interface DirtyTrackerOptions<T> {\n isEqual?: (a: T, b: T) => boolean;\n}\n\n/**\n * Tracks a baseline value and determines if the current state is dirty (modified).\n */\nexport class DirtyTracker<T = unknown> {\n private baseline: T;\n private readonly isEqual: (a: T, b: T) => boolean;\n\n constructor(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n ) {\n this.baseline = initialBaseline;\n if (typeof options === \"function\") {\n this.isEqual = options;\n } else {\n this.isEqual = options?.isEqual ?? defaultIsEqual;\n }\n }\n\n /**\n * Returns current baseline value.\n */\n public getBaseline(): T {\n return this.baseline;\n }\n\n /**\n * Sets a new baseline value without triggering any dirty state.\n */\n public setBaseline(value: T): void {\n this.baseline = value;\n }\n\n /**\n * Checks whether the given value differs from the baseline.\n */\n public isDirty(current: T): boolean {\n return !this.isEqual(this.baseline, current);\n }\n\n /**\n * Resets the baseline to the provided current value (or clears dirty status).\n */\n public reset(current: T): void {\n this.baseline = current;\n }\n}\n\n/**\n * Creates a DirtyTracker instance.\n */\nexport function createDirtyTracker<T>(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n): DirtyTracker<T> {\n return new DirtyTracker(initialBaseline, options);\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -6,7 +6,7 @@ export { M as Mention, a as MentionEntity, b as MentionOptions, c as createMenti
6
6
  export { ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, MarkdownToHtmlOptions, MentionSegment, PreprocessMarkdownMentionsOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, plainTextToSlice, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, stripMarkdownCode } from './serializers/index.cjs';
7
7
  import { Editor, EditorOptions, Content, Extensions } from '@tiptap/core';
8
8
  export { Content, Editor, EditorOptions, Extensions } from '@tiptap/core';
9
- export { ASTNode, BinaryOpNode, CellCoordinate, CellData, CellDep, CellFormat, CellRange, CellRefNode, ColumnBinding, ColumnType, DataSourceBinder, DependencyGraph, EvaluationContext, FormulaEvaluator, FormulaParser, FormulaToken, FormulaTokenType, FunctionCallNode, LiteralNode, PropertyRefNode, RangeNode, RowType, SpreadsheetColumn, SpreadsheetController, SpreadsheetControllerOptions, SpreadsheetDataSource, SpreadsheetDataSourceField, SpreadsheetDocument, SpreadsheetRow, UnaryOpNode, colNameToIndex, extractCellDependencies, indexToColName, parseCellReference, parseFormula, parseRange, tokenizeFormula } from './spreadsheet/index.cjs';
9
+ export { ASTNode, BinaryOpNode, CellCoordinate, CellData, CellDep, CellFormat, CellRange, CellRefNode, ColumnBinding, ColumnType, DataSourceBinder, DependencyGraph, EvaluationContext, FORMULA_ERRORS, FormulaEvaluator, FormulaParser, FormulaToken, FormulaTokenType, FunctionCallNode, LiteralNode, PropertyRefNode, RangeNode, RowType, SpreadsheetColumn, SpreadsheetController, SpreadsheetControllerOptions, SpreadsheetDataSource, SpreadsheetDataSourceField, SpreadsheetDocument, SpreadsheetRow, StructuralChange, UnaryOpNode, WHOLE_COLUMN_END_ROW, colNameToIndex, columnDependencyKey, extractCellDependencies, indexToColName, isFormulaError, parseCellReference, parseFormula, parseRange, shiftFormulaReferences, tokenizeFormula } from './spreadsheet/index.cjs';
10
10
  export { Command, HistoryManager, HistoryManagerOptions, HistoryState, MergedExecutionOptions, SnapshotCommandOptions, createHistoryManager } from './history/index.cjs';
11
11
  export { MarkdownOptions } from 'tiptap-markdown';
12
12
  import '@tiptap/pm/view';
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ export { M as Mention, a as MentionEntity, b as MentionOptions, c as createMenti
6
6
  export { ExtractedMention, MARKDOWN_MENTION_SPLIT_REGEX, MENTION_REGEX, MarkdownToHtmlOptions, MentionSegment, PreprocessMarkdownMentionsOptions, escapeHtml, extractMentions, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, parseMentionSegments, plainTextToSlice, plainTextToTipTapHtml, preprocessMarkdownFileLinks, preprocessMarkdownMentions, stripMarkdownCode } from './serializers/index.js';
7
7
  import { Editor, EditorOptions, Content, Extensions } from '@tiptap/core';
8
8
  export { Content, Editor, EditorOptions, Extensions } from '@tiptap/core';
9
- export { ASTNode, BinaryOpNode, CellCoordinate, CellData, CellDep, CellFormat, CellRange, CellRefNode, ColumnBinding, ColumnType, DataSourceBinder, DependencyGraph, EvaluationContext, FormulaEvaluator, FormulaParser, FormulaToken, FormulaTokenType, FunctionCallNode, LiteralNode, PropertyRefNode, RangeNode, RowType, SpreadsheetColumn, SpreadsheetController, SpreadsheetControllerOptions, SpreadsheetDataSource, SpreadsheetDataSourceField, SpreadsheetDocument, SpreadsheetRow, UnaryOpNode, colNameToIndex, extractCellDependencies, indexToColName, parseCellReference, parseFormula, parseRange, tokenizeFormula } from './spreadsheet/index.js';
9
+ export { ASTNode, BinaryOpNode, CellCoordinate, CellData, CellDep, CellFormat, CellRange, CellRefNode, ColumnBinding, ColumnType, DataSourceBinder, DependencyGraph, EvaluationContext, FORMULA_ERRORS, FormulaEvaluator, FormulaParser, FormulaToken, FormulaTokenType, FunctionCallNode, LiteralNode, PropertyRefNode, RangeNode, RowType, SpreadsheetColumn, SpreadsheetController, SpreadsheetControllerOptions, SpreadsheetDataSource, SpreadsheetDataSourceField, SpreadsheetDocument, SpreadsheetRow, StructuralChange, UnaryOpNode, WHOLE_COLUMN_END_ROW, colNameToIndex, columnDependencyKey, extractCellDependencies, indexToColName, isFormulaError, parseCellReference, parseFormula, parseRange, shiftFormulaReferences, tokenizeFormula } from './spreadsheet/index.js';
10
10
  export { Command, HistoryManager, HistoryManagerOptions, HistoryState, MergedExecutionOptions, SnapshotCommandOptions, createHistoryManager } from './history/index.js';
11
11
  export { MarkdownOptions } from 'tiptap-markdown';
12
12
  import '@tiptap/pm/view';
package/dist/index.js CHANGED
@@ -61,17 +61,22 @@ import {
61
61
  import {
62
62
  DataSourceBinder,
63
63
  DependencyGraph,
64
+ FORMULA_ERRORS,
64
65
  FormulaEvaluator,
65
66
  FormulaParser,
66
67
  SpreadsheetController,
68
+ WHOLE_COLUMN_END_ROW,
67
69
  colNameToIndex,
70
+ columnDependencyKey,
68
71
  extractCellDependencies,
69
72
  indexToColName,
73
+ isFormulaError,
70
74
  parseCellReference,
71
75
  parseFormula,
72
76
  parseRange,
77
+ shiftFormulaReferences,
73
78
  tokenizeFormula
74
- } from "./chunk-NNJRJJSC.js";
79
+ } from "./chunk-AIZUKWTL.js";
75
80
  import {
76
81
  HistoryManager,
77
82
  createHistoryManager
@@ -297,6 +302,7 @@ export {
297
302
  DependencyGraph,
298
303
  DirtyTracker,
299
304
  EditorController,
305
+ FORMULA_ERRORS,
300
306
  FontSize,
301
307
  FormulaEvaluator,
302
308
  FormulaParser,
@@ -317,7 +323,9 @@ export {
317
323
  TEMPLATE_REGEX,
318
324
  TemplateSuggestions,
319
325
  VARIABLE_REGEX,
326
+ WHOLE_COLUMN_END_ROW,
320
327
  colNameToIndex,
328
+ columnDependencyKey,
321
329
  createDirtyTracker,
322
330
  createEditor,
323
331
  createHistoryManager,
@@ -342,6 +350,7 @@ export {
342
350
  indexToColName,
343
351
  insertImageNode,
344
352
  instructionRegex,
353
+ isFormulaError,
345
354
  mapRawOffsetToResolved,
346
355
  mapResolvedOffsetToRaw,
347
356
  markdownToTipTapHtml,
@@ -357,6 +366,7 @@ export {
357
366
  resolveTemplates,
358
367
  resolveTemplatesWithMapping,
359
368
  resolveVariables,
369
+ shiftFormulaReferences,
360
370
  stripMarkdownCode,
361
371
  templateRegex,
362
372
  tokenizeFormula,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/controller.ts","../src/dirty.ts"],"sourcesContent":["import { Editor, EditorOptions, Content, Extensions } from \"@tiptap/core\";\nimport { Slice } from \"@tiptap/pm/model\";\nimport { Token, tokenizePrompt } from \"./grammar\";\nimport {\n plainTextToTipTapHtml,\n plainTextToSlice,\n getEditorText,\n markdownToTipTapHtml,\n getEditorMarkdown,\n} from \"./serializers\";\n\nexport interface EditorControllerOptions extends Partial<\n Omit<EditorOptions, \"element\" | \"content\">\n> {\n element?: Element | HTMLElement | null;\n content?: string | Content;\n plainTextMode?: boolean;\n markdownMode?: boolean;\n extensions?: Extensions;\n onPlainTextChange?: (text: string) => void;\n onMarkdownChange?: (markdown: string) => void;\n onTokensChange?: (tokens: Token[]) => void;\n onSelectionChange?: (range: { from: number; to: number } | null) => void;\n}\n\n/**\n * UI-agnostic controller managing the lifecycle, commands, and plain-text/token\n * synchronization of a rich text or prompt editor.\n */\nexport class EditorController {\n public readonly editor: Editor;\n private readonly plainTextMode: boolean;\n private readonly markdownMode: boolean;\n private readonly onPlainTextChange?: (text: string) => void;\n private readonly onMarkdownChange?: (markdown: string) => void;\n private readonly onTokensChange?: (tokens: Token[]) => void;\n private readonly onSelectionChange?: (\n range: { from: number; to: number } | null,\n ) => void;\n private baselineContent: string;\n\n constructor(options: EditorControllerOptions = {}) {\n const {\n element,\n content,\n plainTextMode = false,\n markdownMode = false,\n extensions = [],\n onPlainTextChange,\n onMarkdownChange,\n onTokensChange,\n onSelectionChange,\n ...editorOptions\n } = options;\n\n this.plainTextMode = plainTextMode;\n this.markdownMode = markdownMode;\n this.onPlainTextChange = onPlainTextChange;\n this.onMarkdownChange = onMarkdownChange;\n this.onTokensChange = onTokensChange;\n this.onSelectionChange = onSelectionChange;\n\n const initialContent =\n plainTextMode && typeof content === \"string\"\n ? plainTextToTipTapHtml(content)\n : markdownMode && typeof content === \"string\"\n ? markdownToTipTapHtml(content)\n : content;\n\n this.editor = new Editor({\n element: element || undefined,\n content: initialContent,\n extensions,\n ...editorOptions,\n onUpdate: (props) => {\n editorOptions.onUpdate?.(props);\n this.handleUpdate();\n },\n onSelectionUpdate: (props) => {\n editorOptions.onSelectionUpdate?.(props);\n this.handleSelectionUpdate();\n },\n });\n\n if (plainTextMode) {\n this.enforcePlainTextClipboard();\n }\n\n this.baselineContent = this.getCurrentContentString();\n }\n\n private enforcePlainTextClipboard() {\n this.editor.setOptions({\n editorProps: {\n ...this.editor.options.editorProps,\n clipboardTextParser: (\n text: string,\n context: any,\n _plain: boolean,\n view?: any,\n ) => {\n const schema =\n context?.doc?.type?.schema ||\n context?.schema ||\n view?.state?.schema ||\n this.editor.schema;\n\n if (!schema) return Slice.empty;\n\n return plainTextToSlice(text, schema);\n },\n },\n });\n }\n\n private handleUpdate() {\n if (this.plainTextMode || this.onPlainTextChange || this.onTokensChange) {\n const text = this.getPlainText();\n this.onPlainTextChange?.(text);\n\n if (this.onTokensChange) {\n const tokens = tokenizePrompt(text);\n this.onTokensChange(tokens);\n }\n }\n\n if (this.markdownMode || this.onMarkdownChange) {\n const markdown = this.getMarkdown();\n this.onMarkdownChange?.(markdown);\n }\n }\n\n private handleSelectionUpdate() {\n if (this.onSelectionChange) {\n const { from, to } = this.editor.state.selection;\n this.onSelectionChange({ from, to });\n }\n }\n\n public getPlainText(): string {\n return getEditorText(this.editor);\n }\n\n public setPlainText(text: string, emitUpdate = true) {\n const html = plainTextToTipTapHtml(text);\n this.editor.commands.setContent(html, emitUpdate);\n }\n\n public getMarkdown(): string {\n return getEditorMarkdown(this.editor);\n }\n\n public setMarkdown(markdown: string, emitUpdate = true) {\n if (this.editor.storage?.markdown?.parser) {\n this.editor.commands.setContent(markdown, emitUpdate);\n } else {\n const html = markdownToTipTapHtml(markdown);\n this.editor.commands.setContent(html, emitUpdate);\n }\n }\n\n /**\n * Replaces `from`..`to` with literal text: HTML in `text` is not parsed, and\n * newlines split paragraphs.\n */\n private insertPlainText(from: number, to: number, text: string) {\n const { state, view } = this.editor;\n const tr = text.includes(\"\\n\") || text.includes(\"\\r\")\n ? state.tr.replace(from, to, plainTextToSlice(text, state.schema))\n : text\n ? state.tr.insertText(text, from, to)\n : state.tr.delete(from, to);\n view.dispatch(tr.scrollIntoView());\n }\n\n /** Inserts text literally at the selection; HTML in `text` is not parsed. */\n public insertText(text: string) {\n const { from, to } = this.editor.state.selection;\n this.insertPlainText(from, to, text);\n }\n\n /** Inserts text literally at `pos`; HTML in `text` is not parsed. */\n public insertTextAt(pos: number, text: string) {\n this.insertPlainText(pos, pos, text);\n this.editor.commands.focus();\n }\n\n /** Replaces a range with literal text; HTML in `text` is not parsed. */\n public replaceRange(from: number, to: number, text: string) {\n this.insertPlainText(from, to, text);\n this.editor.commands.focus();\n }\n\n public getCurrentContentString(): string {\n if (this.plainTextMode) return this.getPlainText();\n if (this.markdownMode) return this.getMarkdown();\n return this.editor.getHTML();\n }\n\n public isDirty(): boolean {\n return this.getCurrentContentString() !== this.baselineContent;\n }\n\n public setCheckpoint(content?: string): void {\n this.baselineContent =\n content !== undefined ? content : this.getCurrentContentString();\n }\n\n public resetDirty(): void {\n this.setCheckpoint();\n }\n\n public getBaselineContent(): string {\n return this.baselineContent;\n }\n\n public destroy() {\n this.editor.destroy();\n }\n}\n\n/**\n * Creates and initializes an EditorController instance.\n */\nexport function createEditor(\n options: EditorControllerOptions = {},\n): EditorController {\n return new EditorController(options);\n}\n","/**\n * Compares two values for structural equality.\n * Handles primitives, objects, arrays, and null/undefined.\n */\nexport function defaultIsEqual<T>(a: T, b: T): boolean {\n if (Object.is(a, b)) return true;\n if (\n typeof a !== \"object\" ||\n a === null ||\n typeof b !== \"object\" ||\n b === null\n ) {\n return false;\n }\n\n // Fast path for arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!defaultIsEqual(a[i], b[i])) return false;\n }\n return true;\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n\n const keysA = Object.keys(a) as (keyof T)[];\n const keysB = Object.keys(b) as (keyof T)[];\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false;\n if (!defaultIsEqual(a[key], b[key])) return false;\n }\n\n return true;\n}\n\nexport interface DirtyTrackerOptions<T> {\n isEqual?: (a: T, b: T) => boolean;\n}\n\n/**\n * Tracks a baseline value and determines if the current state is dirty (modified).\n */\nexport class DirtyTracker<T = unknown> {\n private baseline: T;\n private readonly isEqual: (a: T, b: T) => boolean;\n\n constructor(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n ) {\n this.baseline = initialBaseline;\n if (typeof options === \"function\") {\n this.isEqual = options;\n } else {\n this.isEqual = options?.isEqual ?? defaultIsEqual;\n }\n }\n\n /**\n * Returns current baseline value.\n */\n public getBaseline(): T {\n return this.baseline;\n }\n\n /**\n * Sets a new baseline value without triggering any dirty state.\n */\n public setBaseline(value: T): void {\n this.baseline = value;\n }\n\n /**\n * Checks whether the given value differs from the baseline.\n */\n public isDirty(current: T): boolean {\n return !this.isEqual(this.baseline, current);\n }\n\n /**\n * Resets the baseline to the provided current value (or clears dirty status).\n */\n public reset(current: T): void {\n this.baseline = current;\n }\n}\n\n/**\n * Creates a DirtyTracker instance.\n */\nexport function createDirtyTracker<T>(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n): DirtyTracker<T> {\n return new DirtyTracker(initialBaseline, options);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/controller.ts","../src/dirty.ts"],"sourcesContent":["import { Editor, EditorOptions, Content, Extensions } from \"@tiptap/core\";\nimport { Slice } from \"@tiptap/pm/model\";\nimport { Token, tokenizePrompt } from \"./grammar\";\nimport {\n plainTextToTipTapHtml,\n plainTextToSlice,\n getEditorText,\n markdownToTipTapHtml,\n getEditorMarkdown,\n} from \"./serializers\";\n\nexport interface EditorControllerOptions extends Partial<\n Omit<EditorOptions, \"element\" | \"content\">\n> {\n element?: Element | HTMLElement | null;\n content?: string | Content;\n plainTextMode?: boolean;\n markdownMode?: boolean;\n extensions?: Extensions;\n onPlainTextChange?: (text: string) => void;\n onMarkdownChange?: (markdown: string) => void;\n onTokensChange?: (tokens: Token[]) => void;\n onSelectionChange?: (range: { from: number; to: number } | null) => void;\n}\n\n/**\n * UI-agnostic controller managing the lifecycle, commands, and plain-text/token\n * synchronization of a rich text or prompt editor.\n */\nexport class EditorController {\n public readonly editor: Editor;\n private readonly plainTextMode: boolean;\n private readonly markdownMode: boolean;\n private readonly onPlainTextChange?: (text: string) => void;\n private readonly onMarkdownChange?: (markdown: string) => void;\n private readonly onTokensChange?: (tokens: Token[]) => void;\n private readonly onSelectionChange?: (\n range: { from: number; to: number } | null,\n ) => void;\n private baselineContent: string;\n\n constructor(options: EditorControllerOptions = {}) {\n const {\n element,\n content,\n plainTextMode = false,\n markdownMode = false,\n extensions = [],\n onPlainTextChange,\n onMarkdownChange,\n onTokensChange,\n onSelectionChange,\n ...editorOptions\n } = options;\n\n this.plainTextMode = plainTextMode;\n this.markdownMode = markdownMode;\n this.onPlainTextChange = onPlainTextChange;\n this.onMarkdownChange = onMarkdownChange;\n this.onTokensChange = onTokensChange;\n this.onSelectionChange = onSelectionChange;\n\n const initialContent =\n plainTextMode && typeof content === \"string\"\n ? plainTextToTipTapHtml(content)\n : markdownMode && typeof content === \"string\"\n ? markdownToTipTapHtml(content)\n : content;\n\n this.editor = new Editor({\n element: element || undefined,\n content: initialContent,\n extensions,\n ...editorOptions,\n onUpdate: (props) => {\n editorOptions.onUpdate?.(props);\n this.handleUpdate();\n },\n onSelectionUpdate: (props) => {\n editorOptions.onSelectionUpdate?.(props);\n this.handleSelectionUpdate();\n },\n });\n\n if (plainTextMode) {\n this.enforcePlainTextClipboard();\n }\n\n this.baselineContent = this.getCurrentContentString();\n }\n\n private enforcePlainTextClipboard() {\n this.editor.setOptions({\n editorProps: {\n ...this.editor.options.editorProps,\n clipboardTextParser: (\n text: string,\n context: any,\n _plain: boolean,\n view?: any,\n ) => {\n const schema =\n context?.doc?.type?.schema ||\n context?.schema ||\n view?.state?.schema ||\n this.editor.schema;\n\n if (!schema) return Slice.empty;\n\n return plainTextToSlice(text, schema);\n },\n },\n });\n }\n\n private handleUpdate() {\n if (this.plainTextMode || this.onPlainTextChange || this.onTokensChange) {\n const text = this.getPlainText();\n this.onPlainTextChange?.(text);\n\n if (this.onTokensChange) {\n const tokens = tokenizePrompt(text);\n this.onTokensChange(tokens);\n }\n }\n\n if (this.markdownMode || this.onMarkdownChange) {\n const markdown = this.getMarkdown();\n this.onMarkdownChange?.(markdown);\n }\n }\n\n private handleSelectionUpdate() {\n if (this.onSelectionChange) {\n const { from, to } = this.editor.state.selection;\n this.onSelectionChange({ from, to });\n }\n }\n\n public getPlainText(): string {\n return getEditorText(this.editor);\n }\n\n public setPlainText(text: string, emitUpdate = true) {\n const html = plainTextToTipTapHtml(text);\n this.editor.commands.setContent(html, emitUpdate);\n }\n\n public getMarkdown(): string {\n return getEditorMarkdown(this.editor);\n }\n\n public setMarkdown(markdown: string, emitUpdate = true) {\n if (this.editor.storage?.markdown?.parser) {\n this.editor.commands.setContent(markdown, emitUpdate);\n } else {\n const html = markdownToTipTapHtml(markdown);\n this.editor.commands.setContent(html, emitUpdate);\n }\n }\n\n /**\n * Replaces `from`..`to` with literal text: HTML in `text` is not parsed, and\n * newlines split paragraphs.\n */\n private insertPlainText(from: number, to: number, text: string) {\n const { state, view } = this.editor;\n const tr = text.includes(\"\\n\") || text.includes(\"\\r\")\n ? state.tr.replace(from, to, plainTextToSlice(text, state.schema))\n : text\n ? state.tr.insertText(text, from, to)\n : state.tr.delete(from, to);\n view.dispatch(tr.scrollIntoView());\n }\n\n /** Inserts text literally at the selection; HTML in `text` is not parsed. */\n public insertText(text: string) {\n const { from, to } = this.editor.state.selection;\n this.insertPlainText(from, to, text);\n }\n\n /** Inserts text literally at `pos`; HTML in `text` is not parsed. */\n public insertTextAt(pos: number, text: string) {\n this.insertPlainText(pos, pos, text);\n this.editor.commands.focus();\n }\n\n /** Replaces a range with literal text; HTML in `text` is not parsed. */\n public replaceRange(from: number, to: number, text: string) {\n this.insertPlainText(from, to, text);\n this.editor.commands.focus();\n }\n\n public getCurrentContentString(): string {\n if (this.plainTextMode) return this.getPlainText();\n if (this.markdownMode) return this.getMarkdown();\n return this.editor.getHTML();\n }\n\n public isDirty(): boolean {\n return this.getCurrentContentString() !== this.baselineContent;\n }\n\n public setCheckpoint(content?: string): void {\n this.baselineContent =\n content !== undefined ? content : this.getCurrentContentString();\n }\n\n public resetDirty(): void {\n this.setCheckpoint();\n }\n\n public getBaselineContent(): string {\n return this.baselineContent;\n }\n\n public destroy() {\n this.editor.destroy();\n }\n}\n\n/**\n * Creates and initializes an EditorController instance.\n */\nexport function createEditor(\n options: EditorControllerOptions = {},\n): EditorController {\n return new EditorController(options);\n}\n","/**\n * Compares two values for structural equality.\n * Handles primitives, objects, arrays, and null/undefined.\n */\nexport function defaultIsEqual<T>(a: T, b: T): boolean {\n if (Object.is(a, b)) return true;\n if (\n typeof a !== \"object\" ||\n a === null ||\n typeof b !== \"object\" ||\n b === null\n ) {\n return false;\n }\n\n // Fast path for arrays\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!defaultIsEqual(a[i], b[i])) return false;\n }\n return true;\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n\n const keysA = Object.keys(a) as (keyof T)[];\n const keysB = Object.keys(b) as (keyof T)[];\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false;\n if (!defaultIsEqual(a[key], b[key])) return false;\n }\n\n return true;\n}\n\nexport interface DirtyTrackerOptions<T> {\n isEqual?: (a: T, b: T) => boolean;\n}\n\n/**\n * Tracks a baseline value and determines if the current state is dirty (modified).\n */\nexport class DirtyTracker<T = unknown> {\n private baseline: T;\n private readonly isEqual: (a: T, b: T) => boolean;\n\n constructor(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n ) {\n this.baseline = initialBaseline;\n if (typeof options === \"function\") {\n this.isEqual = options;\n } else {\n this.isEqual = options?.isEqual ?? defaultIsEqual;\n }\n }\n\n /**\n * Returns current baseline value.\n */\n public getBaseline(): T {\n return this.baseline;\n }\n\n /**\n * Sets a new baseline value without triggering any dirty state.\n */\n public setBaseline(value: T): void {\n this.baseline = value;\n }\n\n /**\n * Checks whether the given value differs from the baseline.\n */\n public isDirty(current: T): boolean {\n return !this.isEqual(this.baseline, current);\n }\n\n /**\n * Resets the baseline to the provided current value (or clears dirty status).\n */\n public reset(current: T): void {\n this.baseline = current;\n }\n}\n\n/**\n * Creates a DirtyTracker instance.\n */\nexport function createDirtyTracker<T>(\n initialBaseline: T,\n options?: DirtyTrackerOptions<T> | ((a: T, b: T) => boolean),\n): DirtyTracker<T> {\n return new DirtyTracker(initialBaseline, options);\n}\n"],"mappings":"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","names":[]}
@@ -11,12 +11,12 @@
11
11
 
12
12
 
13
13
 
14
- var _chunkCYKQLDYHcjs = require('../chunk-CYKQLDYH.cjs');
15
14
 
16
15
 
17
16
 
18
17
 
19
18
 
19
+ var _chunkYQCI4CCNcjs = require('../chunk-YQCI4CCN.cjs');
20
20
 
21
21
 
22
22
 
@@ -25,5 +25,15 @@ var _chunkCYKQLDYHcjs = require('../chunk-CYKQLDYH.cjs');
25
25
 
26
26
 
27
27
 
28
- exports.DataSourceBinder = _chunkCYKQLDYHcjs.DataSourceBinder; exports.DependencyGraph = _chunkCYKQLDYHcjs.DependencyGraph; exports.FormulaEvaluator = _chunkCYKQLDYHcjs.FormulaEvaluator; exports.FormulaParser = _chunkCYKQLDYHcjs.FormulaParser; exports.SpreadsheetController = _chunkCYKQLDYHcjs.SpreadsheetController; exports.colNameToIndex = _chunkCYKQLDYHcjs.colNameToIndex; exports.extractCellDependencies = _chunkCYKQLDYHcjs.extractCellDependencies; exports.indexToColName = _chunkCYKQLDYHcjs.indexToColName; exports.parseCellReference = _chunkCYKQLDYHcjs.parseCellReference; exports.parseFormula = _chunkCYKQLDYHcjs.parseFormula; exports.parseRange = _chunkCYKQLDYHcjs.parseRange; exports.tokenizeFormula = _chunkCYKQLDYHcjs.tokenizeFormula;
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+ exports.DataSourceBinder = _chunkYQCI4CCNcjs.DataSourceBinder; exports.DependencyGraph = _chunkYQCI4CCNcjs.DependencyGraph; exports.FORMULA_ERRORS = _chunkYQCI4CCNcjs.FORMULA_ERRORS; exports.FormulaEvaluator = _chunkYQCI4CCNcjs.FormulaEvaluator; exports.FormulaParser = _chunkYQCI4CCNcjs.FormulaParser; exports.SpreadsheetController = _chunkYQCI4CCNcjs.SpreadsheetController; exports.WHOLE_COLUMN_END_ROW = _chunkYQCI4CCNcjs.WHOLE_COLUMN_END_ROW; exports.colNameToIndex = _chunkYQCI4CCNcjs.colNameToIndex; exports.columnDependencyKey = _chunkYQCI4CCNcjs.columnDependencyKey; exports.extractCellDependencies = _chunkYQCI4CCNcjs.extractCellDependencies; exports.indexToColName = _chunkYQCI4CCNcjs.indexToColName; exports.isFormulaError = _chunkYQCI4CCNcjs.isFormulaError; exports.parseCellReference = _chunkYQCI4CCNcjs.parseCellReference; exports.parseFormula = _chunkYQCI4CCNcjs.parseFormula; exports.parseRange = _chunkYQCI4CCNcjs.parseRange; exports.shiftFormulaReferences = _chunkYQCI4CCNcjs.shiftFormulaReferences; exports.tokenizeFormula = _chunkYQCI4CCNcjs.tokenizeFormula;
29
39
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/spreadsheet/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,yuBAAC","file":"/home/runner/work/editor/editor/packages/core/dist/spreadsheet/index.cjs"}
1
+ {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/spreadsheet/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,sjCAAC","file":"/home/runner/work/editor/editor/packages/core/dist/spreadsheet/index.cjs"}