import { strFromU8, unzipSync } from 'fflate';
import { describe, expect, it } from 'vitest';
import type { ParserDiagnostic } from '../model/diagnostics.js';
import type {
OneNoteContentBlock,
OneNoteTextBlock,
OneNoteTextStyle,
} from '../one/content-model.js';
import {
createOneNoteExportPlan,
createOneNoteExportSnapshot,
createOneNoteStaticNotebookZip,
OneNoteExportError,
SafeExportNameAllocator,
sanitizeExportFilename,
serializeOneNoteMarkdown,
serializeOneNotePlainText,
serializeOneNoteSemanticHtml,
serializeOneNoteStructuredJson,
type OneNoteExportSnapshot,
} from './index.js';
import { utf8ByteLength } from './plan.js';
const PNG = Uint8Array.from([
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49,
0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);
const JPEG = Uint8Array.from([
0xff, 0xd8, 0xff, 0xc0, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01,
0x11, 0x00, 0xff, 0xd9,
]);
const SOURCE_MARKUP = '
';
describe('OneNote export serializers', () => {
it('retains provenance and rich content without emitting active source markup', () => {
const snapshot = fixtureSnapshot();
const structured = JSON.parse(serializeOneNoteStructuredJson(snapshot)) as {
app: { version: string };
parser: { version: string };
supportLevel: string;
source: { name: string };
diagnostics: ParserDiagnostic[];
warnings: Array<{ code: string }>;
unsupportedContent: Array<{ sourceJcid: number }>;
resources: Array>;
};
expect(structured).toMatchObject({
app: { version: '1.2.3' },
parser: { version: '9.8.7' },
supportLevel: 'substantial',
source: { name: '../../'
);
const html = strFromU8(files['index.html']!);
const document = new DOMParser().parseFromString(html, 'text/html');
expect(document.querySelector('img')?.getAttribute('src')).toBe(
'assets/_CON/photo.png'
);
expect(document.querySelector('a[download]')?.getAttribute('href')).toBe(
'assets/_CON/CON_script_.html.bin'
);
expect(
document.querySelectorAll('script,object,iframe,embed')
).toHaveLength(0);
const manifest = JSON.parse(strFromU8(files['manifest.json']!)) as {
app: { version: string };
parser: { version: string };
supportLevel: string;
source: { name: string };
resources: Array<{ path: string; mediaType: string }>;
};
expect(manifest).toMatchObject({
app: { version: '1.2.3' },
parser: { version: '9.8.7' },
supportLevel: 'substantial',
source: { name: '../../',
},
];
return createOneNoteExportSnapshot({
sourceName: '../../',
text: SOURCE_MARKUP,
textPreview: SOURCE_MARKUP,
blocks,
diagnostics: [diagnostic('page-warning')],
},
{
id: 'page-2',
title: 'Fallback',
text: 'Fallback page text ',
textPreview: 'Fallback page text',
blocks: [],
diagnostics: [],
},
],
diagnostics: [diagnostic('section-warning')],
},
],
resources: [
{
sectionId: 'section-1',
id: 'image-1',
kind: 'image',
filename: 'photo.svg',
extension: 'svg',
mediaType: 'image/svg+xml',
browserRenderable: true,
size: PNG.byteLength,
bytes: PNG,
},
{
sectionId: 'section-1',
id: 'bad-image',
kind: 'image',
filename: 'bad.svg',
extension: 'svg',
mediaType: 'image/svg+xml',
browserRenderable: true,
bytes: new TextEncoder().encode(''),
},
{
sectionId: 'section-1',
id: 'image-2',
kind: 'image',
filename: 'photo.png',
extension: 'png',
mediaType: 'image/png',
browserRenderable: true,
bytes: JPEG,
},
{
sectionId: 'section-1',
id: 'attachment-1',
kind: 'attachment',
filename: '../../CON'),
},
],
diagnostics: [diagnostic('package-warning')],
});
}
function minimalSnapshot(
blocks: OneNoteContentBlock[] = [],
resources: OneNoteExportSnapshot['resources'] = []
): OneNoteExportSnapshot {
return createOneNoteExportSnapshot({
sourceName: 's.one',
sourceFormat: 'one',
notebookName: 'n',
appName: 'a',
appVersion: '1',
parser: {
name: 'p',
version: '1',
implementation: 't',
supportedVariants: [],
},
sections: [
{
id: 's',
name: 's',
pages: [
{
id: 'p',
title: 'p',
text: '',
textPreview: '',
blocks,
diagnostics: [],
},
],
diagnostics: [],
},
],
resources,
});
}
function pngWithDimensions(width: number, height: number): Uint8Array {
const bytes = PNG.slice();
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
view.setUint32(16, width);
view.setUint32(20, height);
return bytes;
}
function textBlock(
id: string,
text: string,
style: OneNoteTextStyle = {}
): OneNoteTextBlock {
return {
kind: 'text',
id,
sourceText: text,
text,
runs: [{ start: 0, end: text.length, text, style }],
paragraphStyle: {},
layout: {},
};
}
function diagnostic(code: string): ParserDiagnostic {
return {
severity: 'warning',
code,
message: `${code} `,
recoverable: true,
};
}