inspect() JSON schema, version 1
inspect(input, options?) (and inspectFile(path, options?) from xlvane/node) returns plain JSON data describing a workbook. JSON.stringify of the result is lossless. The field schemaVersion changes only when a field is removed or changes meaning; new fields may be added within a version.
Options
| Option | Default | Meaning |
|---|---|---|
limits | see DEFAULT_READ_LIMITS | resource limits used while reading the file |
maxColumns | 200 | maximum number of columns described per sheet; columnsTruncated says whether more exist |
headerScanRows | 20 | number of leading non-empty rows searched for a header row |
formulaSamples | 10 | maximum number of example formulas per sheet |
Workbook
| Field | Type | Meaning |
|---|---|---|
schemaVersion | 1 | version of this schema |
format | "xlsx" | "xlsm" | "xltx" | "xltm" | "unknown" | from the content type of the workbook part |
conformance | "transitional" | "strict" | Office Open XML conformance class of the package |
dateSystem | "1900" | "1904" | date system used for serial dates |
hasMacros | boolean | the package contains a VBA project or Excel 4.0 macro sheets (never run) |
externalLinkCount | number | links to other workbooks (never followed) |
properties | object | document properties that are set (title, creator, created, …, from docProps/core.xml); all values are strings, dates as ISO 8601 in UTC ("2026-10-01T00:00:00.000Z"); {} when the file has none |
definedNames | { name, refersTo, sheet, hidden }[] | defined names in file order, at most 100; refersTo is the formula text without "=", cut to 100 characters; sheet is null for a workbook-level name; built-in names such as _xlnm._FilterDatabase are included |
definedNamesTruncated | boolean | the workbook has more than 100 defined names |
sheetCount | number | number of sheets |
sheets | array of sheet objects | in workbook order |
warnings | array of warning objects | see below |
Sheet
| Field | Type | Meaning |
|---|---|---|
name | string | sheet name |
index | number | 0-based position |
sheetId | number or null | the sheet's id in the file (sheet@sheetId), independent of its position; null when the file has none, an invalid one or a repeated one |
kind | "worksheet" | "chartsheet" | "dialogsheet" | "macrosheet" | only worksheets have cells |
state | "visible" | "hidden" | "veryHidden" | visibility |
dimension | string or null | range declared in the file, e.g. "A1:D20" |
usedRange | string or null | smallest range containing every cell with a value or formula; null for an empty sheet |
rowCount, columnCount | number | size of usedRange |
cellCount | number | cells with a value or formula |
formulaCount | number | cells with a formula |
mergedRanges | string[] | merged ranges, e.g. ["A1:D1"]; at most the first 100 |
mergedRangeCount | number | number of merged ranges on the sheet |
mergedRangesTruncated | boolean | true when mergedRanges lists only the first 100 |
headerRow | { row, confidence } or null | detected header row (1-based) and "high" or "low" confidence |
columns | array of column objects | one per column of usedRange, at most maxColumns |
columnsTruncated | boolean | usedRange has more columns than were described |
formulas | { cell, formula }[] | up to formulaSamples examples; formula is the text without "=" or null for cells that reuse a shared formula |
richTextCellCount | number | cells whose text has formatted runs (Cell.richText) |
richTextCells | string[] | up to ten of those cells |
styledColumns | string[] | columns with a default style (col@style, ColumnInfo.style), e.g. ["B", "D:F"]; at most maxColumns entries |
hyperlinkCount | number | hyperlinks of the sheet (Sheet.hyperlinks) |
hyperlinks | object[] | up to ten of them: ref, target (external URL or path as stored, or null), location (place in the workbook, or null); targets are never opened |
noteCount | number | notes (comments) of the sheet (Sheet.notes) |
imageCount | number | pictures of the sheet's drawing (Sheet.images); charts and shapes are not counted |
images | array | up to 10 pictures: cell of the top-left corner (null for an absolute position) and format (png, jpeg, gif, or null for other formats) |
notes | string[] | up to ten cells that have a note |
protected | boolean | the sheet is protected (Sheet.protection.sheet) |
printArea | string[] | null | the print area (Sheet.printArea), at most ten ranges |
pageBreakCount | number | manual page breaks, rows and columns together (Sheet.pageBreaks) |
dataValidationCount | number | data validation rules (Sheet.dataValidations) |
conditionalFormatCount | number | conditional formatting rules over all ranges (Sheet.conditionalFormats) |
tables | array | tables of the sheet (Sheet.tables): name (the name used in formulas), ref (header and totals rows included) and columns (column names); at most 20 tables and 50 columns each |
Header detection. Among the first headerScanRows non-empty rows, the header row is the first one in which:
- cells with a formula are left out (a total such as
=SUM(B3:B9)may sit next to the column names); - every other cell is non-blank text or a year: a whole number from 1900 to 2100 (
Region | 2023 | 2024). The years of the row must be consecutive, and in the next non-empty row at least one value below them must not be such a year, so that a data row with years (Alice | 1985) is not taken for a header; - at least one cell is text, and the cells cover at least half of the used width.
Repeated names are allowed; readTable gives the second one the key name_2, and so on. The confidence is "high" when the names are distinct and the next non-empty row contains a value that is not text (number, date, boolean or error), otherwise "low". A year used as a column name is reported as text in header ("2023"). This is a heuristic; check confidence before relying on it, or give the header row yourself (readTable(…, { header: 2 }), xlvane read --header 2).
Column
| Field | Type | Meaning |
|---|---|---|
index | number | 1-based column number |
letter | string | column letters, e.g. "C" |
header | string or null | text of the header cell, null without a header row |
dominantType | "number" | "string" | "date" | "boolean" | "error" | "empty" | most frequent non-empty type in the data rows (ties: number, string, date, boolean, error) |
types | { number, string, boolean, date, error, empty } | counts over the data rows: the rows below the header row (or all rows without one) down to the end of usedRange |
samples | array | up to three distinct example values from the data rows |
Values in samples are JSON-safe: numbers, booleans, strings (cut to 100 characters) and dates as ISO 8601 strings without a time zone, as in CSV: the date alone at midnight ("2024-01-31"), otherwise date and time ("2024-01-31T13:45:00", with .sss when there are milliseconds), because spreadsheet dates have no time zone. Error cells appear as their code, e.g. "#DIV/0!".
Warning
| Field | Type | Meaning |
|---|---|---|
code | string | XLV_W_* code, see docs/errors.md |
message | string | what was found and what xlvane did |
location | object | sheet and/or part where it applies |
count | number | number of occurrences (warnings are aggregated per sheet) |
cells | string[] (optional) | up to ten example cells |
Example
{
"schemaVersion": 1,
"format": "xlsx",
"conformance": "transitional",
"dateSystem": "1900",
"hasMacros": false,
"externalLinkCount": 0,
"properties": { "title": "Sales 2024", "creator": "Finance" },
"definedNames": [{ "name": "Total", "refersTo": "Sales!$C$3", "sheet": null, "hidden": false }],
"definedNamesTruncated": false,
"sheetCount": 1,
"sheets": [
{
"name": "Sales",
"index": 0,
"sheetId": 1,
"kind": "worksheet",
"state": "visible",
"dimension": "A1:C3",
"usedRange": "A1:C3",
"cellCount": 9,
"formulaCount": 1,
"mergedRanges": [],
"mergedRangeCount": 0,
"mergedRangesTruncated": false,
"formulas": [{ "cell": "C3", "formula": "SUM(C2:C2)" }],
"richTextCellCount": 0,
"richTextCells": [],
"styledColumns": [],
"hyperlinkCount": 0,
"hyperlinks": [],
"noteCount": 0,
"imageCount": 0,
"images": [],
"notes": [],
"protected": false,
"printArea": null,
"pageBreakCount": 0,
"dataValidationCount": 0,
"conditionalFormatCount": 0,
"tables": [],
"rowCount": 3,
"columnCount": 3,
"headerRow": { "row": 1, "confidence": "high" },
"columns": [
{ "index": 1, "letter": "A", "header": "Date", "dominantType": "date", "types": { "number": 0, "string": 0, "boolean": 0, "date": 2, "error": 0, "empty": 0 }, "samples": ["2024-01-31", "2024-02-01"] },
{ "index": 2, "letter": "B", "header": "Customer", "dominantType": "string", "types": { "number": 0, "string": 1, "boolean": 0, "date": 0, "error": 0, "empty": 1 }, "samples": ["ACME"] },
{ "index": 3, "letter": "C", "header": "Amount", "dominantType": "number", "types": { "number": 2, "string": 0, "boolean": 0, "date": 0, "error": 0, "empty": 0 }, "samples": [100.5] }
],
"columnsTruncated": false
}
],
"warnings": []
}Source: docs/inspect-json.md (version 1.2.2)