@cesarandreslopez/occ 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +130 -4
  2. package/dist/src/cli.js +8 -0
  3. package/dist/src/cli.js.map +1 -1
  4. package/dist/src/code/build.js +22 -9
  5. package/dist/src/code/build.js.map +1 -1
  6. package/dist/src/code/command.js +2 -2
  7. package/dist/src/code/command.js.map +1 -1
  8. package/dist/src/code/output.js +12 -3
  9. package/dist/src/code/output.js.map +1 -1
  10. package/dist/src/code/parsers.js +52 -10
  11. package/dist/src/code/parsers.js.map +1 -1
  12. package/dist/src/code/query.js +82 -22
  13. package/dist/src/code/query.js.map +1 -1
  14. package/dist/src/code/types.d.ts +5 -3
  15. package/dist/src/doc/command.d.ts +2 -0
  16. package/dist/src/doc/command.js +54 -0
  17. package/dist/src/doc/command.js.map +1 -0
  18. package/dist/src/doc/inspect-docx.d.ts +14 -0
  19. package/dist/src/doc/inspect-docx.js +188 -0
  20. package/dist/src/doc/inspect-docx.js.map +1 -0
  21. package/dist/src/doc/inspect-odt.d.ts +8 -0
  22. package/dist/src/doc/inspect-odt.js +91 -0
  23. package/dist/src/doc/inspect-odt.js.map +1 -0
  24. package/dist/src/doc/inspect-pdf.d.ts +8 -0
  25. package/dist/src/doc/inspect-pdf.js +82 -0
  26. package/dist/src/doc/inspect-pdf.js.map +1 -0
  27. package/dist/src/doc/inspect.d.ts +2 -0
  28. package/dist/src/doc/inspect.js +70 -0
  29. package/dist/src/doc/inspect.js.map +1 -0
  30. package/dist/src/doc/output.d.ts +3 -0
  31. package/dist/src/doc/output.js +82 -0
  32. package/dist/src/doc/output.js.map +1 -0
  33. package/dist/src/doc/types.d.ts +59 -0
  34. package/dist/src/doc/types.js +2 -0
  35. package/dist/src/doc/types.js.map +1 -0
  36. package/dist/src/inspect/shared.d.ts +18 -0
  37. package/dist/src/inspect/shared.js +18 -0
  38. package/dist/src/inspect/shared.js.map +1 -0
  39. package/dist/src/parsers/xlsx.js +3 -1
  40. package/dist/src/parsers/xlsx.js.map +1 -1
  41. package/dist/src/sheet/command.d.ts +2 -0
  42. package/dist/src/sheet/command.js +70 -0
  43. package/dist/src/sheet/command.js.map +1 -0
  44. package/dist/src/sheet/inspect.d.ts +7 -0
  45. package/dist/src/sheet/inspect.js +454 -0
  46. package/dist/src/sheet/inspect.js.map +1 -0
  47. package/dist/src/sheet/output.d.ts +3 -0
  48. package/dist/src/sheet/output.js +158 -0
  49. package/dist/src/sheet/output.js.map +1 -0
  50. package/dist/src/sheet/types.d.ts +117 -0
  51. package/dist/src/sheet/types.js +2 -0
  52. package/dist/src/sheet/types.js.map +1 -0
  53. package/dist/src/slide/command.d.ts +2 -0
  54. package/dist/src/slide/command.js +54 -0
  55. package/dist/src/slide/command.js.map +1 -0
  56. package/dist/src/slide/inspect-odp.d.ts +7 -0
  57. package/dist/src/slide/inspect-odp.js +105 -0
  58. package/dist/src/slide/inspect-odp.js.map +1 -0
  59. package/dist/src/slide/inspect-pptx.d.ts +11 -0
  60. package/dist/src/slide/inspect-pptx.js +157 -0
  61. package/dist/src/slide/inspect-pptx.js.map +1 -0
  62. package/dist/src/slide/inspect.d.ts +2 -0
  63. package/dist/src/slide/inspect.js +76 -0
  64. package/dist/src/slide/inspect.js.map +1 -0
  65. package/dist/src/slide/output.d.ts +3 -0
  66. package/dist/src/slide/output.js +92 -0
  67. package/dist/src/slide/output.js.map +1 -0
  68. package/dist/src/slide/types.d.ts +59 -0
  69. package/dist/src/slide/types.js +2 -0
  70. package/dist/src/slide/types.js.map +1 -0
  71. package/dist/src/table/command.d.ts +2 -0
  72. package/dist/src/table/command.js +68 -0
  73. package/dist/src/table/command.js.map +1 -0
  74. package/dist/src/table/inspect-docx.d.ts +2 -0
  75. package/dist/src/table/inspect-docx.js +108 -0
  76. package/dist/src/table/inspect-docx.js.map +1 -0
  77. package/dist/src/table/inspect-odp.d.ts +2 -0
  78. package/dist/src/table/inspect-odp.js +106 -0
  79. package/dist/src/table/inspect-odp.js.map +1 -0
  80. package/dist/src/table/inspect-odt.d.ts +2 -0
  81. package/dist/src/table/inspect-odt.js +100 -0
  82. package/dist/src/table/inspect-odt.js.map +1 -0
  83. package/dist/src/table/inspect-pptx.d.ts +2 -0
  84. package/dist/src/table/inspect-pptx.js +112 -0
  85. package/dist/src/table/inspect-pptx.js.map +1 -0
  86. package/dist/src/table/inspect-xlsx.d.ts +2 -0
  87. package/dist/src/table/inspect-xlsx.js +161 -0
  88. package/dist/src/table/inspect-xlsx.js.map +1 -0
  89. package/dist/src/table/inspect.d.ts +2 -0
  90. package/dist/src/table/inspect.js +63 -0
  91. package/dist/src/table/inspect.js.map +1 -0
  92. package/dist/src/table/output.d.ts +3 -0
  93. package/dist/src/table/output.js +93 -0
  94. package/dist/src/table/output.js.map +1 -0
  95. package/dist/src/table/types.d.ts +38 -0
  96. package/dist/src/table/types.js +2 -0
  97. package/dist/src/table/types.js.map +1 -0
  98. package/package.json +2 -2
@@ -0,0 +1,158 @@
1
+ import Table from 'cli-table3';
2
+ import chalk from 'chalk';
3
+ import { formatBytes, formatNumber } from '../utils.js';
4
+ import { sectionHeader, stripAnsi, tableChars } from '../output/tabular.js';
5
+ const colors = {
6
+ header: (value) => chalk.bold(value),
7
+ key: (value) => chalk.cyan(value),
8
+ value: (value) => value,
9
+ dim: (value) => chalk.dim(value),
10
+ ok: (value) => chalk.green(value),
11
+ warn: (value) => chalk.yellow(value),
12
+ };
13
+ const noColor = Object.fromEntries(Object.keys(colors).map(key => [key, (value) => value]));
14
+ function palette(ci = false) {
15
+ return ci ? noColor : colors;
16
+ }
17
+ export function formatSheetPayloadJson(payload) {
18
+ return JSON.stringify(payload, null, 2);
19
+ }
20
+ export function formatSheetInspection(result, ci = false) {
21
+ const c = palette(ci);
22
+ const sections = [];
23
+ const overviewLines = [
24
+ `${c.key('File')}: ${c.value(result.workbook.file)}`,
25
+ `${c.key('Format')}: ${c.value('XLSX')}`,
26
+ `${c.key('Size')}: ${c.value(formatBytes(result.workbook.size))}`,
27
+ `${c.key('Sheets')}: ${c.value(`${formatNumber(result.workbook.sheetCount)} total (${formatNumber(result.workbook.visibleSheetCount)} visible, ${formatNumber(result.workbook.hiddenSheetCount)} hidden, ${formatNumber(result.workbook.veryHiddenSheetCount)} very hidden)`)}`,
28
+ ];
29
+ const propEntries = Object.entries(result.workbook.properties).filter(([, value]) => value);
30
+ if (propEntries.length > 0) {
31
+ overviewLines.push(`${c.key('Properties')}: ${propEntries.map(([key, value]) => `${key}=${value}`).join(' | ')}`);
32
+ }
33
+ if (result.workbook.definedNames.length > 0) {
34
+ overviewLines.push(`${c.key('Workbook Names')}: ${result.workbook.definedNames.map(name => `${name.name}=${name.ref}`).join(' | ')}`);
35
+ }
36
+ const riskFlags = Object.entries(result.workbook.riskFlags).filter(([, enabled]) => enabled).map(([key]) => key);
37
+ overviewLines.push(`${c.key('Risk Flags')}: ${riskFlags.length > 0 ? c.warn(riskFlags.join(', ')) : c.ok('none')}`);
38
+ sections.push(overviewLines.join('\n'));
39
+ if (result.sheets.length > 0) {
40
+ const inventory = new Table({
41
+ head: [
42
+ c.key('Sheet'),
43
+ c.key('Visibility'),
44
+ c.key('Range'),
45
+ c.key('Rows'),
46
+ c.key('Cols'),
47
+ c.key('Non-Empty'),
48
+ c.key('Formulae'),
49
+ c.key('Links'),
50
+ c.key('Comments'),
51
+ c.key('Tokens'),
52
+ ],
53
+ chars: tableChars(ci),
54
+ style: { head: [], border: [] },
55
+ colAligns: ['left', 'left', 'left', 'right', 'right', 'right', 'right', 'right', 'right', 'right'],
56
+ });
57
+ for (const sheet of result.sheets) {
58
+ inventory.push([
59
+ `${sheet.index}. ${sheet.name}`,
60
+ sheet.visibility,
61
+ sheet.usedRange ?? '',
62
+ formatNumber(sheet.totalRows),
63
+ formatNumber(sheet.totalCols),
64
+ formatNumber(sheet.nonEmptyCellCount),
65
+ formatNumber(sheet.formulaCellCount),
66
+ formatNumber(sheet.hyperlinkCellCount),
67
+ formatNumber(sheet.commentCellCount),
68
+ formatNumber(sheet.fullTokenEstimate),
69
+ ]);
70
+ }
71
+ const rendered = inventory.toString();
72
+ const width = stripAnsi(rendered.split('\n')[0] ?? '').length;
73
+ sections.push(`${c.header(sectionHeader('Sheet Inventory', width, ci))}\n${rendered}`);
74
+ }
75
+ for (const sheet of result.sheets) {
76
+ sections.push(formatSheetProfile(sheet, ci));
77
+ }
78
+ return sections.join('\n\n') + '\n';
79
+ }
80
+ function formatSheetProfile(sheet, ci = false) {
81
+ const c = palette(ci);
82
+ const lines = [];
83
+ const title = `Sheet: ${sheet.name} (${sheet.visibility})`;
84
+ const summary = [
85
+ `${c.key('Range')}: ${sheet.usedRange ?? '(empty)'}`,
86
+ `${c.key('Grid')}: ${formatNumber(sheet.totalRows)} rows x ${formatNumber(sheet.totalCols)} cols (${formatNumber(sheet.rectangularRangeCellCount)} cells)`,
87
+ `${c.key('Signals')}: ${formatNumber(sheet.formulaCellCount)} formulae | ${formatNumber(sheet.commentCellCount)} comments | ${formatNumber(sheet.hyperlinkCellCount)} hyperlinks | ${formatNumber(sheet.mergedRangeCount)} merges`,
88
+ `${c.key('Layout')}: ${formatNumber(sheet.hiddenRowCount)} hidden rows | ${formatNumber(sheet.hiddenColumnCount)} hidden cols | autofilter=${sheet.autoFilterRef ?? 'none'} | protected=${sheet.protected ? 'yes' : 'no'}`,
89
+ `${c.key('Header')}: ${sheet.headerSelection.rowNumber ?? 'none'} (${sheet.headerSelection.mode})`,
90
+ `${c.key('Token Estimate')}: sample=${formatNumber(sheet.sampleTokenEstimate)} | full=${formatNumber(sheet.fullTokenEstimate)}`,
91
+ ];
92
+ if (sheet.definedNames.length > 0) {
93
+ summary.push(`${c.key('Defined Names')}: ${sheet.definedNames.map(name => `${name.name}=${name.ref}`).join(' | ')}`);
94
+ }
95
+ lines.push(summary.join('\n'));
96
+ if (sheet.schema.columns.length > 0) {
97
+ lines.push(formatSchemaTable(sheet.schema.columns, sheet.schema.truncated, ci));
98
+ }
99
+ else {
100
+ lines.push(c.dim('No schema columns found.'));
101
+ }
102
+ if (sheet.sample.rows.length > 0) {
103
+ lines.push(formatSampleTable(sheet.sample.rows, sheet.sample.truncatedRows, sheet.sample.truncatedColumns, ci));
104
+ }
105
+ else {
106
+ lines.push(c.dim('No sample rows found.'));
107
+ }
108
+ const width = Math.max(...lines.map(line => stripAnsi(line.split('\n')[0] ?? '').length), title.length, 40);
109
+ return `${c.header(sectionHeader(title, width, ci))}\n${lines.join('\n\n')}`;
110
+ }
111
+ function formatSchemaTable(columns, truncated, ci = false) {
112
+ const c = palette(ci);
113
+ const table = new Table({
114
+ head: [
115
+ c.key('Col'),
116
+ c.key('Name'),
117
+ c.key('Type'),
118
+ c.key('Non-Empty'),
119
+ c.key('Coverage'),
120
+ c.key('Examples'),
121
+ ],
122
+ chars: tableChars(ci),
123
+ style: { head: [], border: [] },
124
+ colAligns: ['left', 'left', 'left', 'right', 'right', 'left'],
125
+ });
126
+ for (const column of columns) {
127
+ table.push([
128
+ `${column.letter} (${column.index})`,
129
+ column.name,
130
+ column.dominantType,
131
+ formatNumber(column.nonEmptyCount),
132
+ `${Math.round(column.nonEmptyRatio * 100)}%`,
133
+ column.examples.join(' | '),
134
+ ]);
135
+ }
136
+ const suffix = truncated ? '\n(truncated columns)' : '';
137
+ return `${palette(ci).header('Schema')}\n${table.toString()}${suffix}`;
138
+ }
139
+ function formatSampleTable(rows, truncatedRows, truncatedColumns, ci = false) {
140
+ const c = palette(ci);
141
+ const columnNames = Object.keys(rows[0]?.values ?? {});
142
+ const table = new Table({
143
+ head: [c.key('Row'), ...columnNames.map(name => c.key(name))],
144
+ chars: tableChars(ci),
145
+ style: { head: [], border: [] },
146
+ });
147
+ for (const row of rows) {
148
+ table.push([String(row.rowNumber), ...columnNames.map(name => row.values[name] ?? '')]);
149
+ }
150
+ const notes = [];
151
+ if (truncatedRows)
152
+ notes.push('truncated rows');
153
+ if (truncatedColumns)
154
+ notes.push('truncated columns');
155
+ const suffix = notes.length > 0 ? `\n(${notes.join(', ')})` : '';
156
+ return `${palette(ci).header('Sample')}\n${table.toString()}${suffix}`;
157
+ }
158
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/sheet/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ export type SheetVisibility = 'visible' | 'hidden' | 'very_hidden';
2
+ export type HeaderSelectionMode = 'auto' | 'none' | 'explicit';
3
+ export type ColumnValueType = 'string' | 'number' | 'boolean' | 'date' | 'error' | 'blank_stub' | 'unknown';
4
+ export interface InspectSheetOptions {
5
+ sheet?: string;
6
+ sampleRows: number;
7
+ headerRow: 'auto' | 'none' | number;
8
+ maxColumns: number;
9
+ }
10
+ export interface DefinedNameInfo {
11
+ name: string;
12
+ ref: string;
13
+ scope: 'workbook' | 'sheet';
14
+ sheetIndex?: number;
15
+ sheetName?: string;
16
+ external: boolean;
17
+ }
18
+ export interface WorkbookProperties {
19
+ title?: string;
20
+ subject?: string;
21
+ author?: string;
22
+ company?: string;
23
+ manager?: string;
24
+ createdDate?: string;
25
+ modifiedDate?: string;
26
+ }
27
+ export interface WorkbookRiskFlags {
28
+ hiddenSheets: boolean;
29
+ formulas: boolean;
30
+ comments: boolean;
31
+ hyperlinks: boolean;
32
+ mergedCells: boolean;
33
+ protectedSheets: boolean;
34
+ externalFormulaRefs: boolean;
35
+ }
36
+ export interface CellTypeCounts {
37
+ string: number;
38
+ number: number;
39
+ boolean: number;
40
+ date: number;
41
+ error: number;
42
+ blankStub: number;
43
+ }
44
+ export interface ColumnProfile {
45
+ index: number;
46
+ letter: string;
47
+ name: string;
48
+ dominantType: ColumnValueType;
49
+ nonEmptyCount: number;
50
+ nonEmptyRatio: number;
51
+ examples: string[];
52
+ }
53
+ export interface SampleRow {
54
+ rowNumber: number;
55
+ values: Record<string, string>;
56
+ }
57
+ export interface SheetProfile {
58
+ index: number;
59
+ name: string;
60
+ visibility: SheetVisibility;
61
+ usedRange: string | null;
62
+ totalRows: number;
63
+ totalCols: number;
64
+ rectangularRangeCellCount: number;
65
+ nonEmptyCellCount: number;
66
+ cellTypeCounts: CellTypeCounts;
67
+ formulaCellCount: number;
68
+ commentCellCount: number;
69
+ hyperlinkCellCount: number;
70
+ mergedRangeCount: number;
71
+ hiddenRowCount: number;
72
+ hiddenColumnCount: number;
73
+ autoFilterRef: string | null;
74
+ protected: boolean;
75
+ definedNames: DefinedNameInfo[];
76
+ externalFormulaRefCount: number;
77
+ headerSelection: {
78
+ requested: 'auto' | 'none' | number;
79
+ mode: HeaderSelectionMode;
80
+ rowNumber: number | null;
81
+ };
82
+ schema: {
83
+ truncated: boolean;
84
+ columns: ColumnProfile[];
85
+ };
86
+ sample: {
87
+ truncatedRows: boolean;
88
+ truncatedColumns: boolean;
89
+ rows: SampleRow[];
90
+ };
91
+ sampleTokenEstimate: number;
92
+ fullTokenEstimate: number;
93
+ estimateMethod: 'full_scan';
94
+ }
95
+ export interface WorkbookInspection {
96
+ file: string;
97
+ format: 'xlsx';
98
+ size: number;
99
+ properties: WorkbookProperties;
100
+ customPropertyCount: number;
101
+ customProperties: Record<string, unknown>;
102
+ sheetCount: number;
103
+ visibleSheetCount: number;
104
+ hiddenSheetCount: number;
105
+ veryHiddenSheetCount: number;
106
+ definedNames: DefinedNameInfo[];
107
+ riskFlags: WorkbookRiskFlags;
108
+ }
109
+ export interface SheetInspectionResult {
110
+ workbook: WorkbookInspection;
111
+ sheets: SheetProfile[];
112
+ }
113
+ export interface SheetInspectPayload {
114
+ file: string;
115
+ query: Record<string, unknown>;
116
+ results: SheetInspectionResult;
117
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/sheet/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerSlideCommands(program: Command): void;
@@ -0,0 +1,54 @@
1
+ import { writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { inspectPresentation } from './inspect.js';
4
+ import { formatSlideInspection, formatSlidePayloadJson } from './output.js';
5
+ import { createInspectPayload } from '../inspect/shared.js';
6
+ import { writeStream } from '../utils.js';
7
+ function getOptions(command) {
8
+ return command.optsWithGlobals();
9
+ }
10
+ function parsePositiveInt(value, fallback, label) {
11
+ if (!value)
12
+ return fallback;
13
+ const parsed = Number.parseInt(value, 10);
14
+ if (!Number.isFinite(parsed) || parsed <= 0) {
15
+ throw new Error(`Invalid ${label}: "${value}"`);
16
+ }
17
+ return parsed;
18
+ }
19
+ async function emit(output, options) {
20
+ if (options.output) {
21
+ await writeFile(options.output, output);
22
+ return;
23
+ }
24
+ await writeStream(process.stdout, output);
25
+ }
26
+ export function registerSlideCommands(program) {
27
+ const slide = program.command('slide').description('Inspect presentation structure and content before deep reading');
28
+ const inspect = slide.command('inspect <file>').description('Inspect PPTX or ODP presentation metadata, slides, and content preview');
29
+ inspect
30
+ .option('--format <type>', 'output format: tabular or json', 'tabular')
31
+ .option('-o, --output <file>', 'write output to file')
32
+ .option('--ci', 'ASCII-only output, no colors')
33
+ .option('--sample-slides <n>', 'preview slide count', '3')
34
+ .option('--slide <number>', 'inspect specific slide (1-based index)');
35
+ inspect.action(async (file, _options, command) => {
36
+ const options = getOptions(command);
37
+ const resolved = path.resolve(file);
38
+ const inspectOptions = {
39
+ sampleSlides: parsePositiveInt(options.sampleSlides, 3, 'sample slide count'),
40
+ slide: options.slide ? parsePositiveInt(options.slide, 1, 'slide number') : undefined,
41
+ };
42
+ const result = await inspectPresentation(resolved, inspectOptions);
43
+ const payload = createInspectPayload(resolved, {
44
+ command: 'slide.inspect',
45
+ sampleSlides: inspectOptions.sampleSlides,
46
+ slide: inspectOptions.slide,
47
+ }, result);
48
+ const output = options.format === 'json'
49
+ ? formatSlidePayloadJson(payload)
50
+ : formatSlideInspection(result, options.ci);
51
+ await emit(output.endsWith('\n') ? output : `${output}\n`, options);
52
+ });
53
+ }
54
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../../src/slide/command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { DocumentProperties } from '../inspect/shared.js';
2
+ import type { SlideRiskFlags, SlideProfile } from './types.js';
3
+ export declare function inspectOdp(buffer: Buffer): Promise<{
4
+ properties: DocumentProperties;
5
+ riskFlags: SlideRiskFlags;
6
+ slideProfiles: SlideProfile[];
7
+ }>;
@@ -0,0 +1,105 @@
1
+ import JSZip from 'jszip';
2
+ import { countWords } from '../utils.js';
3
+ import { asOptionalString, formatDateLike } from '../inspect/shared.js';
4
+ function parseXmlText(xml, tag) {
5
+ const regex = new RegExp(`<${tag}[^>]*>([^<]*)</${tag}>`, 'i');
6
+ const match = xml.match(regex);
7
+ return match?.[1]?.trim() || undefined;
8
+ }
9
+ function extractTextFromElement(xml) {
10
+ const matches = xml.match(/<text:(?:p|span)[^>]*>([^<]*)<\/text:(?:p|span)>/g) || [];
11
+ const texts = [];
12
+ for (const m of matches) {
13
+ const text = m.replace(/<[^>]+>/g, '').trim();
14
+ if (text)
15
+ texts.push(text);
16
+ }
17
+ return texts.join(' ');
18
+ }
19
+ export async function inspectOdp(buffer) {
20
+ const zip = await JSZip.loadAsync(buffer);
21
+ // Parse metadata
22
+ const properties = {};
23
+ const metaXml = await zip.file('meta.xml')?.async('text');
24
+ if (metaXml) {
25
+ properties.title = asOptionalString(parseXmlText(metaXml, 'dc:title'));
26
+ properties.subject = asOptionalString(parseXmlText(metaXml, 'dc:subject'));
27
+ properties.author = asOptionalString(parseXmlText(metaXml, 'dc:creator') ?? parseXmlText(metaXml, 'meta:initial-creator'));
28
+ properties.keywords = asOptionalString(parseXmlText(metaXml, 'meta:keyword'));
29
+ properties.createdDate = formatDateLike(parseXmlText(metaXml, 'meta:creation-date'));
30
+ properties.modifiedDate = formatDateLike(parseXmlText(metaXml, 'dc:date'));
31
+ }
32
+ // Parse content.xml for slides
33
+ const contentXml = await zip.file('content.xml')?.async('text');
34
+ const slideProfiles = [];
35
+ const riskFlags = {
36
+ comments: false,
37
+ speakerNotes: false,
38
+ hyperlinks: false,
39
+ embeddedMedia: false,
40
+ animations: false,
41
+ macros: false,
42
+ charts: false,
43
+ tables: false,
44
+ };
45
+ if (contentXml) {
46
+ // Split by draw:page elements
47
+ const slideMatches = contentXml.match(/<draw:page\b[^>]*>[\s\S]*?<\/draw:page>/g) || [];
48
+ for (let i = 0; i < slideMatches.length; i++) {
49
+ const slideXml = slideMatches[i];
50
+ // Get title from draw:name attribute or first text frame
51
+ let title = null;
52
+ const nameMatch = slideXml.match(/draw:name="([^"]*)"/);
53
+ if (nameMatch && nameMatch[1]) {
54
+ title = nameMatch[1];
55
+ }
56
+ // Extract text
57
+ const text = extractTextFromElement(slideXml);
58
+ const words = countWords(text);
59
+ // Count tables and images
60
+ const tables = (slideXml.match(/<table:table\b/g) || []).length;
61
+ const images = (slideXml.match(/<draw:image\b/g) || []).length;
62
+ // Check for notes
63
+ let hasNotes = false;
64
+ let notePreview = null;
65
+ const notesMatch = slideXml.match(/<presentation:notes\b[^>]*>([\s\S]*?)<\/presentation:notes>/);
66
+ if (notesMatch) {
67
+ const notesText = extractTextFromElement(notesMatch[1]);
68
+ if (notesText.trim()) {
69
+ hasNotes = true;
70
+ notePreview = notesText.length > 200 ? notesText.slice(0, 200) + '...' : notesText;
71
+ }
72
+ }
73
+ slideProfiles.push({
74
+ index: i + 1,
75
+ title,
76
+ words,
77
+ hasNotes,
78
+ notePreview,
79
+ images,
80
+ tables,
81
+ charts: 0,
82
+ });
83
+ }
84
+ // Risk flags
85
+ if (/<office:annotation\b/.test(contentXml))
86
+ riskFlags.comments = true;
87
+ if (slideProfiles.some(p => p.hasNotes))
88
+ riskFlags.speakerNotes = true;
89
+ if (/<text:a\b[^>]*xlink:href=/.test(contentXml))
90
+ riskFlags.hyperlinks = true;
91
+ if (/<draw:image\b/.test(contentXml))
92
+ riskFlags.embeddedMedia = true;
93
+ if (/<presentation:transition\b/.test(contentXml) || /<anim:/.test(contentXml))
94
+ riskFlags.animations = true;
95
+ if (/<table:table\b/.test(contentXml))
96
+ riskFlags.tables = true;
97
+ if (/<draw:object\b/.test(contentXml))
98
+ riskFlags.charts = true;
99
+ }
100
+ // Check for macros
101
+ if (zip.file('Basic/') || zip.file('Scripts/'))
102
+ riskFlags.macros = true;
103
+ return { properties, riskFlags, slideProfiles };
104
+ }
105
+ //# sourceMappingURL=inspect-odp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect-odp.js","sourceRoot":"","sources":["../../../src/slide/inspect-odp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import JSZip from 'jszip';
2
+ import type { DocumentProperties } from '../inspect/shared.js';
3
+ import type { SlideRiskFlags, SlideProfile } from './types.js';
4
+ export declare function extractPptxProperties(zip: JSZip): Promise<DocumentProperties>;
5
+ export declare function extractPptxRiskFlags(zip: JSZip, slideProfiles: SlideProfile[]): Promise<SlideRiskFlags>;
6
+ export declare function extractPptxSlideProfiles(zip: JSZip): Promise<SlideProfile[]>;
7
+ export declare function inspectPptx(buffer: Buffer): Promise<{
8
+ properties: DocumentProperties;
9
+ riskFlags: SlideRiskFlags;
10
+ slideProfiles: SlideProfile[];
11
+ }>;
@@ -0,0 +1,157 @@
1
+ import JSZip from 'jszip';
2
+ import { countWords } from '../utils.js';
3
+ import { asOptionalString, formatDateLike } from '../inspect/shared.js';
4
+ function parseXmlText(xml, tag) {
5
+ const regex = new RegExp(`<${tag}[^>]*>([^<]*)</${tag}>`, 'i');
6
+ const match = xml.match(regex);
7
+ return match?.[1]?.trim() || undefined;
8
+ }
9
+ function extractAllText(xml) {
10
+ const matches = xml.match(/<a:t>([^<]*)<\/a:t>/g) || [];
11
+ return matches.map(m => {
12
+ const text = m.match(/<a:t>([^<]*)<\/a:t>/);
13
+ return text?.[1] || '';
14
+ }).join(' ').trim();
15
+ }
16
+ export async function extractPptxProperties(zip) {
17
+ const props = {};
18
+ const coreXml = await zip.file('docProps/core.xml')?.async('text');
19
+ if (coreXml) {
20
+ props.title = asOptionalString(parseXmlText(coreXml, 'dc:title'));
21
+ props.subject = asOptionalString(parseXmlText(coreXml, 'dc:subject'));
22
+ props.author = asOptionalString(parseXmlText(coreXml, 'dc:creator'));
23
+ props.keywords = asOptionalString(parseXmlText(coreXml, 'cp:keywords'));
24
+ props.lastModifiedBy = asOptionalString(parseXmlText(coreXml, 'cp:lastModifiedBy'));
25
+ props.createdDate = formatDateLike(parseXmlText(coreXml, 'dcterms:created'));
26
+ props.modifiedDate = formatDateLike(parseXmlText(coreXml, 'dcterms:modified'));
27
+ }
28
+ const appXml = await zip.file('docProps/app.xml')?.async('text');
29
+ if (appXml) {
30
+ props.company = asOptionalString(parseXmlText(appXml, 'Company'));
31
+ }
32
+ return props;
33
+ }
34
+ export async function extractPptxRiskFlags(zip, slideProfiles) {
35
+ const flags = {
36
+ comments: false,
37
+ speakerNotes: false,
38
+ hyperlinks: false,
39
+ embeddedMedia: false,
40
+ animations: false,
41
+ macros: false,
42
+ charts: false,
43
+ tables: false,
44
+ };
45
+ // Check for comments folder
46
+ const commentFiles = Object.keys(zip.files).filter(name => /^ppt\/comments\//.test(name));
47
+ if (commentFiles.length > 0)
48
+ flags.comments = true;
49
+ // Check for speaker notes
50
+ if (slideProfiles.some(p => p.hasNotes))
51
+ flags.speakerNotes = true;
52
+ // Check for media files
53
+ const mediaFiles = Object.keys(zip.files).filter(name => /^ppt\/media\//.test(name));
54
+ if (mediaFiles.length > 0)
55
+ flags.embeddedMedia = true;
56
+ // Check for macros
57
+ if (zip.file('ppt/vbaProject.bin'))
58
+ flags.macros = true;
59
+ // Check for charts
60
+ const chartFiles = Object.keys(zip.files).filter(name => /^ppt\/charts\//.test(name));
61
+ if (chartFiles.length > 0)
62
+ flags.charts = true;
63
+ // Aggregate from profiles
64
+ if (slideProfiles.some(p => p.tables > 0))
65
+ flags.tables = true;
66
+ // Check slides for animations and hyperlinks
67
+ const slideFiles = Object.keys(zip.files)
68
+ .filter(name => /^ppt\/slides\/slide\d+\.xml$/.test(name))
69
+ .sort((a, b) => {
70
+ const numA = parseInt(a.match(/slide(\d+)/)?.[1] || '0', 10);
71
+ const numB = parseInt(b.match(/slide(\d+)/)?.[1] || '0', 10);
72
+ return numA - numB;
73
+ });
74
+ for (const slideFile of slideFiles) {
75
+ const xml = await zip.file(slideFile)?.async('text');
76
+ if (!xml)
77
+ continue;
78
+ if (/<p:transition\b/.test(xml) || /<p:anim\b/.test(xml) || /<p:animMotion\b/.test(xml)) {
79
+ flags.animations = true;
80
+ }
81
+ if (/<a:hlinkClick\b/.test(xml) || /<a:hlinkMouseOver\b/.test(xml)) {
82
+ flags.hyperlinks = true;
83
+ }
84
+ if (flags.animations && flags.hyperlinks)
85
+ break;
86
+ }
87
+ return flags;
88
+ }
89
+ export async function extractPptxSlideProfiles(zip) {
90
+ const slideFiles = Object.keys(zip.files)
91
+ .filter(name => /^ppt\/slides\/slide\d+\.xml$/.test(name))
92
+ .sort((a, b) => {
93
+ const numA = parseInt(a.match(/slide(\d+)/)?.[1] || '0', 10);
94
+ const numB = parseInt(b.match(/slide(\d+)/)?.[1] || '0', 10);
95
+ return numA - numB;
96
+ });
97
+ const profiles = [];
98
+ for (let i = 0; i < slideFiles.length; i++) {
99
+ const slideXml = await zip.file(slideFiles[i])?.async('text');
100
+ if (!slideXml)
101
+ continue;
102
+ // Extract title
103
+ let title = null;
104
+ // Look for title placeholder
105
+ const titleMatch = slideXml.match(/<p:sp>[\s\S]*?<p:ph[^>]*type="(?:title|ctrTitle)"[^>]*\/>[\s\S]*?<\/p:sp>/i);
106
+ if (titleMatch) {
107
+ const titleText = extractAllText(titleMatch[0]);
108
+ if (titleText)
109
+ title = titleText;
110
+ }
111
+ // Extract all text for word count
112
+ const allText = extractAllText(slideXml);
113
+ const words = countWords(allText);
114
+ // Count tables
115
+ const tables = (slideXml.match(/<a:tbl\b/g) || []).length;
116
+ // Count images
117
+ const images = (slideXml.match(/<p:pic\b/g) || []).length + (slideXml.match(/<a:blip\b/g) || []).length;
118
+ // Count charts (from relationships)
119
+ const slideNum = parseInt(slideFiles[i].match(/slide(\d+)/)?.[1] || '0', 10);
120
+ const relsFile = `ppt/slides/_rels/slide${slideNum}.xml.rels`;
121
+ const relsXml = await zip.file(relsFile)?.async('text');
122
+ const charts = relsXml ? (relsXml.match(/chart/gi) || []).length : 0;
123
+ // Check for speaker notes
124
+ const notesFile = `ppt/notesSlides/notesSlide${slideNum}.xml`;
125
+ const notesXml = await zip.file(notesFile)?.async('text');
126
+ let hasNotes = false;
127
+ let notePreview = null;
128
+ if (notesXml) {
129
+ const notesText = extractAllText(notesXml);
130
+ // Filter out slide number placeholder text
131
+ const cleanNotes = notesText.replace(/\d+/g, '').trim();
132
+ if (cleanNotes.length > 0) {
133
+ hasNotes = true;
134
+ notePreview = notesText.length > 200 ? notesText.slice(0, 200) + '...' : notesText;
135
+ }
136
+ }
137
+ profiles.push({
138
+ index: i + 1,
139
+ title,
140
+ words,
141
+ hasNotes,
142
+ notePreview,
143
+ images,
144
+ tables,
145
+ charts,
146
+ });
147
+ }
148
+ return profiles;
149
+ }
150
+ export async function inspectPptx(buffer) {
151
+ const zip = await JSZip.loadAsync(buffer);
152
+ const properties = await extractPptxProperties(zip);
153
+ const slideProfiles = await extractPptxSlideProfiles(zip);
154
+ const riskFlags = await extractPptxRiskFlags(zip, slideProfiles);
155
+ return { properties, riskFlags, slideProfiles };
156
+ }
157
+ //# sourceMappingURL=inspect-pptx.js.map