@ai-matrx/alchemy 0.20.6 → 0.22.2

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/core.cjs +1 -6
  3. package/dist/core.cjs.map +1 -1
  4. package/dist/core.d.cts +2 -6
  5. package/dist/core.d.ts +2 -6
  6. package/dist/core.js +1 -6
  7. package/dist/core.js.map +1 -1
  8. package/dist/index.cjs +1 -6
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +2 -6
  11. package/dist/index.d.ts +2 -6
  12. package/dist/index.js +1 -6
  13. package/dist/index.js.map +1 -1
  14. package/dist/operate-read.cjs +1 -1
  15. package/dist/operate-read.cjs.map +1 -1
  16. package/dist/operate-read.d.cts +5 -69
  17. package/dist/operate-read.d.ts +5 -69
  18. package/dist/operate-read.js +1 -1
  19. package/dist/operate-read.js.map +1 -1
  20. package/dist/operate-xlsx.cjs +2 -148
  21. package/dist/operate-xlsx.cjs.map +1 -1
  22. package/dist/operate-xlsx.d.cts +8 -1225
  23. package/dist/operate-xlsx.d.ts +8 -1225
  24. package/dist/operate-xlsx.js +2 -148
  25. package/dist/operate-xlsx.js.map +1 -1
  26. package/dist/operate.cjs +1 -6
  27. package/dist/operate.cjs.map +1 -1
  28. package/dist/operate.d.cts +2 -6
  29. package/dist/operate.d.ts +2 -6
  30. package/dist/operate.js +1 -6
  31. package/dist/operate.js.map +1 -1
  32. package/dist/react-surface.cjs +3 -0
  33. package/dist/react-surface.cjs.map +1 -0
  34. package/dist/react-surface.d.cts +19 -0
  35. package/dist/react-surface.d.ts +19 -0
  36. package/dist/react-surface.js +3 -0
  37. package/dist/react-surface.js.map +1 -0
  38. package/dist/react-workspace.cjs +2 -2
  39. package/dist/react-workspace.cjs.map +1 -1
  40. package/dist/react-workspace.d.cts +3 -6
  41. package/dist/react-workspace.d.ts +3 -6
  42. package/dist/react-workspace.js +2 -2
  43. package/dist/react-workspace.js.map +1 -1
  44. package/package.json +14 -3
@@ -1,2 +1,2 @@
1
- "use strict";var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target,mod)),__toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var operate_read_exports={};__export(operate_read_exports,{UnreadableFormatError:()=>UnreadableFormatError,fileFormatOf:()=>fileFormatOf,parseDelimited:()=>import_delimited.parseDelimited,readFile:()=>readFile,readWorkbook:()=>readWorkbook,toDelimitedText:()=>toDelimitedText});module.exports=__toCommonJS(operate_read_exports);var import_operate=require("@ai-matrx/alchemy/operate"),import_delimited=require("@ai-matrx/kit/delimited"),import_delimited2=require("@ai-matrx/kit/delimited");function toDelimitedText(header,rows,options={}){let columns=header.map((label,i)=>({id:`c${i}`,label,path:`/c${i}`,visible:!0})),record=row=>{let out={};return header.forEach((label,i)=>{let v=Array.isArray(row)?row[i]:row[label];v!==void 0&&(out[`c${i}`]=v)}),out},captured=(0,import_operate.directSource)({kind:"rows",columns,rows:rows.map(record)}),draft=(0,import_operate.createDraft)((0,import_operate.projectSnapshot)(captured.snapshot,captured.projection));return(0,import_operate.serialize)(draft,options.format??"csv",options.spreadsheetSafe===void 0?{}:{spreadsheetSafe:options.spreadsheetSafe}).plainText}async function bytesOf(input){return typeof input=="string"?new TextEncoder().encode(input):input instanceof Uint8Array?input:input instanceof ArrayBuffer?new Uint8Array(input):new Uint8Array(await input.arrayBuffer())}async function readWorkbook(input,options={}){let bytes=await bytesOf(input),{readWorkbookBytes}=await import("@ai-matrx/alchemy/operate/formats/xlsx");return readWorkbookBytes(bytes,options)}var WORKBOOK_FORMATS=new Set(["xlsx","xls","ods","xlsm","xlsb"]),DELIMITED_FORMATS=new Set(["csv","tsv","txt","tab"]),UnreadableFormatError=class extends Error{format;constructor(format){super(`A "${format}" file is not a table we can read. Choose a CSV, TSV, or Excel file.`),this.format=format,this.name="UnreadableFormatError"}};function fileFormatOf(name){let m=/\.([a-z0-9]+)$/i.exec(name??"");return m?m[1].toLowerCase():""}async function readFile(input,options={}){let name=options.filename??(typeof Blob<"u"&&input instanceof Blob&&"name"in input?String(input.name):void 0),format=(options.format??fileFormatOf(name))||(typeof input=="string"?"csv":"");if(WORKBOOK_FORMATS.has(format)){let book=await readWorkbook(input,options.workbook);return{format:format==="xlsm"||format==="xlsb"?"xlsx":format,sheets:book.sheets.map(s=>({name:s.name,grid:s.grid(options.grid),merges:s.merges})),errors:[]}}if(!DELIMITED_FORMATS.has(format))throw new UnreadableFormatError(format||"unknown");let text=typeof input=="string"?input:new TextDecoder("utf-8").decode(await bytesOf(input)),parsed=(0,import_delimited2.parseDelimited)(text,{...options,header:!1,...options.delimiter?{}:format==="tsv"||format==="tab"?{delimiter:" "}:{}});return{format:format==="tab"?"tsv":format,sheets:[{name:name?.replace(/\.[^.]+$/,"")||"Sheet1",grid:parsed.data,merges:[]}],errors:parsed.errors,delimiter:parsed.meta.delimiter}}
1
+ "use strict";var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target,mod)),__toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var operate_read_exports={};__export(operate_read_exports,{UnreadableFormatError:()=>UnreadableFormatError,fileFormatOf:()=>fileFormatOf,parseDelimited:()=>import_delimited.parseDelimited,readFile:()=>readFile,readWorkbook:()=>readWorkbook,toDelimitedText:()=>toDelimitedText});module.exports=__toCommonJS(operate_read_exports);var import_operate=require("@ai-matrx/alchemy/operate"),import_delimited=require("@ai-matrx/kit/delimited"),import_delimited2=require("@ai-matrx/kit/delimited");function toDelimitedText(header,rows,options={}){let columns=header.map((label,i)=>({id:`c${i}`,label,path:`/c${i}`,visible:!0})),record=row=>{let out={};return header.forEach((label,i)=>{let v=Array.isArray(row)?row[i]:row[label];v!==void 0&&(out[`c${i}`]=v)}),out},captured=(0,import_operate.directSource)({kind:"rows",columns,rows:rows.map(record)}),draft=(0,import_operate.createDraft)((0,import_operate.projectSnapshot)(captured.snapshot,captured.projection));return(0,import_operate.serialize)(draft,options.format??"csv",options.spreadsheetSafe===void 0?{}:{spreadsheetSafe:options.spreadsheetSafe}).plainText}async function bytesOf(input){return typeof input=="string"?new TextEncoder().encode(input):input instanceof Uint8Array?input:input instanceof ArrayBuffer?new Uint8Array(input):new Uint8Array(await input.arrayBuffer())}async function readWorkbook(input,options={}){return(await import("@ai-matrx/alchemy/operate/formats/xlsx")).readWorkbookBytes(input,options)}var WORKBOOK_FORMATS=new Set(["xlsx","xls","ods","xlsm","xlsb"]),DELIMITED_FORMATS=new Set(["csv","tsv","txt","tab"]),UnreadableFormatError=class extends Error{format;constructor(format){super(`A "${format}" file is not a table we can read. Choose a CSV, TSV, or Excel file.`),this.format=format,this.name="UnreadableFormatError"}};function fileFormatOf(name){let m=/\.([a-z0-9]+)$/i.exec(name??"");return m?m[1].toLowerCase():""}async function readFile(input,options={}){let name=options.filename??(typeof Blob<"u"&&input instanceof Blob&&"name"in input?String(input.name):void 0),format=(options.format??fileFormatOf(name))||(typeof input=="string"?"csv":"");if(WORKBOOK_FORMATS.has(format)){let book=await readWorkbook(input,options.workbook);return{format:format==="xlsm"||format==="xlsb"?"xlsx":format,sheets:book.sheets.map(s=>({name:s.name,grid:s.grid(options.grid),merges:s.merges})),errors:[]}}if(!DELIMITED_FORMATS.has(format))throw new UnreadableFormatError(format||"unknown");let text=typeof input=="string"?input:new TextDecoder("utf-8").decode(await bytesOf(input)),parsed=(0,import_delimited2.parseDelimited)(text,{...options,header:!1,...options.delimiter?{}:format==="tsv"||format==="tab"?{delimiter:" "}:{}});return{format:format==="tab"?"tsv":format,sheets:[{name:name?.replace(/\.[^.]+$/,"")||"Sheet1",grid:parsed.data,merges:[]}],errors:parsed.errors,delimiter:parsed.meta.delimiter}}
2
2
  //# sourceMappingURL=operate-read.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/operate-read.ts","../src/operate/read.ts"],"sourcesContent":["/** `@ai-matrx/alchemy/operate/read` — the one parse door (CSV/TSV parser; workbooks through the lazy SheetJS leaf). */\nexport {\n UnreadableFormatError,\n fileFormatOf,\n parseDelimited,\n readFile,\n readWorkbook,\n toDelimitedText,\n type DelimitedCell,\n type DelimitedMeta,\n type DelimitedParseError,\n type DelimitedParseOptions,\n type DelimitedResult,\n type ReadFileOptions,\n type ReadInput,\n type TabularFile,\n type TabularFormat,\n type TabularSheet,\n type Workbook,\n type WorkbookCell,\n type WorkbookCellAddress,\n type WorkbookCellJson,\n type WorkbookCellRange,\n type WorkbookGridOptions,\n type WorkbookJson,\n type WorkbookReadOptions,\n type WorkbookRecordOptions,\n type WorkbookSheet,\n} from \"./operate/read\";\n","/**\n * `@ai-matrx/alchemy/operate/read` — the one parse door (ALC-19 T4–T12). Write has `buildFile`; read has `readFile`.\n *\n * One engine per format across read and write:\n * - CSV / TSV / delimited text: kit's `parseDelimited` (no library; it sits in `@ai-matrx/kit/delimited`\n * beside the one writer so packages below alchemy read through it too), re-exported here. `parseDelimited` is Papa Parse–compatible in the options the platform\n * uses (auto delimiter + line ending, quotes, `skipEmptyLines` true | \"greedy\", `header`,\n * `transformHeader`, `dynamicTyping`) and answers the same `{ data, errors, meta }` shape and\n * error codes, so a repointed importer keeps its behaviour.\n * - XLSX / XLS / ODS: SheetJS, the library the `xlsx` writer uses, loaded on first use from the\n * `/operate/formats/xlsx` leaf (`readWorkbook`). A caller that needs spreadsheet typing of a CSV\n * (dates, numbers, formulas as SheetJS reads them) reads it through `readWorkbook` too.\n */\n\n// Through the PUBLIC `/operate` subpath, so this entry shares the transfer core at runtime instead of bundling a copy.\nimport { createDraft, directSource, projectSnapshot, serialize, type Column, type Json } from \"@ai-matrx/alchemy/operate\";\n\n// ─── Delimited text ───────────────────────────────────────────────────────────────────────────────\n// THE one parser lives beside THE one writer in @ai-matrx/kit/delimited (AP-2: packages below\n// alchemy read CSV too); this door re-exports it unchanged, so `/operate/read` keeps its API.\nexport { parseDelimited } from \"@ai-matrx/kit/delimited\";\nexport type {\n DelimitedParseError,\n DelimitedParseOptions,\n ParsedDelimitedCell as DelimitedCell,\n DelimitedMeta,\n DelimitedResult,\n} from \"@ai-matrx/kit/delimited\";\nimport { parseDelimited, type DelimitedParseError, type DelimitedParseOptions } from \"@ai-matrx/kit/delimited\";\n\n/**\n * Delimited text from a header row + body rows, through the SAME `csv`/`tsv` serializer the\n * Alchemy menu's copy and download use (quoting, nested values as compact JSON, `null` empty).\n * `spreadsheetSafe` defaults ON (kit `spreadsheetSafeByDefault`: csv/tsv are for spreadsheets) and\n * prefixes formula-looking text with `'`; pass `false` only for a lossless round-trip or AI-read text.\n */\nexport function toDelimitedText(\n header: readonly string[],\n rows: readonly (readonly (Json | undefined)[] | Readonly<Record<string, Json | undefined>>)[],\n options: { format?: \"csv\" | \"tsv\"; spreadsheetSafe?: boolean } = {},\n): string {\n const columns: Column[] = header.map((label, i) => ({ id: `c${i}`, label, path: `/c${i}`, visible: true }));\n const record = (row: (typeof rows)[number]): Record<string, Json> => {\n const out: Record<string, Json> = {};\n header.forEach((label, i) => {\n const v = Array.isArray(row) ? (row as readonly (Json | undefined)[])[i] : (row as Readonly<Record<string, Json | undefined>>)[label];\n if (v !== undefined) out[`c${i}`] = v;\n });\n return out;\n };\n const captured = directSource({ kind: \"rows\", columns, rows: rows.map(record) });\n const draft = createDraft(projectSnapshot(captured.snapshot, captured.projection));\n return serialize(draft, options.format ?? \"csv\", options.spreadsheetSafe === undefined ? {} : { spreadsheetSafe: options.spreadsheetSafe }).plainText;\n}\n\n// ─── Workbooks (the SheetJS leaf, loaded on first use) ───────────────────────────────────────────\n\nexport type WorkbookCellAddress = { r: number; c: number };\nexport type WorkbookCellRange = { s: WorkbookCellAddress; e: WorkbookCellAddress };\n/** A cell as the workbook engine reads it: type, raw value, formatted text, formula source. */\nexport type WorkbookCell = {\n t: \"s\" | \"n\" | \"b\" | \"d\" | \"e\" | \"z\";\n v?: string | number | boolean | Date;\n w?: string;\n f?: string;\n styled: boolean;\n};\n/** Grid shape options (header row included): `raw: false` → formatted text; `defval` fills gaps. */\nexport type WorkbookGridOptions = { raw?: boolean; defval?: unknown; blankrows?: boolean; dateNF?: string; rawNumbers?: boolean };\nexport type WorkbookRecordOptions = { raw?: boolean; defval?: unknown; blankrows?: boolean; dateNF?: string; rawNumbers?: boolean };\nexport interface WorkbookSheet {\n name: string;\n /** The used range, null for a sheet without one. */\n range: WorkbookCellRange | null;\n merges: WorkbookCellRange[];\n cell(r: number, c: number): WorkbookCell | null;\n cells(): Iterable<readonly [WorkbookCellAddress, WorkbookCell]>;\n grid(options?: WorkbookGridOptions): unknown[][];\n records(options?: WorkbookRecordOptions): Record<string, unknown>[];\n}\nexport interface Workbook {\n sheetNames: string[];\n sheets: WorkbookSheet[];\n sheet(name: string): WorkbookSheet | undefined;\n}\n/** `dates`: date cells as Date (`t: \"d\"`); `formulas`: keep formula source; `styles`: read cell styles. */\nexport type WorkbookReadOptions = { dates?: boolean; formulas?: boolean; styles?: boolean };\n\n/** A typed cell for the `xlsx-workbook` format; a bare string/number/boolean is a value cell. */\nexport type WorkbookCellJson = { t?: \"s\" | \"n\" | \"b\"; v?: string | number | boolean | null; f?: string };\n/** The `xlsx-workbook` payload value (`{ kind: \"registered\", format: \"workbook\", value }`). */\nexport type WorkbookJson = {\n sheets: { name: string; rows: (WorkbookCellJson | string | number | boolean | null)[][]; merges?: WorkbookCellRange[] }[];\n};\n\nexport type ReadInput = Blob | ArrayBuffer | Uint8Array | string;\n\nasync function bytesOf(input: ReadInput): Promise<Uint8Array> {\n if (typeof input === \"string\") return new TextEncoder().encode(input);\n if (input instanceof Uint8Array) return input;\n if (input instanceof ArrayBuffer) return new Uint8Array(input);\n return new Uint8Array(await input.arrayBuffer());\n}\n\n/** Read a spreadsheet (XLSX, XLS, ODS; CSV/TSV with spreadsheet typing) through the one workbook engine. */\nexport async function readWorkbook(input: ReadInput, options: WorkbookReadOptions = {}): Promise<Workbook> {\n const bytes = await bytesOf(input);\n const { readWorkbookBytes } = await import(\"@ai-matrx/alchemy/operate/formats/xlsx\");\n return readWorkbookBytes(bytes, options);\n}\n\n// ─── readFile: the door ──────────────────────────────────────────────────────────────────────────\n\nexport type TabularFormat = \"csv\" | \"tsv\" | \"txt\" | \"xlsx\" | \"xls\" | \"ods\";\nconst WORKBOOK_FORMATS: ReadonlySet<string> = new Set([\"xlsx\", \"xls\", \"ods\", \"xlsm\", \"xlsb\"]);\nconst DELIMITED_FORMATS: ReadonlySet<string> = new Set([\"csv\", \"tsv\", \"txt\", \"tab\"]);\n\nexport type ReadFileOptions = DelimitedParseOptions & {\n /** The file's format; absent → from `filename` (or a File's name) extension. */\n format?: TabularFormat | (string & {});\n filename?: string;\n /** Workbooks: the grid shape (`sheet_to_json` header-row semantics). */\n grid?: WorkbookGridOptions;\n /** Workbooks: read options. */\n workbook?: WorkbookReadOptions;\n};\nexport type TabularSheet = { name: string; grid: unknown[][]; merges: WorkbookCellRange[] };\nexport type TabularFile = { format: TabularFormat; sheets: TabularSheet[]; errors: DelimitedParseError[]; delimiter?: string };\n\nexport class UnreadableFormatError extends Error {\n readonly format: string;\n constructor(format: string) {\n super(`A \"${format}\" file is not a table we can read. Choose a CSV, TSV, or Excel file.`);\n this.format = format;\n this.name = \"UnreadableFormatError\";\n }\n}\n\n/** The format a file name declares (lower-case extension), or \"\" when it has none. */\nexport function fileFormatOf(name: string | undefined): string {\n const m = /\\.([a-z0-9]+)$/i.exec(name ?? \"\");\n return m ? m[1]!.toLowerCase() : \"\";\n}\n\n/**\n * Read a table file — CSV/TSV/plain text through the delimited parser, XLSX/XLS/ODS through the\n * workbook engine — into sheets of grids (header row first). Delimited text is one sheet.\n */\nexport async function readFile(input: ReadInput, options: ReadFileOptions = {}): Promise<TabularFile> {\n const name = options.filename ?? (typeof Blob !== \"undefined\" && input instanceof Blob && \"name\" in input ? String((input as File).name) : undefined);\n const format = (options.format ?? fileFormatOf(name)) || (typeof input === \"string\" ? \"csv\" : \"\");\n if (WORKBOOK_FORMATS.has(format)) {\n const book = await readWorkbook(input, options.workbook);\n return {\n format: (format === \"xlsm\" || format === \"xlsb\" ? \"xlsx\" : format) as TabularFormat,\n sheets: book.sheets.map((s) => ({ name: s.name, grid: s.grid(options.grid), merges: s.merges })),\n errors: [],\n };\n }\n if (!DELIMITED_FORMATS.has(format)) throw new UnreadableFormatError(format || \"unknown\");\n const text = typeof input === \"string\" ? input : new TextDecoder(\"utf-8\").decode(await bytesOf(input));\n const parsed = parseDelimited(text, {\n ...options,\n header: false,\n ...(options.delimiter ? {} : format === \"tsv\" || format === \"tab\" ? { delimiter: \"\\t\" } : {}),\n } as DelimitedParseOptions & { header: false; dynamicTyping?: false });\n return {\n format: (format === \"tab\" ? \"tsv\" : format) as TabularFormat,\n sheets: [{ name: name?.replace(/\\.[^.]+$/, \"\") || \"Sheet1\", grid: parsed.data, merges: [] }],\n errors: parsed.errors,\n delimiter: parsed.meta.delimiter,\n };\n}\n"],"mappings":"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","names":["import_delimited"]}
1
+ {"version":3,"sources":["../src/operate-read.ts","../src/operate/read.ts"],"sourcesContent":["/** `@ai-matrx/alchemy/operate/read` — the one parse door (CSV/TSV parser; workbooks through the lazy SheetJS leaf). */\nexport {\n UnreadableFormatError,\n fileFormatOf,\n parseDelimited,\n readFile,\n readWorkbook,\n toDelimitedText,\n type DelimitedCell,\n type DelimitedMeta,\n type DelimitedParseError,\n type DelimitedParseOptions,\n type DelimitedResult,\n type ReadFileOptions,\n type ReadInput,\n type TabularFile,\n type TabularFormat,\n type TabularSheet,\n type Workbook,\n type WorkbookCell,\n type WorkbookCellAddress,\n type WorkbookCellJson,\n type WorkbookCellRange,\n type WorkbookGridOptions,\n type WorkbookJson,\n type WorkbookReadOptions,\n type WorkbookRecordOptions,\n type WorkbookSheet,\n} from \"./operate/read\";\n","/**\n * `@ai-matrx/alchemy/operate/read` — the one parse door (ALC-19 T4–T12). Write has `buildFile`; read has `readFile`.\n *\n * One engine per format across read and write:\n * - CSV / TSV / delimited text: kit's `parseDelimited` (no library; it sits in `@ai-matrx/kit/delimited`\n * beside the one writer so packages below alchemy read through it too), re-exported here. `parseDelimited` is Papa Parse–compatible in the options the platform\n * uses (auto delimiter + line ending, quotes, `skipEmptyLines` true | \"greedy\", `header`,\n * `transformHeader`, `dynamicTyping`) and answers the same `{ data, errors, meta }` shape and\n * error codes, so a repointed importer keeps its behaviour.\n * - XLSX / XLS / ODS: SheetJS, the library the `xlsx` writer uses, loaded on first use from the\n * `/operate/formats/xlsx` leaf (`readWorkbook`). A caller that needs spreadsheet typing of a CSV\n * (dates, numbers, formulas as SheetJS reads them) reads it through `readWorkbook` too.\n */\n\n// Through the PUBLIC `/operate` subpath, so this entry shares the transfer core at runtime instead of bundling a copy.\nimport { createDraft, directSource, projectSnapshot, serialize, type Column, type Json } from \"@ai-matrx/alchemy/operate\";\n\n// ─── Delimited text ───────────────────────────────────────────────────────────────────────────────\n// THE one parser lives beside THE one writer in @ai-matrx/kit/delimited (AP-2: packages below\n// alchemy read CSV too); this door re-exports it unchanged, so `/operate/read` keeps its API.\nexport { parseDelimited } from \"@ai-matrx/kit/delimited\";\nexport type {\n DelimitedParseError,\n DelimitedParseOptions,\n ParsedDelimitedCell as DelimitedCell,\n DelimitedMeta,\n DelimitedResult,\n} from \"@ai-matrx/kit/delimited\";\nimport { parseDelimited, type DelimitedParseError, type DelimitedParseOptions } from \"@ai-matrx/kit/delimited\";\n\n/**\n * Delimited text from a header row + body rows, through the SAME `csv`/`tsv` serializer the\n * Alchemy menu's copy and download use (quoting, nested values as compact JSON, `null` empty).\n * `spreadsheetSafe` defaults ON (kit `spreadsheetSafeByDefault`: csv/tsv are for spreadsheets) and\n * prefixes formula-looking text with `'`; pass `false` only for a lossless round-trip or AI-read text.\n */\nexport function toDelimitedText(\n header: readonly string[],\n rows: readonly (readonly (Json | undefined)[] | Readonly<Record<string, Json | undefined>>)[],\n options: { format?: \"csv\" | \"tsv\"; spreadsheetSafe?: boolean } = {},\n): string {\n const columns: Column[] = header.map((label, i) => ({ id: `c${i}`, label, path: `/c${i}`, visible: true }));\n const record = (row: (typeof rows)[number]): Record<string, Json> => {\n const out: Record<string, Json> = {};\n header.forEach((label, i) => {\n const v = Array.isArray(row) ? (row as readonly (Json | undefined)[])[i] : (row as Readonly<Record<string, Json | undefined>>)[label];\n if (v !== undefined) out[`c${i}`] = v;\n });\n return out;\n };\n const captured = directSource({ kind: \"rows\", columns, rows: rows.map(record) });\n const draft = createDraft(projectSnapshot(captured.snapshot, captured.projection));\n return serialize(draft, options.format ?? \"csv\", options.spreadsheetSafe === undefined ? {} : { spreadsheetSafe: options.spreadsheetSafe }).plainText;\n}\n\n// ─── Workbooks (the SheetJS leaf, loaded on first use) ───────────────────────────────────────────\n\n// The workbook types and reader are print's (`@ai-matrx/print/xlsx`, architecture step 13).\nexport type {\n Workbook,\n WorkbookCell,\n WorkbookCellAddress,\n WorkbookCellJson,\n WorkbookCellRange,\n WorkbookGridOptions,\n WorkbookJson,\n WorkbookReadOptions,\n WorkbookRecordOptions,\n WorkbookSheet,\n ReadInput,\n} from \"@ai-matrx/print/xlsx\";\nimport type { ReadInput, Workbook, WorkbookCellRange, WorkbookGridOptions, WorkbookReadOptions } from \"@ai-matrx/print/xlsx\";\n\nasync function bytesOf(input: ReadInput): Promise<Uint8Array> {\n if (typeof input === \"string\") return new TextEncoder().encode(input);\n if (input instanceof Uint8Array) return input;\n if (input instanceof ArrayBuffer) return new Uint8Array(input);\n return new Uint8Array(await input.arrayBuffer());\n}\n\n/** Read a spreadsheet (XLSX, XLS, ODS; CSV/TSV with spreadsheet typing) through the one workbook engine (lazy). */\nexport async function readWorkbook(input: ReadInput, options: WorkbookReadOptions = {}): Promise<Workbook> {\n const engine = await import(\"@ai-matrx/alchemy/operate/formats/xlsx\");\n return engine.readWorkbookBytes(input, options);\n}\n\n// ─── readFile: the door ──────────────────────────────────────────────────────────────────────────\n\nexport type TabularFormat = \"csv\" | \"tsv\" | \"txt\" | \"xlsx\" | \"xls\" | \"ods\";\nconst WORKBOOK_FORMATS: ReadonlySet<string> = new Set([\"xlsx\", \"xls\", \"ods\", \"xlsm\", \"xlsb\"]);\nconst DELIMITED_FORMATS: ReadonlySet<string> = new Set([\"csv\", \"tsv\", \"txt\", \"tab\"]);\n\nexport type ReadFileOptions = DelimitedParseOptions & {\n /** The file's format; absent → from `filename` (or a File's name) extension. */\n format?: TabularFormat | (string & {});\n filename?: string;\n /** Workbooks: the grid shape (`sheet_to_json` header-row semantics). */\n grid?: WorkbookGridOptions;\n /** Workbooks: read options. */\n workbook?: WorkbookReadOptions;\n};\nexport type TabularSheet = { name: string; grid: unknown[][]; merges: WorkbookCellRange[] };\nexport type TabularFile = { format: TabularFormat; sheets: TabularSheet[]; errors: DelimitedParseError[]; delimiter?: string };\n\nexport class UnreadableFormatError extends Error {\n readonly format: string;\n constructor(format: string) {\n super(`A \"${format}\" file is not a table we can read. Choose a CSV, TSV, or Excel file.`);\n this.format = format;\n this.name = \"UnreadableFormatError\";\n }\n}\n\n/** The format a file name declares (lower-case extension), or \"\" when it has none. */\nexport function fileFormatOf(name: string | undefined): string {\n const m = /\\.([a-z0-9]+)$/i.exec(name ?? \"\");\n return m ? m[1]!.toLowerCase() : \"\";\n}\n\n/**\n * Read a table file — CSV/TSV/plain text through the delimited parser, XLSX/XLS/ODS through the\n * workbook engine — into sheets of grids (header row first). Delimited text is one sheet.\n */\nexport async function readFile(input: ReadInput, options: ReadFileOptions = {}): Promise<TabularFile> {\n const name = options.filename ?? (typeof Blob !== \"undefined\" && input instanceof Blob && \"name\" in input ? String((input as File).name) : undefined);\n const format = (options.format ?? fileFormatOf(name)) || (typeof input === \"string\" ? \"csv\" : \"\");\n if (WORKBOOK_FORMATS.has(format)) {\n const book = await readWorkbook(input, options.workbook);\n return {\n format: (format === \"xlsm\" || format === \"xlsb\" ? \"xlsx\" : format) as TabularFormat,\n sheets: book.sheets.map((s) => ({ name: s.name, grid: s.grid(options.grid), merges: s.merges })),\n errors: [],\n };\n }\n if (!DELIMITED_FORMATS.has(format)) throw new UnreadableFormatError(format || \"unknown\");\n const text = typeof input === \"string\" ? input : new TextDecoder(\"utf-8\").decode(await bytesOf(input));\n const parsed = parseDelimited(text, {\n ...options,\n header: false,\n ...(options.delimiter ? {} : format === \"tsv\" || format === \"tab\" ? { delimiter: \"\\t\" } : {}),\n } as DelimitedParseOptions & { header: false; dynamicTyping?: false });\n return {\n format: (format === \"tab\" ? \"tsv\" : format) as TabularFormat,\n sheets: [{ name: name?.replace(/\\.[^.]+$/, \"\") || \"Sheet1\", grid: parsed.data, merges: [] }],\n errors: parsed.errors,\n delimiter: parsed.meta.delimiter,\n };\n}\n"],"mappings":"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","names":["import_delimited"]}
@@ -1,6 +1,8 @@
1
1
  import { Json } from '@ai-matrx/alchemy/operate';
2
2
  import { DelimitedParseOptions, DelimitedParseError } from '@ai-matrx/kit/delimited';
3
3
  export { ParsedDelimitedCell as DelimitedCell, DelimitedMeta, DelimitedParseError, DelimitedParseOptions, DelimitedResult, parseDelimited } from '@ai-matrx/kit/delimited';
4
+ import { WorkbookGridOptions, WorkbookReadOptions, WorkbookCellRange, ReadInput, Workbook } from '@ai-matrx/print/xlsx';
5
+ export { ReadInput, Workbook, WorkbookCell, WorkbookCellAddress, WorkbookCellJson, WorkbookCellRange, WorkbookGridOptions, WorkbookJson, WorkbookReadOptions, WorkbookRecordOptions, WorkbookSheet } from '@ai-matrx/print/xlsx';
4
6
 
5
7
  /**
6
8
  * `@ai-matrx/alchemy/operate/read` — the one parse door (ALC-19 T4–T12). Write has `buildFile`; read has `readFile`.
@@ -26,74 +28,8 @@ declare function toDelimitedText(header: readonly string[], rows: readonly (read
26
28
  format?: "csv" | "tsv";
27
29
  spreadsheetSafe?: boolean;
28
30
  }): string;
29
- type WorkbookCellAddress = {
30
- r: number;
31
- c: number;
32
- };
33
- type WorkbookCellRange = {
34
- s: WorkbookCellAddress;
35
- e: WorkbookCellAddress;
36
- };
37
- /** A cell as the workbook engine reads it: type, raw value, formatted text, formula source. */
38
- type WorkbookCell = {
39
- t: "s" | "n" | "b" | "d" | "e" | "z";
40
- v?: string | number | boolean | Date;
41
- w?: string;
42
- f?: string;
43
- styled: boolean;
44
- };
45
- /** Grid shape options (header row included): `raw: false` → formatted text; `defval` fills gaps. */
46
- type WorkbookGridOptions = {
47
- raw?: boolean;
48
- defval?: unknown;
49
- blankrows?: boolean;
50
- dateNF?: string;
51
- rawNumbers?: boolean;
52
- };
53
- type WorkbookRecordOptions = {
54
- raw?: boolean;
55
- defval?: unknown;
56
- blankrows?: boolean;
57
- dateNF?: string;
58
- rawNumbers?: boolean;
59
- };
60
- interface WorkbookSheet {
61
- name: string;
62
- /** The used range, null for a sheet without one. */
63
- range: WorkbookCellRange | null;
64
- merges: WorkbookCellRange[];
65
- cell(r: number, c: number): WorkbookCell | null;
66
- cells(): Iterable<readonly [WorkbookCellAddress, WorkbookCell]>;
67
- grid(options?: WorkbookGridOptions): unknown[][];
68
- records(options?: WorkbookRecordOptions): Record<string, unknown>[];
69
- }
70
- interface Workbook {
71
- sheetNames: string[];
72
- sheets: WorkbookSheet[];
73
- sheet(name: string): WorkbookSheet | undefined;
74
- }
75
- /** `dates`: date cells as Date (`t: "d"`); `formulas`: keep formula source; `styles`: read cell styles. */
76
- type WorkbookReadOptions = {
77
- dates?: boolean;
78
- formulas?: boolean;
79
- styles?: boolean;
80
- };
81
- /** A typed cell for the `xlsx-workbook` format; a bare string/number/boolean is a value cell. */
82
- type WorkbookCellJson = {
83
- t?: "s" | "n" | "b";
84
- v?: string | number | boolean | null;
85
- f?: string;
86
- };
87
- /** The `xlsx-workbook` payload value (`{ kind: "registered", format: "workbook", value }`). */
88
- type WorkbookJson = {
89
- sheets: {
90
- name: string;
91
- rows: (WorkbookCellJson | string | number | boolean | null)[][];
92
- merges?: WorkbookCellRange[];
93
- }[];
94
- };
95
- type ReadInput = Blob | ArrayBuffer | Uint8Array | string;
96
- /** Read a spreadsheet (XLSX, XLS, ODS; CSV/TSV with spreadsheet typing) through the one workbook engine. */
31
+
32
+ /** Read a spreadsheet (XLSX, XLS, ODS; CSV/TSV with spreadsheet typing) through the one workbook engine (lazy). */
97
33
  declare function readWorkbook(input: ReadInput, options?: WorkbookReadOptions): Promise<Workbook>;
98
34
  type TabularFormat = "csv" | "tsv" | "txt" | "xlsx" | "xls" | "ods";
99
35
  type ReadFileOptions = DelimitedParseOptions & {
@@ -128,4 +64,4 @@ declare function fileFormatOf(name: string | undefined): string;
128
64
  */
129
65
  declare function readFile(input: ReadInput, options?: ReadFileOptions): Promise<TabularFile>;
130
66
 
131
- export { type ReadFileOptions, type ReadInput, type TabularFile, type TabularFormat, type TabularSheet, UnreadableFormatError, type Workbook, type WorkbookCell, type WorkbookCellAddress, type WorkbookCellJson, type WorkbookCellRange, type WorkbookGridOptions, type WorkbookJson, type WorkbookReadOptions, type WorkbookRecordOptions, type WorkbookSheet, fileFormatOf, readFile, readWorkbook, toDelimitedText };
67
+ export { type ReadFileOptions, type TabularFile, type TabularFormat, type TabularSheet, UnreadableFormatError, fileFormatOf, readFile, readWorkbook, toDelimitedText };
@@ -1,6 +1,8 @@
1
1
  import { Json } from '@ai-matrx/alchemy/operate';
2
2
  import { DelimitedParseOptions, DelimitedParseError } from '@ai-matrx/kit/delimited';
3
3
  export { ParsedDelimitedCell as DelimitedCell, DelimitedMeta, DelimitedParseError, DelimitedParseOptions, DelimitedResult, parseDelimited } from '@ai-matrx/kit/delimited';
4
+ import { WorkbookGridOptions, WorkbookReadOptions, WorkbookCellRange, ReadInput, Workbook } from '@ai-matrx/print/xlsx';
5
+ export { ReadInput, Workbook, WorkbookCell, WorkbookCellAddress, WorkbookCellJson, WorkbookCellRange, WorkbookGridOptions, WorkbookJson, WorkbookReadOptions, WorkbookRecordOptions, WorkbookSheet } from '@ai-matrx/print/xlsx';
4
6
 
5
7
  /**
6
8
  * `@ai-matrx/alchemy/operate/read` — the one parse door (ALC-19 T4–T12). Write has `buildFile`; read has `readFile`.
@@ -26,74 +28,8 @@ declare function toDelimitedText(header: readonly string[], rows: readonly (read
26
28
  format?: "csv" | "tsv";
27
29
  spreadsheetSafe?: boolean;
28
30
  }): string;
29
- type WorkbookCellAddress = {
30
- r: number;
31
- c: number;
32
- };
33
- type WorkbookCellRange = {
34
- s: WorkbookCellAddress;
35
- e: WorkbookCellAddress;
36
- };
37
- /** A cell as the workbook engine reads it: type, raw value, formatted text, formula source. */
38
- type WorkbookCell = {
39
- t: "s" | "n" | "b" | "d" | "e" | "z";
40
- v?: string | number | boolean | Date;
41
- w?: string;
42
- f?: string;
43
- styled: boolean;
44
- };
45
- /** Grid shape options (header row included): `raw: false` → formatted text; `defval` fills gaps. */
46
- type WorkbookGridOptions = {
47
- raw?: boolean;
48
- defval?: unknown;
49
- blankrows?: boolean;
50
- dateNF?: string;
51
- rawNumbers?: boolean;
52
- };
53
- type WorkbookRecordOptions = {
54
- raw?: boolean;
55
- defval?: unknown;
56
- blankrows?: boolean;
57
- dateNF?: string;
58
- rawNumbers?: boolean;
59
- };
60
- interface WorkbookSheet {
61
- name: string;
62
- /** The used range, null for a sheet without one. */
63
- range: WorkbookCellRange | null;
64
- merges: WorkbookCellRange[];
65
- cell(r: number, c: number): WorkbookCell | null;
66
- cells(): Iterable<readonly [WorkbookCellAddress, WorkbookCell]>;
67
- grid(options?: WorkbookGridOptions): unknown[][];
68
- records(options?: WorkbookRecordOptions): Record<string, unknown>[];
69
- }
70
- interface Workbook {
71
- sheetNames: string[];
72
- sheets: WorkbookSheet[];
73
- sheet(name: string): WorkbookSheet | undefined;
74
- }
75
- /** `dates`: date cells as Date (`t: "d"`); `formulas`: keep formula source; `styles`: read cell styles. */
76
- type WorkbookReadOptions = {
77
- dates?: boolean;
78
- formulas?: boolean;
79
- styles?: boolean;
80
- };
81
- /** A typed cell for the `xlsx-workbook` format; a bare string/number/boolean is a value cell. */
82
- type WorkbookCellJson = {
83
- t?: "s" | "n" | "b";
84
- v?: string | number | boolean | null;
85
- f?: string;
86
- };
87
- /** The `xlsx-workbook` payload value (`{ kind: "registered", format: "workbook", value }`). */
88
- type WorkbookJson = {
89
- sheets: {
90
- name: string;
91
- rows: (WorkbookCellJson | string | number | boolean | null)[][];
92
- merges?: WorkbookCellRange[];
93
- }[];
94
- };
95
- type ReadInput = Blob | ArrayBuffer | Uint8Array | string;
96
- /** Read a spreadsheet (XLSX, XLS, ODS; CSV/TSV with spreadsheet typing) through the one workbook engine. */
31
+
32
+ /** Read a spreadsheet (XLSX, XLS, ODS; CSV/TSV with spreadsheet typing) through the one workbook engine (lazy). */
97
33
  declare function readWorkbook(input: ReadInput, options?: WorkbookReadOptions): Promise<Workbook>;
98
34
  type TabularFormat = "csv" | "tsv" | "txt" | "xlsx" | "xls" | "ods";
99
35
  type ReadFileOptions = DelimitedParseOptions & {
@@ -128,4 +64,4 @@ declare function fileFormatOf(name: string | undefined): string;
128
64
  */
129
65
  declare function readFile(input: ReadInput, options?: ReadFileOptions): Promise<TabularFile>;
130
66
 
131
- export { type ReadFileOptions, type ReadInput, type TabularFile, type TabularFormat, type TabularSheet, UnreadableFormatError, type Workbook, type WorkbookCell, type WorkbookCellAddress, type WorkbookCellJson, type WorkbookCellRange, type WorkbookGridOptions, type WorkbookJson, type WorkbookReadOptions, type WorkbookRecordOptions, type WorkbookSheet, fileFormatOf, readFile, readWorkbook, toDelimitedText };
67
+ export { type ReadFileOptions, type TabularFile, type TabularFormat, type TabularSheet, UnreadableFormatError, fileFormatOf, readFile, readWorkbook, toDelimitedText };
@@ -1,2 +1,2 @@
1
- import{createDraft,directSource,projectSnapshot,serialize}from"@ai-matrx/alchemy/operate";import{parseDelimited}from"@ai-matrx/kit/delimited";import{parseDelimited as parseDelimited2}from"@ai-matrx/kit/delimited";function toDelimitedText(header,rows,options={}){let columns=header.map((label,i)=>({id:`c${i}`,label,path:`/c${i}`,visible:!0})),record=row=>{let out={};return header.forEach((label,i)=>{let v=Array.isArray(row)?row[i]:row[label];v!==void 0&&(out[`c${i}`]=v)}),out},captured=directSource({kind:"rows",columns,rows:rows.map(record)}),draft=createDraft(projectSnapshot(captured.snapshot,captured.projection));return serialize(draft,options.format??"csv",options.spreadsheetSafe===void 0?{}:{spreadsheetSafe:options.spreadsheetSafe}).plainText}async function bytesOf(input){return typeof input=="string"?new TextEncoder().encode(input):input instanceof Uint8Array?input:input instanceof ArrayBuffer?new Uint8Array(input):new Uint8Array(await input.arrayBuffer())}async function readWorkbook(input,options={}){let bytes=await bytesOf(input),{readWorkbookBytes}=await import("@ai-matrx/alchemy/operate/formats/xlsx");return readWorkbookBytes(bytes,options)}var WORKBOOK_FORMATS=new Set(["xlsx","xls","ods","xlsm","xlsb"]),DELIMITED_FORMATS=new Set(["csv","tsv","txt","tab"]),UnreadableFormatError=class extends Error{format;constructor(format){super(`A "${format}" file is not a table we can read. Choose a CSV, TSV, or Excel file.`),this.format=format,this.name="UnreadableFormatError"}};function fileFormatOf(name){let m=/\.([a-z0-9]+)$/i.exec(name??"");return m?m[1].toLowerCase():""}async function readFile(input,options={}){let name=options.filename??(typeof Blob<"u"&&input instanceof Blob&&"name"in input?String(input.name):void 0),format=(options.format??fileFormatOf(name))||(typeof input=="string"?"csv":"");if(WORKBOOK_FORMATS.has(format)){let book=await readWorkbook(input,options.workbook);return{format:format==="xlsm"||format==="xlsb"?"xlsx":format,sheets:book.sheets.map(s=>({name:s.name,grid:s.grid(options.grid),merges:s.merges})),errors:[]}}if(!DELIMITED_FORMATS.has(format))throw new UnreadableFormatError(format||"unknown");let text=typeof input=="string"?input:new TextDecoder("utf-8").decode(await bytesOf(input)),parsed=parseDelimited2(text,{...options,header:!1,...options.delimiter?{}:format==="tsv"||format==="tab"?{delimiter:" "}:{}});return{format:format==="tab"?"tsv":format,sheets:[{name:name?.replace(/\.[^.]+$/,"")||"Sheet1",grid:parsed.data,merges:[]}],errors:parsed.errors,delimiter:parsed.meta.delimiter}}export{UnreadableFormatError,fileFormatOf,parseDelimited,readFile,readWorkbook,toDelimitedText};
1
+ import{createDraft,directSource,projectSnapshot,serialize}from"@ai-matrx/alchemy/operate";import{parseDelimited}from"@ai-matrx/kit/delimited";import{parseDelimited as parseDelimited2}from"@ai-matrx/kit/delimited";function toDelimitedText(header,rows,options={}){let columns=header.map((label,i)=>({id:`c${i}`,label,path:`/c${i}`,visible:!0})),record=row=>{let out={};return header.forEach((label,i)=>{let v=Array.isArray(row)?row[i]:row[label];v!==void 0&&(out[`c${i}`]=v)}),out},captured=directSource({kind:"rows",columns,rows:rows.map(record)}),draft=createDraft(projectSnapshot(captured.snapshot,captured.projection));return serialize(draft,options.format??"csv",options.spreadsheetSafe===void 0?{}:{spreadsheetSafe:options.spreadsheetSafe}).plainText}async function bytesOf(input){return typeof input=="string"?new TextEncoder().encode(input):input instanceof Uint8Array?input:input instanceof ArrayBuffer?new Uint8Array(input):new Uint8Array(await input.arrayBuffer())}async function readWorkbook(input,options={}){return(await import("@ai-matrx/alchemy/operate/formats/xlsx")).readWorkbookBytes(input,options)}var WORKBOOK_FORMATS=new Set(["xlsx","xls","ods","xlsm","xlsb"]),DELIMITED_FORMATS=new Set(["csv","tsv","txt","tab"]),UnreadableFormatError=class extends Error{format;constructor(format){super(`A "${format}" file is not a table we can read. Choose a CSV, TSV, or Excel file.`),this.format=format,this.name="UnreadableFormatError"}};function fileFormatOf(name){let m=/\.([a-z0-9]+)$/i.exec(name??"");return m?m[1].toLowerCase():""}async function readFile(input,options={}){let name=options.filename??(typeof Blob<"u"&&input instanceof Blob&&"name"in input?String(input.name):void 0),format=(options.format??fileFormatOf(name))||(typeof input=="string"?"csv":"");if(WORKBOOK_FORMATS.has(format)){let book=await readWorkbook(input,options.workbook);return{format:format==="xlsm"||format==="xlsb"?"xlsx":format,sheets:book.sheets.map(s=>({name:s.name,grid:s.grid(options.grid),merges:s.merges})),errors:[]}}if(!DELIMITED_FORMATS.has(format))throw new UnreadableFormatError(format||"unknown");let text=typeof input=="string"?input:new TextDecoder("utf-8").decode(await bytesOf(input)),parsed=parseDelimited2(text,{...options,header:!1,...options.delimiter?{}:format==="tsv"||format==="tab"?{delimiter:" "}:{}});return{format:format==="tab"?"tsv":format,sheets:[{name:name?.replace(/\.[^.]+$/,"")||"Sheet1",grid:parsed.data,merges:[]}],errors:parsed.errors,delimiter:parsed.meta.delimiter}}export{UnreadableFormatError,fileFormatOf,parseDelimited,readFile,readWorkbook,toDelimitedText};
2
2
  //# sourceMappingURL=operate-read.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/operate/read.ts"],"sourcesContent":["/**\n * `@ai-matrx/alchemy/operate/read` — the one parse door (ALC-19 T4–T12). Write has `buildFile`; read has `readFile`.\n *\n * One engine per format across read and write:\n * - CSV / TSV / delimited text: kit's `parseDelimited` (no library; it sits in `@ai-matrx/kit/delimited`\n * beside the one writer so packages below alchemy read through it too), re-exported here. `parseDelimited` is Papa Parse–compatible in the options the platform\n * uses (auto delimiter + line ending, quotes, `skipEmptyLines` true | \"greedy\", `header`,\n * `transformHeader`, `dynamicTyping`) and answers the same `{ data, errors, meta }` shape and\n * error codes, so a repointed importer keeps its behaviour.\n * - XLSX / XLS / ODS: SheetJS, the library the `xlsx` writer uses, loaded on first use from the\n * `/operate/formats/xlsx` leaf (`readWorkbook`). A caller that needs spreadsheet typing of a CSV\n * (dates, numbers, formulas as SheetJS reads them) reads it through `readWorkbook` too.\n */\n\n// Through the PUBLIC `/operate` subpath, so this entry shares the transfer core at runtime instead of bundling a copy.\nimport { createDraft, directSource, projectSnapshot, serialize, type Column, type Json } from \"@ai-matrx/alchemy/operate\";\n\n// ─── Delimited text ───────────────────────────────────────────────────────────────────────────────\n// THE one parser lives beside THE one writer in @ai-matrx/kit/delimited (AP-2: packages below\n// alchemy read CSV too); this door re-exports it unchanged, so `/operate/read` keeps its API.\nexport { parseDelimited } from \"@ai-matrx/kit/delimited\";\nexport type {\n DelimitedParseError,\n DelimitedParseOptions,\n ParsedDelimitedCell as DelimitedCell,\n DelimitedMeta,\n DelimitedResult,\n} from \"@ai-matrx/kit/delimited\";\nimport { parseDelimited, type DelimitedParseError, type DelimitedParseOptions } from \"@ai-matrx/kit/delimited\";\n\n/**\n * Delimited text from a header row + body rows, through the SAME `csv`/`tsv` serializer the\n * Alchemy menu's copy and download use (quoting, nested values as compact JSON, `null` empty).\n * `spreadsheetSafe` defaults ON (kit `spreadsheetSafeByDefault`: csv/tsv are for spreadsheets) and\n * prefixes formula-looking text with `'`; pass `false` only for a lossless round-trip or AI-read text.\n */\nexport function toDelimitedText(\n header: readonly string[],\n rows: readonly (readonly (Json | undefined)[] | Readonly<Record<string, Json | undefined>>)[],\n options: { format?: \"csv\" | \"tsv\"; spreadsheetSafe?: boolean } = {},\n): string {\n const columns: Column[] = header.map((label, i) => ({ id: `c${i}`, label, path: `/c${i}`, visible: true }));\n const record = (row: (typeof rows)[number]): Record<string, Json> => {\n const out: Record<string, Json> = {};\n header.forEach((label, i) => {\n const v = Array.isArray(row) ? (row as readonly (Json | undefined)[])[i] : (row as Readonly<Record<string, Json | undefined>>)[label];\n if (v !== undefined) out[`c${i}`] = v;\n });\n return out;\n };\n const captured = directSource({ kind: \"rows\", columns, rows: rows.map(record) });\n const draft = createDraft(projectSnapshot(captured.snapshot, captured.projection));\n return serialize(draft, options.format ?? \"csv\", options.spreadsheetSafe === undefined ? {} : { spreadsheetSafe: options.spreadsheetSafe }).plainText;\n}\n\n// ─── Workbooks (the SheetJS leaf, loaded on first use) ───────────────────────────────────────────\n\nexport type WorkbookCellAddress = { r: number; c: number };\nexport type WorkbookCellRange = { s: WorkbookCellAddress; e: WorkbookCellAddress };\n/** A cell as the workbook engine reads it: type, raw value, formatted text, formula source. */\nexport type WorkbookCell = {\n t: \"s\" | \"n\" | \"b\" | \"d\" | \"e\" | \"z\";\n v?: string | number | boolean | Date;\n w?: string;\n f?: string;\n styled: boolean;\n};\n/** Grid shape options (header row included): `raw: false` → formatted text; `defval` fills gaps. */\nexport type WorkbookGridOptions = { raw?: boolean; defval?: unknown; blankrows?: boolean; dateNF?: string; rawNumbers?: boolean };\nexport type WorkbookRecordOptions = { raw?: boolean; defval?: unknown; blankrows?: boolean; dateNF?: string; rawNumbers?: boolean };\nexport interface WorkbookSheet {\n name: string;\n /** The used range, null for a sheet without one. */\n range: WorkbookCellRange | null;\n merges: WorkbookCellRange[];\n cell(r: number, c: number): WorkbookCell | null;\n cells(): Iterable<readonly [WorkbookCellAddress, WorkbookCell]>;\n grid(options?: WorkbookGridOptions): unknown[][];\n records(options?: WorkbookRecordOptions): Record<string, unknown>[];\n}\nexport interface Workbook {\n sheetNames: string[];\n sheets: WorkbookSheet[];\n sheet(name: string): WorkbookSheet | undefined;\n}\n/** `dates`: date cells as Date (`t: \"d\"`); `formulas`: keep formula source; `styles`: read cell styles. */\nexport type WorkbookReadOptions = { dates?: boolean; formulas?: boolean; styles?: boolean };\n\n/** A typed cell for the `xlsx-workbook` format; a bare string/number/boolean is a value cell. */\nexport type WorkbookCellJson = { t?: \"s\" | \"n\" | \"b\"; v?: string | number | boolean | null; f?: string };\n/** The `xlsx-workbook` payload value (`{ kind: \"registered\", format: \"workbook\", value }`). */\nexport type WorkbookJson = {\n sheets: { name: string; rows: (WorkbookCellJson | string | number | boolean | null)[][]; merges?: WorkbookCellRange[] }[];\n};\n\nexport type ReadInput = Blob | ArrayBuffer | Uint8Array | string;\n\nasync function bytesOf(input: ReadInput): Promise<Uint8Array> {\n if (typeof input === \"string\") return new TextEncoder().encode(input);\n if (input instanceof Uint8Array) return input;\n if (input instanceof ArrayBuffer) return new Uint8Array(input);\n return new Uint8Array(await input.arrayBuffer());\n}\n\n/** Read a spreadsheet (XLSX, XLS, ODS; CSV/TSV with spreadsheet typing) through the one workbook engine. */\nexport async function readWorkbook(input: ReadInput, options: WorkbookReadOptions = {}): Promise<Workbook> {\n const bytes = await bytesOf(input);\n const { readWorkbookBytes } = await import(\"@ai-matrx/alchemy/operate/formats/xlsx\");\n return readWorkbookBytes(bytes, options);\n}\n\n// ─── readFile: the door ──────────────────────────────────────────────────────────────────────────\n\nexport type TabularFormat = \"csv\" | \"tsv\" | \"txt\" | \"xlsx\" | \"xls\" | \"ods\";\nconst WORKBOOK_FORMATS: ReadonlySet<string> = new Set([\"xlsx\", \"xls\", \"ods\", \"xlsm\", \"xlsb\"]);\nconst DELIMITED_FORMATS: ReadonlySet<string> = new Set([\"csv\", \"tsv\", \"txt\", \"tab\"]);\n\nexport type ReadFileOptions = DelimitedParseOptions & {\n /** The file's format; absent → from `filename` (or a File's name) extension. */\n format?: TabularFormat | (string & {});\n filename?: string;\n /** Workbooks: the grid shape (`sheet_to_json` header-row semantics). */\n grid?: WorkbookGridOptions;\n /** Workbooks: read options. */\n workbook?: WorkbookReadOptions;\n};\nexport type TabularSheet = { name: string; grid: unknown[][]; merges: WorkbookCellRange[] };\nexport type TabularFile = { format: TabularFormat; sheets: TabularSheet[]; errors: DelimitedParseError[]; delimiter?: string };\n\nexport class UnreadableFormatError extends Error {\n readonly format: string;\n constructor(format: string) {\n super(`A \"${format}\" file is not a table we can read. Choose a CSV, TSV, or Excel file.`);\n this.format = format;\n this.name = \"UnreadableFormatError\";\n }\n}\n\n/** The format a file name declares (lower-case extension), or \"\" when it has none. */\nexport function fileFormatOf(name: string | undefined): string {\n const m = /\\.([a-z0-9]+)$/i.exec(name ?? \"\");\n return m ? m[1]!.toLowerCase() : \"\";\n}\n\n/**\n * Read a table file — CSV/TSV/plain text through the delimited parser, XLSX/XLS/ODS through the\n * workbook engine — into sheets of grids (header row first). Delimited text is one sheet.\n */\nexport async function readFile(input: ReadInput, options: ReadFileOptions = {}): Promise<TabularFile> {\n const name = options.filename ?? (typeof Blob !== \"undefined\" && input instanceof Blob && \"name\" in input ? String((input as File).name) : undefined);\n const format = (options.format ?? fileFormatOf(name)) || (typeof input === \"string\" ? \"csv\" : \"\");\n if (WORKBOOK_FORMATS.has(format)) {\n const book = await readWorkbook(input, options.workbook);\n return {\n format: (format === \"xlsm\" || format === \"xlsb\" ? \"xlsx\" : format) as TabularFormat,\n sheets: book.sheets.map((s) => ({ name: s.name, grid: s.grid(options.grid), merges: s.merges })),\n errors: [],\n };\n }\n if (!DELIMITED_FORMATS.has(format)) throw new UnreadableFormatError(format || \"unknown\");\n const text = typeof input === \"string\" ? input : new TextDecoder(\"utf-8\").decode(await bytesOf(input));\n const parsed = parseDelimited(text, {\n ...options,\n header: false,\n ...(options.delimiter ? {} : format === \"tsv\" || format === \"tab\" ? { delimiter: \"\\t\" } : {}),\n } as DelimitedParseOptions & { header: false; dynamicTyping?: false });\n return {\n format: (format === \"tab\" ? \"tsv\" : format) as TabularFormat,\n sheets: [{ name: name?.replace(/\\.[^.]+$/, \"\") || \"Sheet1\", grid: parsed.data, merges: [] }],\n errors: parsed.errors,\n delimiter: parsed.meta.delimiter,\n };\n}\n"],"mappings":"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","names":["parseDelimited"]}
1
+ {"version":3,"sources":["../src/operate/read.ts"],"sourcesContent":["/**\n * `@ai-matrx/alchemy/operate/read` — the one parse door (ALC-19 T4–T12). Write has `buildFile`; read has `readFile`.\n *\n * One engine per format across read and write:\n * - CSV / TSV / delimited text: kit's `parseDelimited` (no library; it sits in `@ai-matrx/kit/delimited`\n * beside the one writer so packages below alchemy read through it too), re-exported here. `parseDelimited` is Papa Parse–compatible in the options the platform\n * uses (auto delimiter + line ending, quotes, `skipEmptyLines` true | \"greedy\", `header`,\n * `transformHeader`, `dynamicTyping`) and answers the same `{ data, errors, meta }` shape and\n * error codes, so a repointed importer keeps its behaviour.\n * - XLSX / XLS / ODS: SheetJS, the library the `xlsx` writer uses, loaded on first use from the\n * `/operate/formats/xlsx` leaf (`readWorkbook`). A caller that needs spreadsheet typing of a CSV\n * (dates, numbers, formulas as SheetJS reads them) reads it through `readWorkbook` too.\n */\n\n// Through the PUBLIC `/operate` subpath, so this entry shares the transfer core at runtime instead of bundling a copy.\nimport { createDraft, directSource, projectSnapshot, serialize, type Column, type Json } from \"@ai-matrx/alchemy/operate\";\n\n// ─── Delimited text ───────────────────────────────────────────────────────────────────────────────\n// THE one parser lives beside THE one writer in @ai-matrx/kit/delimited (AP-2: packages below\n// alchemy read CSV too); this door re-exports it unchanged, so `/operate/read` keeps its API.\nexport { parseDelimited } from \"@ai-matrx/kit/delimited\";\nexport type {\n DelimitedParseError,\n DelimitedParseOptions,\n ParsedDelimitedCell as DelimitedCell,\n DelimitedMeta,\n DelimitedResult,\n} from \"@ai-matrx/kit/delimited\";\nimport { parseDelimited, type DelimitedParseError, type DelimitedParseOptions } from \"@ai-matrx/kit/delimited\";\n\n/**\n * Delimited text from a header row + body rows, through the SAME `csv`/`tsv` serializer the\n * Alchemy menu's copy and download use (quoting, nested values as compact JSON, `null` empty).\n * `spreadsheetSafe` defaults ON (kit `spreadsheetSafeByDefault`: csv/tsv are for spreadsheets) and\n * prefixes formula-looking text with `'`; pass `false` only for a lossless round-trip or AI-read text.\n */\nexport function toDelimitedText(\n header: readonly string[],\n rows: readonly (readonly (Json | undefined)[] | Readonly<Record<string, Json | undefined>>)[],\n options: { format?: \"csv\" | \"tsv\"; spreadsheetSafe?: boolean } = {},\n): string {\n const columns: Column[] = header.map((label, i) => ({ id: `c${i}`, label, path: `/c${i}`, visible: true }));\n const record = (row: (typeof rows)[number]): Record<string, Json> => {\n const out: Record<string, Json> = {};\n header.forEach((label, i) => {\n const v = Array.isArray(row) ? (row as readonly (Json | undefined)[])[i] : (row as Readonly<Record<string, Json | undefined>>)[label];\n if (v !== undefined) out[`c${i}`] = v;\n });\n return out;\n };\n const captured = directSource({ kind: \"rows\", columns, rows: rows.map(record) });\n const draft = createDraft(projectSnapshot(captured.snapshot, captured.projection));\n return serialize(draft, options.format ?? \"csv\", options.spreadsheetSafe === undefined ? {} : { spreadsheetSafe: options.spreadsheetSafe }).plainText;\n}\n\n// ─── Workbooks (the SheetJS leaf, loaded on first use) ───────────────────────────────────────────\n\n// The workbook types and reader are print's (`@ai-matrx/print/xlsx`, architecture step 13).\nexport type {\n Workbook,\n WorkbookCell,\n WorkbookCellAddress,\n WorkbookCellJson,\n WorkbookCellRange,\n WorkbookGridOptions,\n WorkbookJson,\n WorkbookReadOptions,\n WorkbookRecordOptions,\n WorkbookSheet,\n ReadInput,\n} from \"@ai-matrx/print/xlsx\";\nimport type { ReadInput, Workbook, WorkbookCellRange, WorkbookGridOptions, WorkbookReadOptions } from \"@ai-matrx/print/xlsx\";\n\nasync function bytesOf(input: ReadInput): Promise<Uint8Array> {\n if (typeof input === \"string\") return new TextEncoder().encode(input);\n if (input instanceof Uint8Array) return input;\n if (input instanceof ArrayBuffer) return new Uint8Array(input);\n return new Uint8Array(await input.arrayBuffer());\n}\n\n/** Read a spreadsheet (XLSX, XLS, ODS; CSV/TSV with spreadsheet typing) through the one workbook engine (lazy). */\nexport async function readWorkbook(input: ReadInput, options: WorkbookReadOptions = {}): Promise<Workbook> {\n const engine = await import(\"@ai-matrx/alchemy/operate/formats/xlsx\");\n return engine.readWorkbookBytes(input, options);\n}\n\n// ─── readFile: the door ──────────────────────────────────────────────────────────────────────────\n\nexport type TabularFormat = \"csv\" | \"tsv\" | \"txt\" | \"xlsx\" | \"xls\" | \"ods\";\nconst WORKBOOK_FORMATS: ReadonlySet<string> = new Set([\"xlsx\", \"xls\", \"ods\", \"xlsm\", \"xlsb\"]);\nconst DELIMITED_FORMATS: ReadonlySet<string> = new Set([\"csv\", \"tsv\", \"txt\", \"tab\"]);\n\nexport type ReadFileOptions = DelimitedParseOptions & {\n /** The file's format; absent → from `filename` (or a File's name) extension. */\n format?: TabularFormat | (string & {});\n filename?: string;\n /** Workbooks: the grid shape (`sheet_to_json` header-row semantics). */\n grid?: WorkbookGridOptions;\n /** Workbooks: read options. */\n workbook?: WorkbookReadOptions;\n};\nexport type TabularSheet = { name: string; grid: unknown[][]; merges: WorkbookCellRange[] };\nexport type TabularFile = { format: TabularFormat; sheets: TabularSheet[]; errors: DelimitedParseError[]; delimiter?: string };\n\nexport class UnreadableFormatError extends Error {\n readonly format: string;\n constructor(format: string) {\n super(`A \"${format}\" file is not a table we can read. Choose a CSV, TSV, or Excel file.`);\n this.format = format;\n this.name = \"UnreadableFormatError\";\n }\n}\n\n/** The format a file name declares (lower-case extension), or \"\" when it has none. */\nexport function fileFormatOf(name: string | undefined): string {\n const m = /\\.([a-z0-9]+)$/i.exec(name ?? \"\");\n return m ? m[1]!.toLowerCase() : \"\";\n}\n\n/**\n * Read a table file — CSV/TSV/plain text through the delimited parser, XLSX/XLS/ODS through the\n * workbook engine — into sheets of grids (header row first). Delimited text is one sheet.\n */\nexport async function readFile(input: ReadInput, options: ReadFileOptions = {}): Promise<TabularFile> {\n const name = options.filename ?? (typeof Blob !== \"undefined\" && input instanceof Blob && \"name\" in input ? String((input as File).name) : undefined);\n const format = (options.format ?? fileFormatOf(name)) || (typeof input === \"string\" ? \"csv\" : \"\");\n if (WORKBOOK_FORMATS.has(format)) {\n const book = await readWorkbook(input, options.workbook);\n return {\n format: (format === \"xlsm\" || format === \"xlsb\" ? \"xlsx\" : format) as TabularFormat,\n sheets: book.sheets.map((s) => ({ name: s.name, grid: s.grid(options.grid), merges: s.merges })),\n errors: [],\n };\n }\n if (!DELIMITED_FORMATS.has(format)) throw new UnreadableFormatError(format || \"unknown\");\n const text = typeof input === \"string\" ? input : new TextDecoder(\"utf-8\").decode(await bytesOf(input));\n const parsed = parseDelimited(text, {\n ...options,\n header: false,\n ...(options.delimiter ? {} : format === \"tsv\" || format === \"tab\" ? { delimiter: \"\\t\" } : {}),\n } as DelimitedParseOptions & { header: false; dynamicTyping?: false });\n return {\n format: (format === \"tab\" ? \"tsv\" : format) as TabularFormat,\n sheets: [{ name: name?.replace(/\\.[^.]+$/, \"\") || \"Sheet1\", grid: parsed.data, merges: [] }],\n errors: parsed.errors,\n delimiter: parsed.meta.delimiter,\n };\n}\n"],"mappings":"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","names":["parseDelimited"]}