chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* 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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user