Skip to content

16. 틀 고정

특정 행/열을 고정하여 스크롤 시에도 보이도록 하는 기능을 다룹니다.

set_panes(sheet, cell) / setPanes(sheet, cell)

틀 고정을 설정합니다. 셀 참조는 스크롤 가능한 영역의 왼쪽 상단 셀을 나타냅니다.

Rust:

rust
// Freeze first row
wb.set_panes("Sheet1", "A2")?;

// Freeze first column
wb.set_panes("Sheet1", "B1")?;

// Freeze first row and first column
wb.set_panes("Sheet1", "B2")?;

TypeScript:

typescript
wb.setPanes("Sheet1", "A2");  // freeze row 1
wb.setPanes("Sheet1", "B1");  // freeze column A
wb.setPanes("Sheet1", "B2");  // freeze row 1 + column A

unset_panes(sheet) / unsetPanes(sheet)

틀 고정을 제거합니다.

Rust:

rust
wb.unset_panes("Sheet1")?;

TypeScript:

typescript
wb.unsetPanes("Sheet1");

get_panes(sheet) / getPanes(sheet)

현재 틀 고정 설정을 조회합니다. 설정이 없으면 None / null을 반환합니다.

Rust:

rust
if let Some(cell) = wb.get_panes("Sheet1")? {
    println!("Frozen at: {}", cell);  // e.g., "B2"
}

TypeScript:

typescript
const pane = wb.getPanes("Sheet1");
if (pane) {
    console.log(`Frozen at: ${pane}`);
}

17. 페이지 레이아웃

인쇄 관련 설정을 다룹니다. 여백, 용지 크기, 방향, 배율, 머리글/바닥글, 인쇄 옵션, 페이지 나누기를 포함합니다.

여백 (Margins)

set_page_margins / get_page_margins로 페이지 여백을 인치 단위로 설정하거나 조회합니다.

Rust:

rust
use sheetkit::page_layout::PageMarginsConfig;

wb.set_page_margins("Sheet1", &PageMarginsConfig {
    left: 0.7,
    right: 0.7,
    top: 0.75,
    bottom: 0.75,
    header: 0.3,
    footer: 0.3,
})?;

let margins = wb.get_page_margins("Sheet1")?;

TypeScript:

typescript
wb.setPageMargins("Sheet1", {
    left: 0.7,
    right: 0.7,
    top: 0.75,
    bottom: 0.75,
    header: 0.3,
    footer: 0.3,
});

const margins = wb.getPageMargins("Sheet1");

페이지 설정 (Page Setup)

용지 크기, 방향, 배율, 페이지 맞춤 설정을 다룹니다.

TypeScript:

typescript
wb.setPageSetup("Sheet1", {
    paperSize: "a4",
    orientation: "landscape",
    scale: 80,
    fitToWidth: 1,
    fitToHeight: 0,
});

const setup = wb.getPageSetup("Sheet1");

용지 크기 값: letter, tabloid, legal, a3, a4, a5, b4, b5

방향 값: portrait (세로), landscape (가로)

인쇄 옵션 (Print Options)

TypeScript:

typescript
wb.setPrintOptions("Sheet1", {
    gridLines: true,
    headings: true,
    horizontalCentered: true,
    verticalCentered: false,
});

const opts = wb.getPrintOptions("Sheet1");
속성타입설명
grid_lines / gridLinesbool? / boolean?눈금선 인쇄
headingsbool? / boolean?행/열 머리글 인쇄
horizontal_centered / horizontalCenteredbool? / boolean?가로 가운데 정렬
vertical_centered / verticalCenteredbool? / boolean?세로 가운데 정렬
typescript
wb.setHeaderFooter("Sheet1", "&LLeft Text&CCenter Text&RRight Text", "&CPage &P of &N");

const hf = wb.getHeaderFooter("Sheet1");
// hf.header, hf.footer

Excel 서식 코드: &L (왼쪽), &C (가운데), &R (오른쪽), &P (현재 페이지), &N (총 페이지 수)

페이지 나누기 (Page Breaks)

typescript
wb.insertPageBreak("Sheet1", 20);  // insert break before row 20
wb.insertPageBreak("Sheet1", 40);

const breaks: number[] = wb.getPageBreaks("Sheet1");
// [20, 40]

wb.removePageBreak("Sheet1", 20);

Rust:

rust
wb.insert_page_break("Sheet1", 20)?;
let breaks: Vec<u32> = wb.get_page_breaks("Sheet1")?;
wb.remove_page_break("Sheet1", 20)?;

18. 정의된 이름

워크북 내에서 셀 범위에 이름을 부여하는 기능을 다룹니다. 워크북 범위(모든 시트에서 사용 가능) 또는 시트 범위(특정 시트에서만 사용 가능)로 정의할 수 있습니다.

set_defined_name / setDefinedName

정의된 이름을 추가하거나 업데이트합니다. 동일한 이름과 범위를 가진 항목이 이미 존재하면 값과 주석이 업데이트됩니다(중복 생성 없음).

Rust:

rust
// Workbook-scoped name
wb.set_defined_name("SalesTotal", "Sheet1!$B$10", None, None)?;

// Sheet-scoped name with comment
wb.set_defined_name("LocalRange", "Sheet1!$A$1:$D$10", Some("Sheet1"), Some("Local data range"))?;

TypeScript:

typescript
// Workbook-scoped name
wb.setDefinedName({ name: "SalesTotal", value: "Sheet1!$B$10" });

// Sheet-scoped name with comment
wb.setDefinedName({
    name: "LocalRange",
    value: "Sheet1!$A$1:$D$10",
    scope: "Sheet1",
    comment: "Local data range",
});

get_defined_name / getDefinedName

이름과 선택적 범위로 정의된 이름을 조회합니다. 없으면 None/null을 반환합니다.

Rust:

rust
if let Some(info) = wb.get_defined_name("SalesTotal", None)? {
    println!("Refers to: {}", info.value);
}

// Sheet-scoped name
if let Some(info) = wb.get_defined_name("LocalRange", Some("Sheet1"))? {
    println!("Sheet-scoped: {}", info.value);
}

TypeScript:

typescript
const info = wb.getDefinedName("SalesTotal");
if (info) {
    console.log(`Refers to: ${info.value}`);
}

const local = wb.getDefinedName("LocalRange", "Sheet1");

get_all_defined_names / getDefinedNames

워크북의 모든 정의된 이름을 반환합니다.

Rust:

rust
let names = wb.get_all_defined_names();
for dn in &names {
    println!("{}: {} (scope: {:?})", dn.name, dn.value, dn.scope);
}

TypeScript:

typescript
const names = wb.getDefinedNames();
for (const dn of names) {
    console.log(`${dn.name}: ${dn.value} (scope: ${dn.scope ?? "workbook"})`);
}

delete_defined_name / deleteDefinedName

이름과 선택적 범위로 정의된 이름을 삭제합니다. 해당 이름이 없으면 오류를 반환합니다.

Rust:

rust
wb.delete_defined_name("SalesTotal", None)?;
wb.delete_defined_name("LocalRange", Some("Sheet1"))?;

TypeScript:

typescript
wb.deleteDefinedName("SalesTotal");
wb.deleteDefinedName("LocalRange", "Sheet1");

DefinedNameInfo

속성Rust 타입TypeScript 타입설명
nameStringstring정의된 이름
valueStringstring참조 또는 수식
scopeDefinedNameScopestring?시트 이름(시트 범위) 또는 None/undefined(워크북 범위)
commentOption<String>string?선택적 주석

정의된 이름에는 \ / ? * [ ] 문자를 사용할 수 없으며, 앞뒤 공백도 허용되지 않습니다.


19. 문서 속성

워크북의 메타데이터를 설정하고 조회하는 기능을 다룹니다. 핵심 속성, 앱 속성, 사용자 정의 속성의 세 가지 유형이 있습니다.

핵심 속성 (Core Properties)

제목, 작성자 등 표준 문서 메타데이터를 다룹니다.

Rust:

rust
use sheetkit::doc_props::DocProperties;

wb.set_doc_props(DocProperties {
    title: Some("Annual Report".into()),
    subject: Some("Financial Data".into()),
    creator: Some("Finance Team".into()),
    keywords: Some("finance, annual, 2024".into()),
    description: Some("Annual financial report".into()),
    last_modified_by: Some("Admin".into()),
    revision: Some("3".into()),
    created: Some("2024-01-01T00:00:00Z".into()),
    modified: Some("2024-06-15T10:30:00Z".into()),
    category: Some("Reports".into()),
    content_status: Some("Final".into()),
});

let props = wb.get_doc_props();

TypeScript:

typescript
wb.setDocProps({
    title: "Annual Report",
    subject: "Financial Data",
    creator: "Finance Team",
    keywords: "finance, annual, 2024",
    description: "Annual financial report",
    lastModifiedBy: "Admin",
    revision: "3",
    created: "2024-01-01T00:00:00Z",
    modified: "2024-06-15T10:30:00Z",
    category: "Reports",
    contentStatus: "Final",
});

const props = wb.getDocProps();

DocProperties 속성:

속성타입설명
titlestring?제목
subjectstring?주제
creatorstring?작성자
keywordsstring?키워드
descriptionstring?설명
last_modified_by / lastModifiedBystring?마지막 수정자
revisionstring?수정 번호
createdstring?생성 날짜 (ISO 8601)
modifiedstring?수정 날짜 (ISO 8601)
categorystring?분류
content_status / contentStatusstring?콘텐츠 상태

앱 속성 (App Properties)

애플리케이션 관련 메타데이터를 다룹니다.

Rust:

rust
use sheetkit::doc_props::AppProperties;

wb.set_app_props(AppProperties {
    application: Some("SheetKit".into()),
    doc_security: Some(0),
    company: Some("ACME Corp".into()),
    app_version: Some("1.0".into()),
    manager: Some("Department Lead".into()),
    template: None,
});

let app_props = wb.get_app_props();

TypeScript:

typescript
wb.setAppProps({
    application: "SheetKit",
    docSecurity: 0,
    company: "ACME Corp",
    appVersion: "1.0",
    manager: "Department Lead",
});

const appProps = wb.getAppProps();

AppProperties 속성:

속성타입설명
applicationstring?애플리케이션 이름
doc_security / docSecurityu32? / number?보안 수준
companystring?회사 이름
app_version / appVersionstring?앱 버전
managerstring?관리자
templatestring?템플릿

사용자 정의 속성 (Custom Properties)

키-값 쌍으로 사용자 정의 메타데이터를 저장합니다. 값은 문자열, 숫자, 불리언 타입을 지원합니다.

Rust:

rust
use sheetkit::doc_props::CustomPropertyValue;

wb.set_custom_property("Department", CustomPropertyValue::String("Engineering".into()));
wb.set_custom_property("Version", CustomPropertyValue::Int(3));
wb.set_custom_property("Approved", CustomPropertyValue::Bool(true));
wb.set_custom_property("Rating", CustomPropertyValue::Float(4.5));

let val = wb.get_custom_property("Department");
// Some(CustomPropertyValue::String("Engineering"))

let deleted = wb.delete_custom_property("Deprecated");
// true if existed

TypeScript:

typescript
wb.setCustomProperty("Department", "Engineering");
wb.setCustomProperty("Version", 3);
wb.setCustomProperty("Approved", true);
wb.setCustomProperty("Rating", 4.5);

const val = wb.getCustomProperty("Department");
// "Engineering"

const deleted: boolean = wb.deleteCustomProperty("Deprecated");

TypeScript에서 정수 값은 자동으로 Int로 변환되고, 소수점이 있는 숫자는 Float으로 저장됩니다.


20. 워크북 보호

워크북 구조(시트 추가/삭제/이름 변경)와 창 위치를 보호하는 기능을 다룹니다. 선택적으로 비밀번호를 설정할 수 있습니다.

protect_workbook(config) / protectWorkbook(config)

워크북 보호를 설정합니다.

Rust:

rust
use sheetkit::protection::WorkbookProtectionConfig;

wb.protect_workbook(WorkbookProtectionConfig {
    password: Some("secret123".into()),
    lock_structure: true,
    lock_windows: false,
    lock_revision: false,
});

TypeScript:

typescript
wb.protectWorkbook({
    password: "secret123",
    lockStructure: true,
    lockWindows: false,
    lockRevision: false,
});

unprotect_workbook() / unprotectWorkbook()

워크북 보호를 해제합니다.

Rust:

rust
wb.unprotect_workbook();

TypeScript:

typescript
wb.unprotectWorkbook();

is_workbook_protected() / isWorkbookProtected()

워크북이 보호되어 있는지 확인합니다.

Rust:

rust
let protected: bool = wb.is_workbook_protected();

TypeScript:

typescript
const isProtected: boolean = wb.isWorkbookProtected();

WorkbookProtectionConfig 속성

속성타입기본값설명
passwordstring?None보호 비밀번호 (레거시 해시로 저장)
lock_structure / lockStructurebool / boolean?false시트 추가/삭제/이름 변경 차단
lock_windows / lockWindowsbool / boolean?false창 위치/크기 변경 차단
lock_revision / lockRevisionbool / boolean?false수정 추적 잠금

비밀번호는 Excel의 레거시 16비트 해시 알고리즘으로 저장됩니다. 이 해시는 암호학적으로 안전하지 않습니다.


21. 시트 보호

개별 시트의 편집을 제한하는 기능을 다룹니다. 선택적으로 비밀번호를 설정하고 특정 작업을 허용할 수 있습니다.

protect_sheet / protectSheet

시트를 보호합니다. 모든 권한 불리언 값은 기본적으로 false(금지)이며, true로 설정하면 보호 상태에서도 해당 작업이 허용됩니다.

Rust:

rust
use sheetkit::sheet::SheetProtectionConfig;

wb.protect_sheet("Sheet1", &SheetProtectionConfig {
    password: Some("mypass".to_string()),
    format_cells: true,
    insert_rows: true,
    sort: true,
    ..SheetProtectionConfig::default()
})?;

TypeScript:

typescript
wb.protectSheet("Sheet1", {
    password: "mypass",
    formatCells: true,
    insertRows: true,
    sort: true,
});

// Protect with defaults (all actions forbidden, no password)
wb.protectSheet("Sheet1");

unprotect_sheet / unprotectSheet

시트 보호를 해제합니다.

Rust:

rust
wb.unprotect_sheet("Sheet1")?;

TypeScript:

typescript
wb.unprotectSheet("Sheet1");

is_sheet_protected / isSheetProtected

시트가 보호되어 있는지 확인합니다.

Rust:

rust
let protected: bool = wb.is_sheet_protected("Sheet1")?;

TypeScript:

typescript
const isProtected: boolean = wb.isSheetProtected("Sheet1");

SheetProtectionConfig 속성

속성Rust 타입TypeScript 타입기본값설명
passwordOption<String>string?None보호 비밀번호 (레거시 해시로 저장)
select_locked_cells / selectLockedCellsboolboolean?false잠긴 셀 선택 허용
select_unlocked_cells / selectUnlockedCellsboolboolean?false잠기지 않은 셀 선택 허용
format_cells / formatCellsboolboolean?false셀 서식 변경 허용
format_columns / formatColumnsboolboolean?false열 서식 변경 허용
format_rows / formatRowsboolboolean?false행 서식 변경 허용
insert_columns / insertColumnsboolboolean?false열 삽입 허용
insert_rows / insertRowsboolboolean?false행 삽입 허용
insert_hyperlinks / insertHyperlinksboolboolean?false하이퍼링크 삽입 허용
delete_columns / deleteColumnsboolboolean?false열 삭제 허용
delete_rows / deleteRowsboolboolean?false행 삭제 허용
sortboolboolean?false정렬 허용
auto_filter / autoFilterboolboolean?false자동 필터 사용 허용
pivot_tables / pivotTablesboolboolean?false피벗 테이블 사용 허용

비밀번호는 Excel의 레거시 16비트 해시 알고리즘으로 저장됩니다. 이 해시는 암호학적으로 안전하지 않습니다.


22. 수식 평가

셀 수식을 파싱하고 실행하는 기능을 다룹니다. nom 파서로 수식을 AST로 변환한 후 평가 엔진이 결과를 계산합니다.

set_cell_formula / setCellFormula

단일 셀에 수식을 설정합니다.

Rust:

rust
wb.set_cell_formula("Sheet1", "C1", "SUM(A1:B1)")?;

TypeScript:

typescript
wb.setCellFormula("Sheet1", "C1", "SUM(A1:B1)");

fill_formula / fillFormula

단일 열 범위에 수식을 채우며, 각 행에 맞게 행 참조를 자동으로 조정합니다. 절대 행 참조($1)는 조정되지 않습니다. 범위의 첫 번째 셀은 수식을 그대로 받고, 이후 셀들은 행 오프셋만큼 행 참조가 이동됩니다.

Rust:

rust
// D2 = SUM(A2:C2), D3 = SUM(A3:C3), ..., D10 = SUM(A10:C10)으로 설정
wb.fill_formula("Sheet1", "D2:D10", "SUM(A2:C2)")?;

// 절대 참조는 보존된다:
// E2 = $A$1*B2, E3 = $A$1*B3, E4 = $A$1*B4
wb.fill_formula("Sheet1", "E2:E4", "$A$1*B2")?;

TypeScript:

typescript
wb.fillFormula("Sheet1", "D2:D10", "SUM(A2:C2)");
wb.fillFormula("Sheet1", "E2:E4", "$A$1*B2");

단일 열 범위만 지원됩니다 (예: "D2:D10"). 다중 열 범위는 오류를 반환합니다.

evaluate_formula(sheet, formula) / evaluateFormula(sheet, formula)

주어진 시트 컨텍스트에서 수식 문자열을 평가하여 결과를 반환합니다. 워크북의 현재 셀 데이터를 참조할 수 있습니다.

Rust:

rust
wb.set_cell_value("Sheet1", "A1", CellValue::Number(10.0))?;
wb.set_cell_value("Sheet1", "A2", CellValue::Number(20.0))?;

let result = wb.evaluate_formula("Sheet1", "SUM(A1:A2)")?;
// CellValue::Number(30.0)

TypeScript:

typescript
wb.setCellValue("Sheet1", "A1", 10);
wb.setCellValue("Sheet1", "A2", 20);

const result = wb.evaluateFormula("Sheet1", "SUM(A1:A2)");
// 30

calculate_all() / calculateAll()

워크북의 모든 수식 셀을 재계산합니다. 의존성 그래프를 구축하고 위상 정렬을 수행하여 올바른 순서로 평가합니다.

Rust:

rust
wb.calculate_all()?;

TypeScript:

typescript
wb.calculateAll();

순환 참조가 발견되면 오류가 발생합니다. 최대 재귀 깊이는 256입니다.

지원 함수 목록 (164개, 10개 카테고리)

수학 함수 (Math) -- 20개

함수설명
SUM합계
PRODUCT
ABS절대값
INT정수 변환 (내림)
MOD나머지
POWER거듭제곱
SQRT제곱근
ROUND반올림
ROUNDUP올림
ROUNDDOWN내림
CEILING올림 (배수)
FLOOR내림 (배수)
SIGN부호
RAND난수 (0-1)
RANDBETWEEN정수 난수 (범위)
PI원주율
LOG로그
LOG10상용 로그
LN자연 로그
EXP지수 함수
QUOTIENT정수 몫
FACT팩토리얼
SUMIF조건부 합계
SUMIFS다중 조건부 합계

통계 함수 (Statistical) -- 16개

함수설명
AVERAGE평균
COUNT숫자 셀 개수
COUNTA비어 있지 않은 셀 개수
COUNTBLANK빈 셀 개수
COUNTIF조건부 개수
COUNTIFS다중 조건부 개수
MIN최소값
MAX최대값
MEDIAN중앙값
MODE최빈값
LARGEN번째 큰 값
SMALLN번째 작은 값
RANK순위
AVERAGEIF조건부 평균
AVERAGEIFS다중 조건부 평균

논리 함수 (Logical) -- 10개

함수설명
IF조건 분기
AND논리곱
OR논리합
NOT부정
XOR배타적 논리합
TRUETRUE 상수
FALSEFALSE 상수
IFERROR오류 시 대체값
IFNA#N/A 시 대체값
IFS다중 조건 분기
SWITCH값 기반 분기

텍스트 함수 (Text) -- 15개

함수설명
LEN문자열 길이
LOWER소문자 변환
UPPER대문자 변환
TRIM공백 제거
LEFT왼쪽 문자 추출
RIGHT오른쪽 문자 추출
MID중간 문자 추출
CONCATENATE문자열 연결
CONCAT문자열 연결 (최신)
FIND문자열 찾기 (대소문자 구분)
SEARCH문자열 찾기 (대소문자 무시)
SUBSTITUTE문자열 치환
REPLACE위치 기반 문자열 교체
REPT문자열 반복
EXACT완전 일치 비교
T텍스트 변환
PROPER단어 첫 글자 대문자

정보 함수 (Information) -- 11개

함수설명
ISNUMBER숫자 여부
ISTEXT텍스트 여부
ISBLANK빈 셀 여부
ISERROR오류 여부 (#N/A 포함)
ISERR오류 여부 (#N/A 제외)
ISNA#N/A 여부
ISLOGICAL논리값 여부
ISEVEN짝수 여부
ISODD홀수 여부
TYPE값 유형 번호
N숫자 변환
NA#N/A 생성
ERROR.TYPE오류 유형 번호

변환 함수 (Conversion) -- 2개

함수설명
VALUE텍스트를 숫자로 변환
TEXT값을 서식 문자열로 변환

날짜/시각 함수 (Date/Time) -- 17개

함수설명
DATE연/월/일로 날짜 생성
TODAY오늘 날짜
NOW현재 날짜 및 시각
YEAR연도 추출
MONTH월 추출
DAY일 추출
HOUR시 추출
MINUTE분 추출
SECOND초 추출
DATEDIF날짜 차이 계산
EDATEN개월 후 날짜
EOMONTHN개월 후 월말
DATEVALUE텍스트를 날짜로 변환
WEEKDAY요일 번호
WEEKNUM주차 번호
NETWORKDAYS근무일수 계산
WORKDAYN 근무일 후 날짜

찾기/참조 함수 (Lookup) -- 11개

함수설명
VLOOKUP세로 방향 조회
HLOOKUP가로 방향 조회
INDEX범위에서 값 추출
MATCH위치 찾기
LOOKUP벡터 조회
ROW행 번호
COLUMN열 번호
ROWS범위의 행 수
COLUMNS범위의 열 수
CHOOSE인덱스로 값 선택
ADDRESS셀 주소 문자열 생성

재무 함수 (Financial) -- 21개

함수설명
FV미래 가치
PV현재 가치
NPV순현재가치
IRR내부수익률
PMT정기 납입금
IPMT이자 부분
PPMT원금 부분
RATE이자율
NPER납입 횟수
DB정률법 감가상각
DDB이중 체감법 감가상각
SLN정액법 감가상각
SYD연수합계법 감가상각
EFFECT실효 이자율
NOMINAL명목 이자율
DOLLARDE분수 가격을 소수로 변환
DOLLARFR소수 가격을 분수로 변환
CUMIPMT누적 이자
CUMPRINC누적 원금
XNPV비정기 순현재가치
XIRR비정기 내부수익률

공학 함수 (Engineering) -- 33개

함수설명
BIN2DEC2진수를 10진수로 변환
BIN2HEX2진수를 16진수로 변환
BIN2OCT2진수를 8진수로 변환
DEC2BIN10진수를 2진수로 변환
DEC2HEX10진수를 16진수로 변환
DEC2OCT10진수를 8진수로 변환
HEX2BIN16진수를 2진수로 변환
HEX2DEC16진수를 10진수로 변환
HEX2OCT16진수를 8진수로 변환
OCT2BIN8진수를 2진수로 변환
OCT2DEC8진수를 10진수로 변환
OCT2HEX8진수를 16진수로 변환
DELTA두 값이 같은지 확인
GESTEP값이 임계값 이상인지 확인
ERF오차 함수
ERFC여오차 함수
COMPLEX복소수 생성
IMREAL복소수의 실수부
IMAGINARY복소수의 허수부
IMABS복소수의 절대값
IMARGUMENT복소수의 편각
IMCONJUGATE복소수의 켤레
IMSUM복소수 합
IMSUB복소수 차
IMPRODUCT복소수 곱
IMDIV복소수 나눗셈
IMPOWER복소수 거듭제곱
IMSQRT복소수 제곱근
CONVERT단위 변환
BESSELI수정 Bessel 함수 I
BESSELJBessel 함수 J
BESSELK수정 Bessel 함수 K
BESSELYBessel 함수 Y

23. 피벗 테이블

피벗 테이블을 생성, 조회, 삭제하는 기능을 다룹니다. 소스 데이터 범위로부터 행/열/데이터 필드를 지정하여 피벗 테이블을 구성합니다.

add_pivot_table(config) / addPivotTable(config)

피벗 테이블을 추가합니다.

Rust:

rust
use sheetkit::pivot::*;

wb.add_pivot_table(&PivotTableConfig {
    name: "SalesPivot".into(),
    source_sheet: "RawData".into(),
    source_range: "A1:D100".into(),
    target_sheet: "PivotSheet".into(),
    target_cell: "A3".into(),
    rows: vec![
        PivotField { name: "Region".into() },
        PivotField { name: "Product".into() },
    ],
    columns: vec![
        PivotField { name: "Quarter".into() },
    ],
    data: vec![
        PivotDataField {
            name: "Revenue".into(),
            function: AggregateFunction::Sum,
            display_name: Some("Total Revenue".into()),
        },
        PivotDataField {
            name: "Quantity".into(),
            function: AggregateFunction::Count,
            display_name: None,
        },
    ],
})?;

TypeScript:

typescript
wb.addPivotTable({
    name: "SalesPivot",
    sourceSheet: "RawData",
    sourceRange: "A1:D100",
    targetSheet: "PivotSheet",
    targetCell: "A3",
    rows: [
        { name: "Region" },
        { name: "Product" },
    ],
    columns: [
        { name: "Quarter" },
    ],
    data: [
        { name: "Revenue", function: "sum", displayName: "Total Revenue" },
        { name: "Quantity", function: "count" },
    ],
});

Node.js에서 data[].function은 지원되는 집계 함수(sum, count, average, max, min, product, countNums, stdDev, stdDevP, var, varP)만 허용되며, 지원되지 않는 값은 오류를 반환합니다.

get_pivot_tables() / getPivotTables()

워크북의 모든 피벗 테이블 정보를 반환합니다.

Rust:

rust
let tables = wb.get_pivot_tables();
for t in &tables {
    println!("{}: {}!{} -> {}!{}", t.name, t.source_sheet, t.source_range, t.target_sheet, t.location);
}

TypeScript:

typescript
const tables = wb.getPivotTables();
for (const t of tables) {
    console.log(`${t.name}: ${t.sourceSheet}!${t.sourceRange} -> ${t.targetSheet}!${t.location}`);
}

PivotTableInfo 구조:

속성타입설명
namestring피벗 테이블 이름
source_sheet / sourceSheetstring소스 데이터 시트 이름
source_range / sourceRangestring소스 데이터 범위
target_sheet / targetSheetstring대상 시트 이름
locationstring피벗 테이블 위치

delete_pivot_table(name) / deletePivotTable(name)

이름으로 피벗 테이블을 삭제합니다.

Rust:

rust
wb.delete_pivot_table("SalesPivot")?;

TypeScript:

typescript
wb.deletePivotTable("SalesPivot");

PivotTableConfig 구조

속성타입설명
namestring피벗 테이블 이름
source_sheet / sourceSheetstring소스 데이터가 있는 시트
source_range / sourceRangestring소스 데이터 범위 (예: "A1:D100")
target_sheet / targetSheetstring피벗 테이블을 배치할 시트
target_cell / targetCellstring피벗 테이블 시작 셀
rowsPivotField[]행 필드
columnsPivotField[]열 필드
dataPivotDataField[]데이터(값) 필드

AggregateFunction (집계 함수)

설명
sum합계
count개수
average평균
max최대값
min최소값
product
countNums숫자 개수
stdDev표준편차
stdDevP모표준편차
var분산
varP모분산

24. 스트림 라이터

대용량 데이터를 메모리 효율적으로 쓰기 위한 스트리밍 API입니다. 행은 오름차순으로만 쓸 수 있으며, 전체 워크시트 XML을 메모리에 구축하지 않고 직접 버퍼에 기록합니다.

사용 흐름

  1. new_stream_writer로 스트림 라이터 생성
  2. 열 너비, 셀 병합 등 설정
  3. write_row로 행 데이터를 순서대로 기록
  4. apply_stream_writer로 워크북에 적용

Rust:

rust
use sheetkit::cell::CellValue;

let mut sw = wb.new_stream_writer("LargeData")?;

// Set column widths
sw.set_col_width(1, 15.0)?;   // Column A
sw.set_col_width(2, 20.0)?;   // Column B

// Add merge cells
sw.add_merge_cell("A1:B1")?;

// Write header row
sw.write_row(1, &[
    CellValue::from("Name"),
    CellValue::from("Value"),
])?;

// Write data rows (must be in ascending order)
for i in 2..=10000 {
    sw.write_row(i, &[
        CellValue::from(format!("Item {}", i - 1)),
        CellValue::Number(i as f64 * 1.5),
    ])?;
}

// Apply to workbook
let sheet_index = wb.apply_stream_writer(sw)?;
wb.save("large_data.xlsx")?;

TypeScript:

typescript
const sw = wb.newStreamWriter("LargeData");

// Set column widths
sw.setColWidth(1, 15);   // Column A
sw.setColWidth(2, 20);   // Column B

// Set width for a range of columns
sw.setColWidthRange(3, 10, 12);  // Columns C-J

// Add merge cells
sw.addMergeCell("A1:B1");

// Write header row
sw.writeRow(1, ["Name", "Value"]);

// Write data rows
for (let i = 2; i <= 10000; i++) {
    sw.writeRow(i, [`Item ${i - 1}`, i * 1.5]);
}

// Apply to workbook
const sheetIndex: number = wb.applyStreamWriter(sw);
await wb.save("large_data.xlsx");

StreamWriter API

new_stream_writer(sheet_name) / newStreamWriter(sheetName)

새 시트를 위한 스트림 라이터를 생성합니다.

write_row(row, values) / writeRow(row, values)

행 데이터를 기록합니다. 행 번호는 1부터 시작하며 반드시 오름차순이어야 합니다.

set_col_width(col, width) / setColWidth(col, width)

열 너비를 설정합니다. col은 1부터 시작하는 열 번호입니다.

set_col_width_range(min_col, max_col, width) / setColWidthRange(minCol, maxCol, width)

열 범위의 너비를 한 번에 설정합니다.

add_merge_cell(reference) / addMergeCell(reference)

셀 병합을 추가합니다 (예: "A1:C3").

apply_stream_writer(writer) / applyStreamWriter(writer)

스트림 라이터의 결과를 워크북에 적용합니다. 시트 인덱스를 반환합니다. 적용 후 스트림 라이터는 소비(consumed)되어 더 이상 사용할 수 없습니다.

StreamRowOptions (Rust 전용)

Rust에서는 write_row_with_options를 사용하여 행별 옵션을 지정할 수 있습니다.

속성타입설명
heightOption<f64>행 높이 (포인트)
visibleOption<bool>행 표시 여부
outline_levelOption<u8>아웃라인 수준 (0-7)
style_idOption<u32>행 스타일 ID

25. 유틸리티 함수

셀 참조 변환에 사용되는 유틸리티 함수들입니다. Rust에서는 sheetkit_core::utils::cell_ref 모듈에서 제공합니다.

cell_name_to_coordinates

A1 형식의 셀 참조를 (열, 행) 좌표로 변환합니다. 열과 행 모두 1부터 시작합니다.

Rust:

rust
use sheetkit_core::utils::cell_ref::cell_name_to_coordinates;

let (col, row) = cell_name_to_coordinates("B3")?;
// col = 2, row = 3

let (col, row) = cell_name_to_coordinates("$AB$100")?;
// col = 28, row = 100 (absolute references are supported)

coordinates_to_cell_name

(열, 행) 좌표를 A1 형식의 셀 참조로 변환합니다.

Rust:

rust
use sheetkit_core::utils::cell_ref::coordinates_to_cell_name;

let name = coordinates_to_cell_name(2, 3)?;
// "B3"

let name = coordinates_to_cell_name(28, 100)?;
// "AB100"

column_name_to_number

열 이름을 1부터 시작하는 열 번호로 변환합니다.

Rust:

rust
use sheetkit_core::utils::cell_ref::column_name_to_number;

assert_eq!(column_name_to_number("A")?, 1);
assert_eq!(column_name_to_number("Z")?, 26);
assert_eq!(column_name_to_number("AA")?, 27);
assert_eq!(column_name_to_number("XFD")?, 16384);  // maximum column

column_number_to_name

1부터 시작하는 열 번호를 열 이름으로 변환합니다.

Rust:

rust
use sheetkit_core::utils::cell_ref::column_number_to_name;

assert_eq!(column_number_to_name(1)?, "A");
assert_eq!(column_number_to_name(26)?, "Z");
assert_eq!(column_number_to_name(27)?, "AA");
assert_eq!(column_number_to_name(16384)?, "XFD");

유틸리티 함수는 현재 Rust 전용으로 제공됩니다. TypeScript에서는 문자열 기반 셀 참조("A1", "B2" 등)를 직접 사용합니다.

is_date_num_fmt(num_fmt_id) (Rust 전용)

내장 숫자 서식 ID가 날짜/시간 서식인지 확인합니다. ID 14-22 및 45-47에 대해 true를 반환합니다.

rust
use sheetkit::is_date_num_fmt;

assert!(is_date_num_fmt(14));   // m/d/yyyy
assert!(is_date_num_fmt(22));   // m/d/yyyy h:mm
assert!(!is_date_num_fmt(0));   // General
assert!(!is_date_num_fmt(49));  // @

is_date_format_code(code) (Rust 전용)

사용자 정의 숫자 서식 문자열이 날짜/시간 서식인지 확인합니다. 따옴표로 감싸진 문자열과 이스케이프된 문자를 제외하고, 서식 코드에 날짜/시간 토큰(y, m, d, h, s)이 포함되어 있으면 true를 반환합니다.

rust
use sheetkit::is_date_format_code;

assert!(is_date_format_code("yyyy-mm-dd"));
assert!(is_date_format_code("h:mm:ss AM/PM"));
assert!(!is_date_format_code("#,##0.00"));
assert!(!is_date_format_code("0%"));

부록: 제한 사항

항목제한
최대 열 수16,384 (XFD)
최대 행 수1,048,576
최대 셀 문자 수32,767
최대 행 높이409 포인트
최대 아웃라인 수준7
최대 스타일 XF 수65,430
수식 최대 재귀 깊이256
지원 수식 함수 수164 / 456

26. 스파크라인

스파크라인은 워크시트 셀에 삽입되는 미니 차트입니다. SheetKit은 Line, Column, Win/Loss 세 가지 스파크라인 유형을 지원합니다. Excel은 36가지 스타일 프리셋(인덱스 0-35)을 정의합니다.

스파크라인은 OOXML 패키지의 x14 워크시트 확장으로 저장되며 저장/열기 라운드트립을 통해 보존됩니다.

타입

SparklineType (Rust) / sparklineType (TypeScript)

RustTypeScriptOOXML
LineSparklineType::Line"line"(default, omitted)
ColumnSparklineType::Column"column""column"
Win/LossSparklineType::WinLoss"winloss" or "stacked""stacked"

SparklineConfig (Rust)

rust
use sheetkit::SparklineConfig;

let config = SparklineConfig::new("Sheet1!A1:A10", "B1");

필드:

필드타입기본값설명
data_rangeString(필수)데이터 소스 범위 (예: "Sheet1!A1:A10")
locationString(필수)스파크라인이 렌더링되는 셀 (예: "B1")
sparkline_typeSparklineTypeLine스파크라인 차트 유형
markersboolfalse데이터 마커 표시
high_pointboolfalse최고점 강조
low_pointboolfalse최저점 강조
first_pointboolfalse첫 번째 점 강조
last_pointboolfalse마지막 점 강조
negative_pointsboolfalse음수 값 강조
show_axisboolfalse가로축 표시
line_weightOption<f64>None선 두께 (포인트)
styleOption<u32>None스타일 프리셋 인덱스 (0-35)

JsSparklineConfig (TypeScript)

typescript
const config = {
  dataRange: 'Sheet1!A1:A10',
  location: 'B1',
  sparklineType: 'line',    // "line" | "column" | "winloss" | "stacked"
  markers: true,
  highPoint: false,
  lowPoint: false,
  firstPoint: false,
  lastPoint: false,
  negativePoints: false,
  showAxis: false,
  lineWeight: 0.75,
  style: 1,
};

Workbook.addSparkline / Workbook::add_sparkline

워크시트에 스파크라인을 추가합니다.

Rust:

rust
use sheetkit::{Workbook, SparklineConfig, SparklineType};

let mut wb = Workbook::new();

let mut config = SparklineConfig::new("Sheet1!A1:A10", "B1");
config.sparkline_type = SparklineType::Column;
config.markers = true;
config.high_point = true;

wb.add_sparkline("Sheet1", &config).unwrap();

TypeScript:

typescript
import { Workbook } from '@sheetkit/node';

const wb = new Workbook();
wb.addSparkline('Sheet1', {
  dataRange: 'Sheet1!A1:A10',
  location: 'B1',
  sparklineType: 'column',
  markers: true,
  highPoint: true,
});

Workbook.getSparklines / Workbook::get_sparklines

워크시트의 모든 스파크라인을 조회합니다.

Rust:

rust
let sparklines = wb.get_sparklines("Sheet1").unwrap();
for s in &sparklines {
    println!("{} -> {}", s.data_range, s.location);
}

TypeScript:

typescript
const sparklines = wb.getSparklines('Sheet1');
for (const s of sparklines) {
  console.log(`${s.dataRange} -> ${s.location}`);
}

Workbook.removeSparkline / Workbook::remove_sparkline

위치 셀 참조로 스파크라인을 제거합니다.

Rust:

rust
wb.remove_sparkline("Sheet1", "B1").unwrap();

TypeScript:

typescript
wb.removeSparkline('Sheet1', 'B1');

유효성 검사

validate_sparkline_config 함수(Rust)는 다음을 확인합니다:

  • data_range가 비어 있지 않음
  • location이 비어 있지 않음
  • line_weight(설정된 경우) 양수 여부
  • style(설정된 경우) 0-35 범위 내 여부

add_sparkline 호출 시 유효성 검사가 자동으로 적용됩니다.

rust
use sheetkit_core::sparkline::{SparklineConfig, validate_sparkline_config};

let config = SparklineConfig::new("Sheet1!A1:A10", "B1");
validate_sparkline_config(&config).unwrap(); // Ok

27. 테마 색상

테마 색상 슬롯(dk1, lt1, dk2, lt2, accent1-6, hlink, folHlink)을 선택적 틴트 값과 함께 조회합니다.

Workbook.getThemeColor (Node.js) / Workbook::get_theme_color (Rust)

ParameterTypeDescription
indexu32 / numberTheme color index (0-11)
tintOption<f64> / number | nullTint value: positive lightens, negative darkens

Returns: ARGB hex string (e.g. "FF4472C4") or None/null if out of range.

Theme Color Indices:

IndexSlot NameDefault Color
0dk1FF000000
1lt1FFFFFFFF
2dk2FF44546A
3lt2FFE7E6E6
4accent1FF4472C4
5accent2FFED7D31
6accent3FFA5A5A5
7accent4FFFFC000
8accent5FF5B9BD5
9accent6FF70AD47
10hlinkFF0563C1
11folHlinkFF954F72

Node.js

javascript
const wb = new Workbook();

// Get accent1 color (no tint)
const color = wb.getThemeColor(4, null); // "FF4472C4"

// Lighten black by 50%
const lightened = wb.getThemeColor(0, 0.5); // "FF7F7F7F"

// Darken white by 50%
const darkened = wb.getThemeColor(1, -0.5); // "FF7F7F7F"

// Out of range returns null
const invalid = wb.getThemeColor(99, null); // null

Rust

rust
let wb = Workbook::new();

// Get accent1 color (no tint)
let color = wb.get_theme_color(4, None); // Some("FF4472C4")

// Apply tint
let tinted = wb.get_theme_color(0, Some(0.5)); // Some("FF7F7F7F")

Gradient Fill

FillStyle type supports gradient fills via the gradient field.

Types

rust
pub struct GradientFillStyle {
    pub gradient_type: GradientType, // Linear or Path
    pub degree: Option<f64>,         // Rotation angle for linear gradients
    pub left: Option<f64>,           // Path gradient coordinates (0.0-1.0)
    pub right: Option<f64>,
    pub top: Option<f64>,
    pub bottom: Option<f64>,
    pub stops: Vec<GradientStop>,    // Color stops
}

pub struct GradientStop {
    pub position: f64,     // Position (0.0-1.0)
    pub color: StyleColor, // Color at this stop
}

pub enum GradientType {
    Linear,
    Path,
}

Rust Example

rust
use sheetkit::*;

let mut wb = Workbook::new();
let style_id = wb.add_style(&Style {
    fill: Some(FillStyle {
        pattern: PatternType::None,
        fg_color: None,
        bg_color: None,
        gradient: Some(GradientFillStyle {
            gradient_type: GradientType::Linear,
            degree: Some(90.0),
            left: None,
            right: None,
            top: None,
            bottom: None,
            stops: vec![
                GradientStop {
                    position: 0.0,
                    color: StyleColor::Rgb("FFFFFFFF".to_string()),
                },
                GradientStop {
                    position: 1.0,
                    color: StyleColor::Rgb("FF4472C4".to_string()),
                },
            ],
        }),
    }),
    ..Style::default()
})?;

28. 서식 있는 텍스트

서식 있는 텍스트(Rich Text)를 사용하면 하나의 셀에 글꼴, 크기, 굵게, 기울임, 색상 등 서로 다른 서식을 가진 여러 텍스트 조각(run)을 넣을 수 있습니다.

RichTextRun 타입

각 run은 RichTextRun으로 기술됩니다.

Rust:

rust
pub struct RichTextRun {
    pub text: String,
    pub font: Option<String>,
    pub size: Option<f64>,
    pub bold: bool,
    pub italic: bool,
    pub color: Option<String>,
}

TypeScript:

typescript
interface RichTextRun {
  text: string;
  font?: string;
  size?: number;
  bold?: boolean;
  italic?: boolean;
  color?: string;  // RGB hex string, e.g. "#FF0000"
}

set_cell_rich_text / setCellRichText

셀에 여러 서식 run으로 구성된 서식 있는 텍스트를 설정합니다.

Rust:

rust
use sheetkit::{Workbook, RichTextRun};

let mut wb = Workbook::new();
let runs = vec![
    RichTextRun {
        text: "Bold text".to_string(),
        font: Some("Arial".to_string()),
        size: Some(14.0),
        bold: true,
        italic: false,
        color: Some("#FF0000".to_string()),
    },
    RichTextRun {
        text: " normal text".to_string(),
        font: None,
        size: None,
        bold: false,
        italic: false,
        color: None,
    },
];
wb.set_cell_rich_text("Sheet1", "A1", runs)?;

TypeScript:

typescript
const wb = new Workbook();
wb.setCellRichText("Sheet1", "A1", [
  { text: "Bold text", font: "Arial", size: 14, bold: true, color: "#FF0000" },
  { text: " normal text" },
]);

get_cell_rich_text / getCellRichText

셀의 서식 있는 텍스트 run을 가져옵니다. 서식 있는 텍스트가 아닌 셀은 None/null을 반환합니다.

Rust:

rust
let runs = wb.get_cell_rich_text("Sheet1", "A1")?;
if let Some(runs) = runs {
    for run in &runs {
        println!("Text: {:?}, Bold: {}", run.text, run.bold);
    }
}

TypeScript:

typescript
const runs = wb.getCellRichText("Sheet1", "A1");
if (runs) {
  for (const run of runs) {
    console.log(`Text: ${run.text}, Bold: ${run.bold ?? false}`);
  }
}

CellValue::RichString (Rust 전용)

서식 있는 텍스트 셀은 CellValue::RichString(Vec<RichTextRun>) variant를 사용합니다. get_cell_value로 읽으면 모든 run의 텍스트가 연결된 문자열로 표시됩니다.

rust
match wb.get_cell_value("Sheet1", "A1")? {
    CellValue::RichString(runs) => {
        println!("Rich text with {} runs", runs.len());
    }
    _ => {}
}

rich_text_to_plain

서식 있는 텍스트 run 슬라이스에서 연결된 일반 텍스트를 추출하는 유틸리티 함수입니다.

Rust:

rust
use sheetkit::rich_text_to_plain;

let plain = rich_text_to_plain(&runs);

29. 파일 암호화

파일 수준 암호화는 전체 .xlsx 파일을 비밀번호로 보호합니다. 암호화된 파일은 일반 ZIP 아카이브가 아닌 OLE/CFB 복합 컨테이너를 사용합니다. SheetKit은 다음을 지원합니다:

  • 복호화: Standard Encryption (Office 2007, AES-128-ECB + SHA-1) 및 Agile Encryption (Office 2010+, AES-256-CBC + SHA-512)
  • 암호화: Agile Encryption (AES-256-CBC + SHA-512, 100,000회 반복)

Rust에서는 encryption feature가 필요합니다: sheetkit = { features = ["encryption"] }. Node.js 바인딩에는 항상 암호화 지원이 포함됩니다.

open_with_password(path, password) / openWithPasswordSync(path, password)

주어진 비밀번호로 암호화된 .xlsx 파일을 엽니다. 비밀번호가 틀리거나 지원하지 않는 암호화 방식이면 에러를 반환합니다.

Rust:

rust
let wb = Workbook::open_with_password("encrypted.xlsx", "secret")?;

TypeScript:

typescript
// 동기
const wb = Workbook.openWithPasswordSync("encrypted.xlsx", "secret");

// 비동기
const wb2 = await Workbook.openWithPassword("encrypted.xlsx", "secret");

save_with_password(path, password) / saveWithPassword(path, password)

Agile Encryption을 사용하여 워크북을 암호화된 .xlsx 파일로 저장합니다.

Rust:

rust
wb.save_with_password("encrypted.xlsx", "secret")?;

TypeScript:

typescript
// 동기
wb.saveWithPassword("encrypted.xlsx", "secret");

// 비동기
await wb.saveWithPassword("encrypted.xlsx", "secret");

에러 타입

에러RustTypeScript설명
파일 암호화됨Error::FileEncrypted에러 메시지: "file is encrypted, password required"open()으로 암호화된 파일을 열 때 반환
잘못된 비밀번호Error::IncorrectPassword에러 메시지: "incorrect password"open_with_password()에 잘못된 비밀번호 전달 시 반환
미지원 방식Error::UnsupportedEncryption(String)에러 메시지: "unsupported encryption method: ..."지원하지 않는 암호화 버전

암호화된 파일 감지

open()이 암호화된 파일을 만나면 파싱을 시도하지 않고 Error::FileEncrypted를 반환합니다. 이런 파일을 열려면 open_with_password()를 사용합니다.

Rust:

rust
match Workbook::open("file.xlsx") {
    Ok(wb) => { /* 암호화되지 않은 파일 */ }
    Err(sheetkit::Error::FileEncrypted) => {
        let wb = Workbook::open_with_password("file.xlsx", "password")?;
    }
    Err(e) => return Err(e),
}

TypeScript:

typescript
try {
  const wb = Workbook.openSync("file.xlsx");
} catch (e) {
  if (e instanceof Error && e.message.includes("encrypted")) {
    const wb = Workbook.openWithPasswordSync("file.xlsx", "password");
  }
}

암호화 상세 사양

항목
알고리즘AES-256-CBC
해시SHA-512
키 유도 반복 횟수100,000
세그먼트 크기4,096 bytes
데이터 무결성HMAC-SHA512
컨테이너 형식OLE/CFB (Compound File Binary)

30. 대량 데이터 전송

SheetKit은 Node.js 바인딩에서 시트 데이터를 읽기 위한 세 가지 접근 방식을 제공하며, 각각 메모리와 성능 특성이 다릅니다. 세 가지 모두 내부적으로 동일한 바이너리 Buffer 프로토콜을 사용합니다.

getRows(sheet) (TypeScript 전용)

셀 데이터를 기존 JsRowData[] 형식으로 반환합니다. 바이너리 Buffer가 투명하게 디코딩되므로 반환 타입은 이전 버전과 하위 호환됩니다. 각 행은 열 이름, 타입, 값을 가진 셀 객체 배열을 포함합니다.

typescript
const rows = wb.getRows('Sheet1');
for (const row of rows) {
  for (const cell of row.cells) {
    console.log(`${cell.column}: ${cell.value ?? cell.numberValue ?? cell.boolValue}`);
  }
}

가장 단순한 API로 기존 코드를 변경할 필요가 없습니다. Buffer 전송은 이전의 셀별 napi 객체 생성에 따른 FFI 오버헤드를 제거하지만, 디코더가 여전히 모든 셀에 대해 JS 객체를 생성합니다.

getRowsBuffer(sheet) (TypeScript 전용)

Rust에서 생성된 raw 바이너리 Buffer를 반환합니다. 가장 저수준 API이며, 커스텀 디코더에 데이터를 전달하거나, 네트워크로 전송하거나, SheetData 클래스와 함께 지연 접근에 사용할 때 유용합니다.

typescript
const buf: Buffer = wb.getRowsBuffer('Sheet1');

Buffer는 아키텍처 문서에 기술된 SKRD 바이너리 형식을 따릅니다.

SheetData 클래스 (TypeScript 전용)

SheetData 클래스는 raw Buffer를 래핑하여 전체 시트를 디코딩하지 않고도 개별 셀이나 행에 O(1) 임의 접근을 제공합니다. @sheetkit/node/sheet-data에서 임포트합니다.

typescript
import { SheetData } from '@sheetkit/node/sheet-data';

const buf = wb.getRowsBuffer('Sheet1');
const sheet = new SheetData(buf);

속성:

속성타입설명
rowCountnumberBuffer 내 행 수
colCountnumber열 수 (경계 사각형 너비)

메서드:

getCell(row, col)

단일 셀의 디코딩된 값을 반환하며, 비어 있으면 null을 반환합니다. 행과 열은 1부터 시작합니다. 반환 타입은 셀 타입에 따라 달라집니다: 숫자 및 날짜 셀은 number, 문자열/에러/수식 셀은 string, 불리언 셀은 boolean.

typescript
const value = sheet.getCell(1, 1);   // 1행, 1열 (A1)
const price = sheet.getCell(5, 3);   // 5행, 3열 (C5)

getCellType(row, col)

셀의 타입 이름을 문자열로 반환합니다: 'empty', 'number', 'string', 'boolean', 'date', 'error', 'formula', 또는 'string' (서식 있는 텍스트).

typescript
const type = sheet.getCellType(1, 1);  // 'string'
if (type === 'number') {
  const val = sheet.getCell(1, 1);
}

getRow(rowNum)

단일 행의 디코딩된 값 배열을 반환합니다. 빈 셀은 null입니다. 행 번호는 1부터 시작합니다.

typescript
const row = sheet.getRow(1);  // [value, value, null, value, ...]

toArray()

모든 행을 디코딩하여 2차원 배열을 반환합니다. 각 요소는 빈 행이면 []이고, 그 외에는 빈 셀이 null인 값 배열입니다.

typescript
const data = sheet.toArray();
for (const row of data) {
  console.log(row);
}

rows() (제너레이터)

빈 행을 포함하여 각 행에 대해 { row: number, values: Array } 객체를 yield합니다. 스트리밍 방식의 반복에 유용합니다.

typescript
for (const { row, values } of sheet.rows()) {
  console.log(`Row ${row}:`, values);
}

columnName(colIndex)

0 기반 열 인덱스 (Buffer의 경계 사각형 기준)를 Excel 열 이름으로 변환합니다.

typescript
sheet.columnName(0);   // 'A' (데이터가 A열에서 시작하는 경우)
sheet.columnName(25);  // 'Z'

API 사용 시기

API메모리지연 시간적합한 경우
getRows()중간 (모든 셀을 객체로 디코딩)전체를 한 번에하위 호환성, 모든 셀 순회
getRowsBuffer() + SheetData낮음 (Buffer + 필요 시 디코딩)접근 시마다대용량 시트, 임의 접근, 셀 일부만 읽기
getRowsBuffer() (raw)최소 (Buffer만)없음커스텀 디코더, 네트워크 전송, 캐싱

31. 시트 보기 옵션

시트 보기 옵션은 Excel UI에서 워크시트가 표시되는 방식을 제어합니다. 눈금선, 수식 표시, 확대/축소 수준, 보기 모드, 스크롤 위치 등을 포함합니다.

set_sheet_view_options(sheet, options) / setSheetViewOptions(sheet, options)

시트의 표시 옵션을 설정합니다. None/undefined가 아닌 필드만 적용되며 나머지 설정은 보존됩니다.

Rust:

rust
use sheetkit::sheet::{SheetViewOptions, ViewMode};

wb.set_sheet_view_options("Sheet1", &SheetViewOptions {
    show_gridlines: Some(false),
    show_formulas: Some(true),
    zoom_scale: Some(150),
    view_mode: Some(ViewMode::PageBreak),
    top_left_cell: Some("C10".to_string()),
    ..Default::default()
})?;

TypeScript:

typescript
wb.setSheetViewOptions("Sheet1", {
    showGridlines: false,
    showFormulas: true,
    zoomScale: 150,
    viewMode: "pageBreak",
    topLeftCell: "C10",
});

get_sheet_view_options(sheet) / getSheetViewOptions(sheet)

현재 시트 보기 표시 옵션을 반환합니다.

Rust:

rust
let opts = wb.get_sheet_view_options("Sheet1")?;
println!("Zoom: {:?}", opts.zoom_scale);

TypeScript:

typescript
const opts = wb.getSheetViewOptions("Sheet1");
console.log("Zoom:", opts.zoomScale);

SheetViewOptions

필드Rust 타입TS 타입설명
show_gridlines / showGridlinesOption<bool>boolean?눈금선 표시 (기본값: true)
show_formulas / showFormulasOption<bool>boolean?결과 대신 수식 표시 (기본값: false)
show_row_col_headers / showRowColHeadersOption<bool>boolean?행/열 헤더 표시 (기본값: true)
zoom_scale / zoomScaleOption<u32>number?확대/축소 비율, 10-400 (기본값: 100)
view_mode / viewModeOption<ViewMode>string?보기 모드
top_left_cell / topLeftCellOption<String>string?표시되는 왼쪽 상단 셀 (예: "A1")

ViewMode

RustTypeScript설명
ViewMode::Normal"normal"일반 편집 보기 (기본값)
ViewMode::PageBreak"pageBreak"페이지 나누기 미리 보기
ViewMode::PageLayout"pageLayout"페이지 레이아웃 보기

확대/축소 값이 10-400 범위 밖이면 오류를 반환합니다. 보기 옵션을 설정해도 기존 틀 고정 설정에는 영향을 주지 않습니다.


32. 시트 표시 여부

시트 표시 여부는 Excel UI에서 시트 탭이 보이는지를 제어합니다. 세 가지 상태가 있습니다: 표시(기본값), 숨김(사용자가 UI를 통해 숨김 해제 가능), 매우 숨김(코드를 통해서만 숨김 해제 가능).

set_sheet_visibility(sheet, visibility) / setSheetVisibility(sheet, visibility)

시트의 표시 상태를 설정합니다. 최소 하나의 시트는 항상 표시 상태여야 합니다. 이 시트를 숨기면 표시 가능한 시트가 없게 되는 경우 오류를 반환합니다.

Rust:

rust
use sheetkit::sheet::SheetVisibility;

wb.new_sheet("Hidden")?;
wb.set_sheet_visibility("Hidden", SheetVisibility::Hidden)?;

wb.new_sheet("Secret")?;
wb.set_sheet_visibility("Secret", SheetVisibility::VeryHidden)?;

TypeScript:

typescript
wb.newSheet("Hidden");
wb.setSheetVisibility("Hidden", "hidden");

wb.newSheet("Secret");
wb.setSheetVisibility("Secret", "veryHidden");

get_sheet_visibility(sheet) / getSheetVisibility(sheet)

시트의 현재 표시 상태를 반환합니다.

Rust:

rust
let vis = wb.get_sheet_visibility("Hidden")?;
assert_eq!(vis, SheetVisibility::Hidden);

TypeScript:

typescript
const vis = wb.getSheetVisibility("Hidden"); // "hidden"

SheetVisibility

RustTypeScript설명
SheetVisibility::Visible"visible"시트 탭이 표시됩니다 (기본값)
SheetVisibility::Hidden"hidden"숨김 상태이며 사용자가 UI를 통해 숨김 해제할 수 있습니다
SheetVisibility::VeryHidden"veryHidden"숨김 상태이며 코드를 통해서만 숨김 해제할 수 있습니다

마지막으로 남은 표시 가능한 시트는 숨길 수 없습니다. 유일하게 표시된 시트를 숨기려고 하면 오류가 반환됩니다.


33. VBA 프로젝트 추출

.xlsm 파일에 저장된 VBA 매크로에 대한 읽기 전용 접근을 제공합니다.

get_vba_project() / getVbaProject()

xl/vbaProject.bin의 raw 바이너리 내용을 반환합니다. VBA 프로젝트가 없는 워크북의 경우 None/null을 반환합니다.

Rust:

rust
let raw: Option<&[u8]> = wb.get_vba_project();

TypeScript:

typescript
const raw: Buffer | null = wb.getVbaProject();

get_vba_modules() / getVbaModules()

VBA 프로젝트 바이너리를 파싱하고, 모듈 소스 코드를 압축 해제하여 모듈 배열을 반환합니다. VBA 프로젝트가 없으면 None/null을 반환합니다. VBA 프로젝트가 손상된 경우 에러를 발생시킵니다.

Rust:

rust
use sheetkit::vba::{VbaModule, VbaModuleType};

if let Some(modules) = wb.get_vba_modules()? {
    for m in &modules {
        println!("{}: {:?}", m.name, m.module_type);
        println!("{}", m.source_code);
    }
}

TypeScript:

typescript
const modules = wb.getVbaModules();
if (modules) {
  for (const m of modules) {
    console.log(`${m.name}: ${m.moduleType}`);
    console.log(m.sourceCode);
  }
}

VbaModule / JsVbaModule

필드Rust 타입TypeScript 타입설명
nameStringstring모듈 이름
source_code / sourceCodeStringstring압축 해제된 VBA 소스 코드
module_type / moduleTypeVbaModuleTypestringstandard, class, form, document, thisWorkbook 중 하나

34. Threaded Comments

Threaded comments(Excel 2019+)는 대화형 댓글 스레드를 지원합니다. 답글, 공유 person list를 통한 작성자 추적, 해결(done) 상태를 지원합니다. 레거시 댓글과 별도로 xl/threadedComments/threadedComment{N}.xml 파트에 저장됩니다.

add_threaded_comment / addThreadedComment

셀에 threaded comment를 추가합니다. 작성자가 person list에 없으면 자동으로 추가됩니다. 생성된 댓글 ID를 반환합니다.

Rust:

rust
use sheetkit::ThreadedCommentInput;

let comment_id = wb.add_threaded_comment(
    "Sheet1",
    "A1",
    &ThreadedCommentInput {
        author: "Alice".into(),
        text: "Please review this value.".into(),
        parent_id: None,
    },
)?;

// Reply to an existing comment
wb.add_threaded_comment(
    "Sheet1",
    "A1",
    &ThreadedCommentInput {
        author: "Bob".into(),
        text: "Looks correct to me.".into(),
        parent_id: Some(comment_id.clone()),
    },
)?;

TypeScript:

typescript
const commentId = wb.addThreadedComment("Sheet1", "A1", {
    author: "Alice",
    text: "Please review this value.",
});

// Reply to an existing comment
wb.addThreadedComment("Sheet1", "A1", {
    author: "Bob",
    text: "Looks correct to me.",
    parentId: commentId,
});

get_threaded_comments / getThreadedComments

시트의 모든 threaded comment를 반환합니다.

Rust:

rust
let comments = wb.get_threaded_comments("Sheet1")?;
for c in &comments {
    println!("{}: {} (by {})", c.cell_ref, c.text, c.author);
}

TypeScript:

typescript
const comments = wb.getThreadedComments("Sheet1");

get_threaded_comments_by_cell / getThreadedCommentsByCell

특정 셀의 threaded comment를 반환합니다.

Rust:

rust
let comments = wb.get_threaded_comments_by_cell("Sheet1", "A1")?;

TypeScript:

typescript
const comments = wb.getThreadedCommentsByCell("Sheet1", "A1");

delete_threaded_comment / deleteThreadedComment

댓글 ID로 threaded comment를 삭제합니다. 댓글을 찾을 수 없으면 오류를 반환합니다.

Rust:

rust
wb.delete_threaded_comment("Sheet1", &comment_id)?;

TypeScript:

typescript
wb.deleteThreadedComment("Sheet1", commentId);

resolve_threaded_comment / resolveThreadedComment

threaded comment의 해결(done) 상태를 설정합니다.

Rust:

rust
wb.resolve_threaded_comment("Sheet1", &comment_id, true)?;

TypeScript:

typescript
wb.resolveThreadedComment("Sheet1", commentId, true);

add_person / addPerson

공유 person list에 사람을 추가합니다. 같은 표시 이름의 사람이 이미 있으면 기존 ID를 반환합니다.

Rust:

rust
use sheetkit::PersonInput;

let person_id = wb.add_person(&PersonInput {
    display_name: "Alice".into(),
    user_id: Some("alice@example.com".into()),
    provider_id: Some("ADAL".into()),
});

TypeScript:

typescript
const personId = wb.addPerson({
    displayName: "Alice",
    userId: "alice@example.com",
    providerId: "ADAL",
});

get_persons / getPersons

person list의 모든 사람을 반환합니다.

Rust:

rust
let persons = wb.get_persons();

TypeScript:

typescript
const persons = wb.getPersons();

ThreadedCommentInput / JsThreadedCommentInput

필드Rust 타입TypeScript 타입설명
authorStringstring작성자 표시 이름 (person list에 자동 추가)
textStringstring댓글 텍스트
parent_id / parentIdOption<String>string?답글 시 부모 댓글 ID

ThreadedCommentData / JsThreadedCommentData

필드Rust 타입TypeScript 타입설명
idStringstring고유 댓글 ID
cell_ref / cellRefStringstring셀 참조 (예: "A1")
textStringstring댓글 텍스트
authorStringstring작성자 표시 이름
person_id / personIdStringstringperson list의 사람 ID
date_time / dateTimeStringstringISO 8601 타임스탬프
parent_id / parentIdOption<String>string?부모 댓글 ID (답글인 경우)
doneboolboolean해결(done) 상태

PersonInput / JsPersonInput

필드Rust 타입TypeScript 타입설명
display_name / displayNameStringstring사람 표시 이름
user_id / userIdOption<String>string?사용자 식별자 (예: 이메일)
provider_id / providerIdOption<String>string?ID 공급자 식별자

PersonData / JsPersonData

필드Rust 타입TypeScript 타입설명
idStringstring고유 사람 ID
display_name / displayNameStringstring사람 표시 이름
user_id / userIdOption<String>string?사용자 식별자
provider_id / providerIdOption<String>string?ID 공급자 식별자

35. 에러 타입

실패할 수 있는 모든 작업은 Rust에서 Result<T, Error>를 반환합니다. TypeScript에서는 Rust 에러 메시지를 포함한 JavaScript Error 객체가 throw됩니다.

Error Enum 레퍼런스

셀 및 참조 에러

Variant메시지설명
InvalidCellReference(String)invalid cell reference: {0}유효하지 않은 A1 스타일 참조
InvalidRowNumber(u32)invalid row number: {0}행 번호가 1..=1,048,576 범위 밖
InvalidColumnNumber(u32)invalid column number: {0}열 번호가 1..=16,384 범위 밖
InvalidReference { reference }invalid reference: {reference}유효하지 않은 셀 범위(sqref)
InvalidMergeCellReference(String)invalid merge cell reference: {0}잘못된 형식의 병합 범위
CellValueTooLong { length, max }cell value too long: {length} characters (max {max})값이 32,767자 제한을 초과

시트 에러

Variant메시지설명
SheetNotFound { name }sheet '{name}' does not exist해당 이름의 시트가 워크북에 없음
SheetAlreadyExists { name }sheet '{name}' already exists중복된 시트 이름
InvalidSheetName(String)invalid sheet name: {0}Excel 이름 규칙을 위반

스타일 에러

Variant메시지설명
StyleNotFound { id }style not found: {id}스타일 ID가 스타일시트에 없음
CellStylesExceeded { max }cell styles exceeded maximum ({max})등록된 스타일 수가 너무 많음
ColumnWidthExceeded { width, max }column width {width} exceeds maximum {max}열 너비 > 255
RowHeightExceeded { height, max }row height {height} exceeds maximum {max}행 높이 > 409
OutlineLevelExceeded { level, max }outline level {level} exceeds maximum {max}개요 수준 > 7

병합 셀 에러

Variant메시지설명
MergeCellOverlap { new, existing }merge cell range '{new}' overlaps with existing range '{existing}'병합 범위가 겹침
MergeCellNotFound(String)merge cell range '{0}' not found병합 범위가 존재하지 않음

수식 에러

Variant메시지설명
CircularReference { cell }circular reference detected at {cell}수식에서 순환 참조 감지
UnknownFunction { name }unknown function: {name}인식할 수 없는 함수 이름
WrongArgCount { name, expected, got }function {name} expects {expected} arguments, got {got}잘못된 인수 개수
FormulaError(String)formula evaluation error: {0}일반적인 수식 평가 실패

이름 정의 에러

Variant메시지설명
InvalidDefinedName(String)invalid defined name: {0}이름에 금지된 문자 포함
DefinedNameNotFound { name }defined name '{name}' not found정의된 이름이 존재하지 않음

기능별 에러

Variant메시지설명
PivotTableNotFound { name }pivot table '{name}' not found피벗 테이블이 존재하지 않음
PivotTableAlreadyExists { name }pivot table '{name}' already exists중복된 피벗 테이블 이름
TableNotFound { name }table '{name}' not found테이블이 존재하지 않음
TableAlreadyExists { name }table '{name}' already exists중복된 테이블 이름
TableColumnNotFound { table, column }column '{column}' not found in table '{table}'테이블에 열이 없음
InvalidSourceRange(String)invalid source range: {0}피벗 테이블 소스 범위가 유효하지 않음
SlicerNotFound { name }slicer '{name}' not found슬라이서가 존재하지 않음
SlicerAlreadyExists { name }slicer '{name}' already exists중복된 슬라이서 이름
ThreadedCommentNotFound { id }threaded comment '{id}' not found댓글 ID가 존재하지 않음
ChartNotFound { sheet, cell }no chart found at cell '{cell}' on sheet '{sheet}'해당 위치에 차트가 없음
PictureNotFound { sheet, cell }no picture found at cell '{cell}' on sheet '{sheet}'해당 위치에 이미지가 없음
UnsupportedImageFormat { format }unsupported image format: {format}지원하지 않는 이미지 형식

StreamWriter 에러

Variant메시지설명
StreamRowAlreadyWritten { row }row {row} has already been written행은 오름차순으로 작성해야 합니다
StreamAlreadyFinishedstream writer already finishedWriter가 이미 완료됨
StreamColumnsAfterRowscannot set column width after rows have been written열 설정은 행 작성 전에 해야 합니다

파일 I/O 및 ZIP 에러

Variant메시지설명
Io(std::io::Error)I/O error: {0}OS 수준의 I/O 에러
Zip(String)ZIP error: {0}ZIP 아카이브 읽기/쓰기 에러
XmlParse(String)XML parse error: {0}잘못된 형식의 XML
XmlDeserialize(String)XML deserialization error: {0}XML이 예상 스키마와 일치하지 않음
UnsupportedFileExtension(String)unsupported file extension: {0}.xlsx/.xlsm/.xltx/.xltm/.xlam이 아님
ZipSizeExceeded { size, limit }ZIP decompressed size {size} bytes exceeds limit of {limit} bytes압축 해제 크기 안전 제한 초과
ZipEntryCountExceeded { count, limit }ZIP entry count {count} exceeds limit of {limit}항목 수 안전 제한 초과

암호화 에러

Variant메시지설명
FileEncryptedfile is encrypted, password required파일에 비밀번호가 필요합니다
IncorrectPasswordincorrect password잘못된 복호화 비밀번호
UnsupportedEncryption(String)unsupported encryption method: {0}알 수 없는 암호화 알고리즘

기타

Variant메시지설명
InvalidArgument(String)invalid argument: {0}일반적인 유효하지 않은 매개변수
Internal(String)internal error: {0}분류되지 않은 내부 에러

TypeScript 에러 처리

TypeScript에서 모든 에러는 표준 Error 객체로 throw됩니다. 메시지 문자열로 에러를 매칭할 수 있습니다:

typescript
try {
    wb.getCellValue("NonExistent", "A1");
} catch (e) {
    if (e instanceof Error && e.message.includes("does not exist")) {
        console.log("Sheet not found");
    }
}

MIT / Apache-2.0 라이선스로 배포됩니다.