d25d482dc2
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
136 lines
3.6 KiB
TypeScript
136 lines
3.6 KiB
TypeScript
/**
|
|
* Table node parser — handles graphicFrame elements containing a:tbl.
|
|
*/
|
|
|
|
import { emuToPx } from '../../parser/units'
|
|
import type { SafeXmlNode } from '../../parser/xml-parser'
|
|
import { type BaseNodeData, parseBaseProps } from './base-node'
|
|
import { parseTextBody, type TextBody } from './shape-node'
|
|
|
|
export interface TableCell {
|
|
gridSpan: number
|
|
rowSpan: number
|
|
hMerge: boolean
|
|
vMerge: boolean
|
|
textBody?: TextBody
|
|
/** @internal Raw XML node — opaque to consumers. Use serializePresentation() for JSON-safe data. */
|
|
properties?: SafeXmlNode
|
|
}
|
|
|
|
interface TableRow {
|
|
height: number
|
|
cells: TableCell[]
|
|
}
|
|
|
|
export interface TableNodeData extends BaseNodeData {
|
|
nodeType: 'table'
|
|
columns: number[]
|
|
rows: TableRow[]
|
|
/** @internal Raw XML node — opaque to consumers. Use serializePresentation() for JSON-safe data. */
|
|
properties?: SafeXmlNode
|
|
tableStyleId?: string
|
|
}
|
|
|
|
/**
|
|
* Parse a single table cell (`a:tc`).
|
|
*/
|
|
function parseCell(tcNode: SafeXmlNode): TableCell {
|
|
const gridSpan = tcNode.numAttr('gridSpan') ?? 1
|
|
const rowSpan = tcNode.numAttr('rowSpan') ?? 1
|
|
const hMerge = tcNode.attr('hMerge') === '1' || tcNode.attr('hMerge') === 'true'
|
|
const vMerge = tcNode.attr('vMerge') === '1' || tcNode.attr('vMerge') === 'true'
|
|
|
|
// Cell text body
|
|
const txBody = tcNode.child('txBody')
|
|
const textBody = parseTextBody(txBody)
|
|
|
|
// Cell properties
|
|
const tcPr = tcNode.child('tcPr')
|
|
|
|
return {
|
|
gridSpan,
|
|
rowSpan,
|
|
hMerge,
|
|
vMerge,
|
|
textBody,
|
|
properties: tcPr.exists() ? tcPr : undefined,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse a table row (`a:tr`).
|
|
*/
|
|
function parseRow(trNode: SafeXmlNode): TableRow {
|
|
const height = emuToPx(trNode.numAttr('h') ?? 0)
|
|
const cells: TableCell[] = []
|
|
|
|
for (const tcNode of trNode.children('tc')) {
|
|
cells.push(parseCell(tcNode))
|
|
}
|
|
|
|
return { height, cells }
|
|
}
|
|
|
|
/**
|
|
* Locate the `a:tbl` element inside a graphicFrame.
|
|
* Path: `a:graphic > a:graphicData > a:tbl`
|
|
*/
|
|
function findTable(frameNode: SafeXmlNode): SafeXmlNode {
|
|
const graphic = frameNode.child('graphic')
|
|
const graphicData = graphic.child('graphicData')
|
|
return graphicData.child('tbl')
|
|
}
|
|
|
|
/**
|
|
* Extract the table style ID from tblPr.
|
|
* It can be in `a:tblStyle@val` or as a direct `tblStyle` attribute.
|
|
*/
|
|
function extractTableStyleId(tblPr: SafeXmlNode): string | undefined {
|
|
// Try <a:tableStyleId>{UUID}</a:tableStyleId> (most common in OOXML)
|
|
const tableStyleIdNode = tblPr.child('tableStyleId')
|
|
if (tableStyleIdNode.exists()) {
|
|
return tableStyleIdNode.text() || tableStyleIdNode.attr('val') || undefined
|
|
}
|
|
// Try <a:tblStyle val="{UUID}"/>
|
|
const tblStyleNode = tblPr.child('tblStyle')
|
|
if (tblStyleNode.exists()) {
|
|
return tblStyleNode.attr('val') ?? (tblStyleNode.text() || undefined)
|
|
}
|
|
// Try direct attribute
|
|
return tblPr.attr('tblStyle') ?? undefined
|
|
}
|
|
|
|
/**
|
|
* Parse a graphicFrame XML node containing a table into TableNodeData.
|
|
*/
|
|
export function parseTableNode(frameNode: SafeXmlNode): TableNodeData {
|
|
const base = parseBaseProps(frameNode)
|
|
const tbl = findTable(frameNode)
|
|
|
|
// --- Column widths ---
|
|
const tblGrid = tbl.child('tblGrid')
|
|
const columns: number[] = []
|
|
for (const gridCol of tblGrid.children('gridCol')) {
|
|
columns.push(emuToPx(gridCol.numAttr('w') ?? 0))
|
|
}
|
|
|
|
// --- Rows ---
|
|
const rows: TableRow[] = []
|
|
for (const trNode of tbl.children('tr')) {
|
|
rows.push(parseRow(trNode))
|
|
}
|
|
|
|
// --- Table properties ---
|
|
const tblPr = tbl.child('tblPr')
|
|
const tableStyleId = extractTableStyleId(tblPr)
|
|
|
|
return {
|
|
...base,
|
|
nodeType: 'table',
|
|
columns,
|
|
rows,
|
|
properties: tblPr.exists() ? tblPr : undefined,
|
|
tableStyleId,
|
|
}
|
|
}
|