@willwade/aac-processors 0.0.6 → 0.0.8

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 (35) hide show
  1. package/README.md +2 -40
  2. package/dist/analytics/history.d.ts +57 -0
  3. package/dist/analytics/history.js +72 -0
  4. package/dist/core/analyze.d.ts +10 -0
  5. package/dist/core/analyze.js +10 -0
  6. package/dist/core/stringCasing.d.ts +11 -0
  7. package/dist/core/stringCasing.js +11 -0
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.js +5 -0
  10. package/dist/processors/dotProcessor.js +31 -12
  11. package/dist/processors/gridset/colorUtils.d.ts +69 -0
  12. package/dist/processors/gridset/colorUtils.js +331 -0
  13. package/dist/processors/gridset/helpers.d.ts +125 -0
  14. package/dist/processors/gridset/helpers.js +354 -0
  15. package/dist/processors/gridset/styleHelpers.d.ts +3 -4
  16. package/dist/processors/gridset/styleHelpers.js +10 -44
  17. package/dist/processors/index.d.ts +6 -4
  18. package/dist/processors/index.js +51 -3
  19. package/dist/processors/obfProcessor.js +10 -2
  20. package/dist/processors/snap/helpers.d.ts +85 -0
  21. package/dist/processors/snap/helpers.js +259 -2
  22. package/dist/processors/snapProcessor.js +27 -5
  23. package/dist/processors/touchchat/helpers.d.ts +12 -0
  24. package/dist/processors/touchchat/helpers.js +12 -2
  25. package/dist/utils/dotnetTicks.d.ts +13 -0
  26. package/dist/utils/dotnetTicks.js +21 -0
  27. package/package.json +8 -6
  28. package/docs/.keep +0 -1
  29. package/docs/ApplePanels.md +0 -309
  30. package/docs/Grid3-Styling-Guide.md +0 -287
  31. package/docs/Grid3-XML-Format.md +0 -1788
  32. package/docs/TobiiDynavox-Snap-Details.md +0 -394
  33. package/docs/asterics-Grid-fileformat-details.md +0 -443
  34. package/docs/obf_.obz Open Board File Formats.md +0 -432
  35. package/docs/touchchat.md +0 -520
@@ -1,4 +1,89 @@
1
1
  import { AACTree } from '../../core/treeStructure';
2
+ /**
3
+ * Build a map of button IDs to resolved image entries for a specific page.
4
+ * Mirrors the Grid helper for consumers that expect image reference data.
5
+ */
2
6
  export declare function getPageTokenImageMap(tree: AACTree, pageId: string): Map<string, string>;
7
+ /**
8
+ * Collect all image entry paths referenced in a Snap tree.
9
+ * Currently empty until resolvedImageEntry is populated by the processor.
10
+ */
3
11
  export declare function getAllowedImageEntries(_tree: AACTree): Set<string>;
12
+ /**
13
+ * Read a binary asset from a Snap pageset.
14
+ * Not implemented yet; provided for API symmetry with other processors.
15
+ */
4
16
  export declare function openImage(_dbOrFile: string | Buffer, _entryPath: string): Buffer | null;
17
+ /**
18
+ * Snap package path information
19
+ */
20
+ export interface SnapPackagePath {
21
+ packageName: string;
22
+ packagePath: string;
23
+ }
24
+ export interface SnapUserInfo {
25
+ userId: string;
26
+ userPath: string;
27
+ vocabPaths: string[];
28
+ }
29
+ export interface SnapUsageEntry {
30
+ id: string;
31
+ content: string;
32
+ occurrences: Array<{
33
+ timestamp: Date;
34
+ modeling?: boolean;
35
+ accessMethod?: number | null;
36
+ }>;
37
+ platform?: {
38
+ label?: string;
39
+ message?: string;
40
+ buttonId?: string;
41
+ };
42
+ }
43
+ /**
44
+ * Find Tobii Communicator Snap package paths
45
+ * Searches in %LOCALAPPDATA%\Packages for Snap-related packages
46
+ * @param packageNamePattern Optional pattern to filter package names (default: 'TobiiDynavox')
47
+ * @returns Array of Snap package path information
48
+ */
49
+ export declare function findSnapPackages(packageNamePattern?: string): SnapPackagePath[];
50
+ /**
51
+ * Find the first Snap package path matching the pattern
52
+ * Convenience method for when you expect only one Snap installation
53
+ * @param packageNamePattern Optional pattern to filter package names (default: 'TobiiDynavox')
54
+ * @returns Path to the first matching Snap package, or null if not found
55
+ */
56
+ export declare function findSnapPackagePath(packageNamePattern?: string): string | null;
57
+ /**
58
+ * Find Snap user directories and their vocab files (.sps/.spb)
59
+ * @param packageNamePattern Optional package filter (default TobiiDynavox)
60
+ * @returns Array of user info with vocab paths
61
+ */
62
+ export declare function findSnapUsers(packageNamePattern?: string): SnapUserInfo[];
63
+ /**
64
+ * Find vocab files for a specific Snap user (or all users)
65
+ * @param userId Optional user identifier filter (case-sensitive directory name)
66
+ * @param packageNamePattern Optional package filter
67
+ * @returns Array of vocab file paths
68
+ */
69
+ export declare function findSnapUserVocabularies(userId?: string, packageNamePattern?: string): string[];
70
+ /**
71
+ * Attempt to find history/analytics files for a Snap user by name
72
+ * Currently searches for files containing "history" under the user directory
73
+ * @param userId User identifier (directory name)
74
+ * @param packageNamePattern Optional package filter
75
+ * @returns Array of history file paths (may be empty if not found)
76
+ */
77
+ export declare function findSnapUserHistory(userId: string, packageNamePattern?: string): string[];
78
+ /**
79
+ * Check whether TD Snap appears to be installed (Windows only)
80
+ */
81
+ export declare function isSnapInstalled(packageNamePattern?: string): boolean;
82
+ /**
83
+ * Read Snap usage history from a pageset file (.sps/.spb)
84
+ */
85
+ export declare function readSnapUsage(pagesetPath: string): SnapUsageEntry[];
86
+ /**
87
+ * Read Snap usage history for a user (all pagesets)
88
+ */
89
+ export declare function readSnapUsageForUser(userId?: string, packageNamePattern?: string): SnapUsageEntry[];
@@ -1,11 +1,81 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
2
28
  Object.defineProperty(exports, "__esModule", { value: true });
3
29
  exports.getPageTokenImageMap = getPageTokenImageMap;
4
30
  exports.getAllowedImageEntries = getAllowedImageEntries;
5
31
  exports.openImage = openImage;
32
+ exports.findSnapPackages = findSnapPackages;
33
+ exports.findSnapPackagePath = findSnapPackagePath;
34
+ exports.findSnapUsers = findSnapUsers;
35
+ exports.findSnapUserVocabularies = findSnapUserVocabularies;
36
+ exports.findSnapUserHistory = findSnapUserHistory;
37
+ exports.isSnapInstalled = isSnapInstalled;
38
+ exports.readSnapUsage = readSnapUsage;
39
+ exports.readSnapUsageForUser = readSnapUsageForUser;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
43
+ const dotnetTicks_1 = require("../../utils/dotnetTicks");
6
44
  // Minimal Snap helpers (stubs) to align with processors/<engine>/helpers pattern
7
45
  // NOTE: Snap buttons currently do not populate resolvedImageEntry; these helpers
8
46
  // therefore return empty collections until image resolution is implemented.
47
+ function collectFiles(root, matcher, maxDepth = 3) {
48
+ const results = new Set();
49
+ const stack = [{ dir: root, depth: 0 }];
50
+ while (stack.length > 0) {
51
+ const current = stack.pop();
52
+ if (!current)
53
+ continue;
54
+ if (current.depth > maxDepth)
55
+ continue;
56
+ let entries;
57
+ try {
58
+ entries = fs.readdirSync(current.dir, { withFileTypes: true });
59
+ }
60
+ catch (error) {
61
+ continue;
62
+ }
63
+ for (const entry of entries) {
64
+ const fullPath = path.join(current.dir, entry.name);
65
+ if (entry.isDirectory()) {
66
+ stack.push({ dir: fullPath, depth: current.depth + 1 });
67
+ }
68
+ else if (matcher(fullPath)) {
69
+ results.add(fullPath);
70
+ }
71
+ }
72
+ }
73
+ return Array.from(results);
74
+ }
75
+ /**
76
+ * Build a map of button IDs to resolved image entries for a specific page.
77
+ * Mirrors the Grid helper for consumers that expect image reference data.
78
+ */
9
79
  function getPageTokenImageMap(tree, pageId) {
10
80
  const map = new Map();
11
81
  const page = tree.getPage(pageId);
@@ -17,11 +87,198 @@ function getPageTokenImageMap(tree, pageId) {
17
87
  }
18
88
  return map;
19
89
  }
90
+ /**
91
+ * Collect all image entry paths referenced in a Snap tree.
92
+ * Currently empty until resolvedImageEntry is populated by the processor.
93
+ */
20
94
  function getAllowedImageEntries(_tree) {
21
- // No known image entry paths for Snap yet
22
95
  return new Set();
23
96
  }
97
+ /**
98
+ * Read a binary asset from a Snap pageset.
99
+ * Not implemented yet; provided for API symmetry with other processors.
100
+ */
24
101
  function openImage(_dbOrFile, _entryPath) {
25
- // Not implemented for Snap yet
26
102
  return null;
27
103
  }
104
+ /**
105
+ * Find Tobii Communicator Snap package paths
106
+ * Searches in %LOCALAPPDATA%\Packages for Snap-related packages
107
+ * @param packageNamePattern Optional pattern to filter package names (default: 'TobiiDynavox')
108
+ * @returns Array of Snap package path information
109
+ */
110
+ function findSnapPackages(packageNamePattern = 'TobiiDynavox') {
111
+ const results = [];
112
+ // Only works on Windows
113
+ if (process.platform !== 'win32') {
114
+ return results;
115
+ }
116
+ try {
117
+ const localAppData = process.env.LOCALAPPDATA;
118
+ if (!localAppData) {
119
+ return results;
120
+ }
121
+ const packagesPath = path.join(localAppData, 'Packages');
122
+ // Check if Packages directory exists
123
+ if (!fs.existsSync(packagesPath)) {
124
+ return results;
125
+ }
126
+ // Enumerate packages
127
+ const packages = fs.readdirSync(packagesPath, { withFileTypes: true });
128
+ for (const packageDir of packages) {
129
+ if (!packageDir.isDirectory())
130
+ continue;
131
+ const packageName = packageDir.name;
132
+ // Filter by pattern
133
+ if (packageName.includes(packageNamePattern)) {
134
+ results.push({
135
+ packageName,
136
+ packagePath: path.join(packagesPath, packageName),
137
+ });
138
+ }
139
+ }
140
+ }
141
+ catch (error) {
142
+ // Silently fail if directory access fails
143
+ }
144
+ return results;
145
+ }
146
+ /**
147
+ * Find the first Snap package path matching the pattern
148
+ * Convenience method for when you expect only one Snap installation
149
+ * @param packageNamePattern Optional pattern to filter package names (default: 'TobiiDynavox')
150
+ * @returns Path to the first matching Snap package, or null if not found
151
+ */
152
+ function findSnapPackagePath(packageNamePattern = 'TobiiDynavox') {
153
+ const packages = findSnapPackages(packageNamePattern);
154
+ return packages.length > 0 ? packages[0].packagePath : null;
155
+ }
156
+ /**
157
+ * Find Snap user directories and their vocab files (.sps/.spb)
158
+ * @param packageNamePattern Optional package filter (default TobiiDynavox)
159
+ * @returns Array of user info with vocab paths
160
+ */
161
+ function findSnapUsers(packageNamePattern = 'TobiiDynavox') {
162
+ const results = [];
163
+ if (process.platform !== 'win32') {
164
+ return results;
165
+ }
166
+ const packagePath = findSnapPackagePath(packageNamePattern);
167
+ if (!packagePath) {
168
+ return results;
169
+ }
170
+ const usersRoot = path.join(packagePath, 'LocalState', 'Users');
171
+ if (!fs.existsSync(usersRoot)) {
172
+ return results;
173
+ }
174
+ const entries = fs.readdirSync(usersRoot, { withFileTypes: true });
175
+ for (const entry of entries) {
176
+ if (!entry.isDirectory())
177
+ continue;
178
+ if (entry.name.toLowerCase().startsWith('swiftkey'))
179
+ continue;
180
+ const userPath = path.join(usersRoot, entry.name);
181
+ const vocabPaths = collectFiles(userPath, (full) => {
182
+ const ext = path.extname(full).toLowerCase();
183
+ return ext === '.sps' || ext === '.spb';
184
+ }, 2);
185
+ results.push({
186
+ userId: entry.name,
187
+ userPath,
188
+ vocabPaths,
189
+ });
190
+ }
191
+ return results;
192
+ }
193
+ /**
194
+ * Find vocab files for a specific Snap user (or all users)
195
+ * @param userId Optional user identifier filter (case-sensitive directory name)
196
+ * @param packageNamePattern Optional package filter
197
+ * @returns Array of vocab file paths
198
+ */
199
+ function findSnapUserVocabularies(userId, packageNamePattern = 'TobiiDynavox') {
200
+ const users = findSnapUsers(packageNamePattern).filter((u) => !userId || u.userId === userId);
201
+ return users.flatMap((u) => u.vocabPaths);
202
+ }
203
+ /**
204
+ * Attempt to find history/analytics files for a Snap user by name
205
+ * Currently searches for files containing "history" under the user directory
206
+ * @param userId User identifier (directory name)
207
+ * @param packageNamePattern Optional package filter
208
+ * @returns Array of history file paths (may be empty if not found)
209
+ */
210
+ function findSnapUserHistory(userId, packageNamePattern = 'TobiiDynavox') {
211
+ const user = findSnapUsers(packageNamePattern).find((u) => u.userId === userId);
212
+ if (!user)
213
+ return [];
214
+ return collectFiles(user.userPath, (full) => path.basename(full).toLowerCase().includes('history'), 2);
215
+ }
216
+ /**
217
+ * Check whether TD Snap appears to be installed (Windows only)
218
+ */
219
+ function isSnapInstalled(packageNamePattern = 'TobiiDynavox') {
220
+ if (process.platform !== 'win32')
221
+ return false;
222
+ return Boolean(findSnapPackagePath(packageNamePattern));
223
+ }
224
+ /**
225
+ * Read Snap usage history from a pageset file (.sps/.spb)
226
+ */
227
+ function readSnapUsage(pagesetPath) {
228
+ if (!fs.existsSync(pagesetPath))
229
+ return [];
230
+ const db = new better_sqlite3_1.default(pagesetPath, { readonly: true });
231
+ const tableCheck = db
232
+ .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name IN ('ButtonUsage','Button')")
233
+ .all();
234
+ if (tableCheck.length < 2)
235
+ return [];
236
+ const rows = db
237
+ .prepare(`
238
+ SELECT
239
+ bu.ButtonUniqueId as ButtonId,
240
+ bu.Timestamp as TickValue,
241
+ bu.Modeling as Modeling,
242
+ bu.AccessMethod as AccessMethod,
243
+ b.Label as Label,
244
+ b.Message as Message
245
+ FROM ButtonUsage bu
246
+ LEFT JOIN Button b ON bu.ButtonUniqueId = b.UniqueId
247
+ WHERE bu.Timestamp IS NOT NULL
248
+ ORDER BY bu.Timestamp ASC
249
+ `)
250
+ .all();
251
+ const events = new Map();
252
+ for (const row of rows) {
253
+ const buttonId = row.ButtonId ?? 'unknown';
254
+ const label = row.Label ?? undefined;
255
+ const message = row.Message ?? undefined;
256
+ const content = message || label || '';
257
+ const entry = events.get(buttonId) ??
258
+ {
259
+ id: `snap:${buttonId}`,
260
+ content,
261
+ occurrences: [],
262
+ platform: {
263
+ label,
264
+ message,
265
+ buttonId,
266
+ },
267
+ };
268
+ entry.occurrences.push({
269
+ timestamp: (0, dotnetTicks_1.dotNetTicksToDate)(BigInt(row.TickValue ?? 0)),
270
+ modeling: row.Modeling === 1,
271
+ accessMethod: row.AccessMethod ?? null,
272
+ });
273
+ events.set(buttonId, entry);
274
+ }
275
+ return Array.from(events.values());
276
+ }
277
+ /**
278
+ * Read Snap usage history for a user (all pagesets)
279
+ */
280
+ function readSnapUsageForUser(userId, packageNamePattern = 'TobiiDynavox') {
281
+ const users = findSnapUsers(packageNamePattern).filter((u) => !userId || u.userId === userId);
282
+ const pagesets = users.flatMap((u) => u.vocabPaths);
283
+ return pagesets.flatMap((p) => readSnapUsage(p));
284
+ }
@@ -476,11 +476,33 @@ class SnapProcessor extends baseProcessor_1.BaseProcessor {
476
476
  serializedMetadata = audio.metadata || null;
477
477
  useMessageRecording = 1;
478
478
  }
479
- insertButton.run(buttonIdCounter++, button.label || '', button.message || button.label || '', navigatePageId, elementRefId, null, null, messageRecordingId, serializedMetadata, useMessageRecording, button.style?.fontColor ? parseInt(button.style.fontColor.replace('#', ''), 16) : null, button.style?.backgroundColor
480
- ? parseInt(button.style.backgroundColor.replace('#', ''), 16)
481
- : null, button.style?.borderColor
482
- ? parseInt(button.style.borderColor.replace('#', ''), 16)
483
- : null, button.style?.borderWidth, button.style?.fontSize, button.style?.fontFamily, button.style?.fontStyle ? parseInt(button.style.fontStyle) : null);
479
+ // Retry logic for SQLite operations
480
+ let retries = 3;
481
+ while (retries > 0) {
482
+ try {
483
+ insertButton.run(buttonIdCounter++, button.label || '', button.message || button.label || '', navigatePageId, elementRefId, null, null, messageRecordingId, serializedMetadata, useMessageRecording, button.style?.fontColor
484
+ ? parseInt(button.style.fontColor.replace('#', ''), 16)
485
+ : null, button.style?.backgroundColor
486
+ ? parseInt(button.style.backgroundColor.replace('#', ''), 16)
487
+ : null, button.style?.borderColor
488
+ ? parseInt(button.style.borderColor.replace('#', ''), 16)
489
+ : null, button.style?.borderWidth, button.style?.fontSize, button.style?.fontFamily, button.style?.fontStyle ? parseInt(button.style.fontStyle) : null);
490
+ break; // Success
491
+ }
492
+ catch (err) {
493
+ if (err.code === 'SQLITE_IOERR' && retries > 1) {
494
+ retries--;
495
+ // Wait a bit before retrying
496
+ const now = Date.now();
497
+ while (Date.now() - now < 100) {
498
+ /* busy wait */
499
+ }
500
+ }
501
+ else {
502
+ throw err;
503
+ }
504
+ }
505
+ }
484
506
  // Insert ElementPlacement
485
507
  const insertPlacement = db.prepare('INSERT INTO ElementPlacement (Id, ElementReferenceId, GridPosition) VALUES (?, ?, ?)');
486
508
  insertPlacement.run(placementIdCounter++, elementRefId, gridPosition);
@@ -1,4 +1,16 @@
1
1
  import { AACTree } from '../../core/treeStructure';
2
+ /**
3
+ * Build a map of button IDs to resolved image entry strings for a page.
4
+ * Returns an empty map when no images are present.
5
+ */
2
6
  export declare function getPageTokenImageMap(tree: AACTree, pageId: string): Map<string, string>;
7
+ /**
8
+ * Collect all referenced image entries across the tree.
9
+ * Currently empty until TouchChat image resolution is implemented.
10
+ */
3
11
  export declare function getAllowedImageEntries(_tree: AACTree): Set<string>;
12
+ /**
13
+ * Read a binary asset from a .ce file.
14
+ * Not implemented yet; provided for API symmetry with other processors.
15
+ */
4
16
  export declare function openImage(_ceFile: string | Buffer, _entryPath: string): Buffer | null;
@@ -6,6 +6,10 @@ exports.openImage = openImage;
6
6
  // Minimal TouchChat helpers (stubs) to align with processors/<engine>/helpers pattern
7
7
  // NOTE: TouchChat buttons currently do not populate resolvedImageEntry; these helpers
8
8
  // therefore return empty collections until image resolution is implemented.
9
+ /**
10
+ * Build a map of button IDs to resolved image entry strings for a page.
11
+ * Returns an empty map when no images are present.
12
+ */
9
13
  function getPageTokenImageMap(tree, pageId) {
10
14
  const map = new Map();
11
15
  const page = tree.getPage(pageId);
@@ -17,11 +21,17 @@ function getPageTokenImageMap(tree, pageId) {
17
21
  }
18
22
  return map;
19
23
  }
24
+ /**
25
+ * Collect all referenced image entries across the tree.
26
+ * Currently empty until TouchChat image resolution is implemented.
27
+ */
20
28
  function getAllowedImageEntries(_tree) {
21
- // No known image entry paths for TouchChat yet
22
29
  return new Set();
23
30
  }
31
+ /**
32
+ * Read a binary asset from a .ce file.
33
+ * Not implemented yet; provided for API symmetry with other processors.
34
+ */
24
35
  function openImage(_ceFile, _entryPath) {
25
- // Not implemented for TouchChat yet
26
36
  return null;
27
37
  }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Number of ticks (.NET 100ns units) between 0001-01-01 and Unix epoch.
3
+ */
4
+ export declare const DOTNET_EPOCH_TICKS = 621355968000000000n;
5
+ /**
6
+ * Number of ticks per millisecond.
7
+ */
8
+ export declare const TICKS_PER_MILLISECOND = 10000n;
9
+ /**
10
+ * Convert .NET ticks (100ns since 0001-01-01) to a JavaScript Date.
11
+ * Accepts bigint or number and rounds down to millisecond precision.
12
+ */
13
+ export declare function dotNetTicksToDate(ticks: number | bigint): Date;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TICKS_PER_MILLISECOND = exports.DOTNET_EPOCH_TICKS = void 0;
4
+ exports.dotNetTicksToDate = dotNetTicksToDate;
5
+ /**
6
+ * Number of ticks (.NET 100ns units) between 0001-01-01 and Unix epoch.
7
+ */
8
+ exports.DOTNET_EPOCH_TICKS = 621355968000000000n;
9
+ /**
10
+ * Number of ticks per millisecond.
11
+ */
12
+ exports.TICKS_PER_MILLISECOND = 10000n;
13
+ /**
14
+ * Convert .NET ticks (100ns since 0001-01-01) to a JavaScript Date.
15
+ * Accepts bigint or number and rounds down to millisecond precision.
16
+ */
17
+ function dotNetTicksToDate(ticks) {
18
+ const tickValue = BigInt(ticks);
19
+ const ms = Number((tickValue - exports.DOTNET_EPOCH_TICKS) / exports.TICKS_PER_MILLISECOND);
20
+ return new Date(ms);
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@willwade/aac-processors",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "A comprehensive TypeScript library for processing AAC (Augmentative and Alternative Communication) file formats with translation support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -17,17 +17,18 @@
17
17
  "test": "test"
18
18
  },
19
19
  "scripts": {
20
- "build": "rimraf dist && mkdir dist && ./node_modules/typescript/bin/tsc",
20
+ "build": "rimraf dist && mkdir dist && tsc",
21
21
  "build:watch": "tsc --watch",
22
22
  "clean": "rimraf dist coverage",
23
- "lint": "eslint 'src/**/*.{js,ts}' 'test/**/*.{js,ts}'",
24
- "lint:fix": "eslint 'src/**/*.{js,ts}' 'test/**/*.{js,ts}' --fix",
25
- "format": "prettier --write 'src/**/*.{js,ts}' 'test/**/*.{js,ts}' '*.{js,ts,json,md}'",
26
- "format:check": "prettier --check 'src/**/*.{js,ts}' 'test/**/*.{js,ts}' '*.{js,ts,json,md}'",
23
+ "lint": "eslint \"src/**/*.{js,ts}\" \"test/**/*.{js,ts}\"",
24
+ "lint:fix": "eslint \"src/**/*.{js,ts}\" \"test/**/*.{js,ts}\" --fix",
25
+ "format": "prettier --write \"src/**/*.{js,ts}\" \"test/**/*.{js,ts}\" \"*.{js,ts,json,md}\"",
26
+ "format:check": "prettier --check \"src/**/*.{js,ts}\" \"test/**/*.{js,ts}\" \"*.{js,ts,json,md}\"",
27
27
  "test": "npm run build && jest",
28
28
  "test:watch": "npm run build && jest --watch",
29
29
  "test:coverage": "npm run build && jest --coverage",
30
30
  "test:ci": "npm run build && jest --coverage --ci --watchAll=false --testTimeout=30000",
31
+ "docs": "typedoc",
31
32
  "coverage:report": "node scripts/coverage-analysis.js",
32
33
  "type-check": "tsc --noEmit",
33
34
  "prepublishOnly": "npm run build",
@@ -88,6 +89,7 @@
88
89
  "prettier": "^3.5.3",
89
90
  "rimraf": "^5.0.5",
90
91
  "ts-jest": "^29.1.2",
92
+ "typedoc": "^0.28.14",
91
93
  "typescript": "~5.5.0"
92
94
  },
93
95
  "dependencies": {
package/docs/.keep DELETED
@@ -1 +0,0 @@
1
-