@willwade/aac-processors 0.1.20 → 0.2.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.
- package/dist/browser/core/baseProcessor.js +4 -0
- package/dist/browser/processors/applePanelsProcessor.js +33 -40
- package/dist/browser/processors/astericsGridProcessor.js +31 -26
- package/dist/browser/processors/dotProcessor.js +11 -12
- package/dist/browser/processors/gridset/colorUtils.js +354 -0
- package/dist/browser/processors/gridset/helpers.js +60 -53
- package/dist/browser/processors/gridset/index.js +61 -0
- package/dist/browser/processors/gridset/styleHelpers.js +205 -0
- package/dist/browser/processors/gridset/symbolExtractor.js +331 -0
- package/dist/browser/processors/gridset/symbolSearch.js +248 -0
- package/dist/browser/processors/gridset/symbols.js +39 -72
- package/dist/browser/processors/gridsetProcessor.js +39 -48
- package/dist/browser/processors/obfProcessor.js +39 -53
- package/dist/browser/processors/opmlProcessor.js +11 -12
- package/dist/browser/processors/snap/helpers.js +57 -49
- package/dist/browser/processors/snapProcessor.js +48 -51
- package/dist/browser/processors/touchchatProcessor.js +60 -52
- package/dist/browser/utilities/analytics/history.js +24 -18
- package/dist/browser/utilities/analytics/metrics/comparison.js +16 -16
- package/dist/browser/utilities/analytics/metrics/vocabulary.js +2 -2
- package/dist/browser/utilities/analytics/reference/browser.js +16 -16
- package/dist/browser/utilities/analytics/reference/index.js +44 -35
- package/dist/browser/utils/io.js +78 -21
- package/dist/browser/utils/sqlite.js +8 -10
- package/dist/browser/utils/zip.js +43 -43
- package/dist/browser/validation/baseValidator.js +5 -0
- package/dist/browser/validation/gridsetValidator.js +12 -20
- package/dist/browser/validation/obfValidator.js +6 -5
- package/dist/browser/validation/snapValidator.js +11 -7
- package/dist/browser/validation/touchChatValidator.js +23 -13
- package/dist/cli/index.js +22 -24
- package/dist/core/baseProcessor.d.ts +7 -7
- package/dist/core/baseProcessor.js +4 -0
- package/dist/processors/applePanelsProcessor.js +32 -39
- package/dist/processors/astericsGridProcessor.d.ts +4 -4
- package/dist/processors/astericsGridProcessor.js +30 -25
- package/dist/processors/dotProcessor.js +10 -11
- package/dist/processors/excelProcessor.d.ts +3 -3
- package/dist/processors/excelProcessor.js +14 -20
- package/dist/processors/gridset/helpers.d.ts +12 -14
- package/dist/processors/gridset/helpers.js +60 -79
- package/dist/processors/gridset/imageDebug.d.ts +3 -5
- package/dist/processors/gridset/imageDebug.js +4 -4
- package/dist/processors/gridset/password.d.ts +1 -1
- package/dist/processors/gridset/symbolExtractor.d.ts +5 -3
- package/dist/processors/gridset/symbolExtractor.js +15 -38
- package/dist/processors/gridset/symbolSearch.d.ts +11 -10
- package/dist/processors/gridset/symbolSearch.js +29 -51
- package/dist/processors/gridset/symbols.d.ts +8 -6
- package/dist/processors/gridset/symbols.js +38 -71
- package/dist/processors/gridset/wordlistHelpers.d.ts +4 -6
- package/dist/processors/gridset/wordlistHelpers.js +15 -74
- package/dist/processors/gridsetProcessor.d.ts +2 -2
- package/dist/processors/gridsetProcessor.js +38 -70
- package/dist/processors/obfProcessor.d.ts +2 -2
- package/dist/processors/obfProcessor.js +38 -75
- package/dist/processors/obfsetProcessor.js +2 -3
- package/dist/processors/opmlProcessor.js +10 -11
- package/dist/processors/snap/helpers.d.ts +9 -9
- package/dist/processors/snap/helpers.js +58 -76
- package/dist/processors/snapProcessor.d.ts +2 -2
- package/dist/processors/snapProcessor.js +47 -50
- package/dist/processors/touchchatProcessor.d.ts +2 -2
- package/dist/processors/touchchatProcessor.js +59 -51
- package/dist/types/aac.d.ts +2 -2
- package/dist/utilities/analytics/history.d.ts +8 -8
- package/dist/utilities/analytics/history.js +24 -18
- package/dist/utilities/analytics/index.d.ts +3 -2
- package/dist/utilities/analytics/index.js +9 -10
- package/dist/utilities/analytics/metrics/comparison.d.ts +1 -1
- package/dist/utilities/analytics/metrics/comparison.js +16 -16
- package/dist/utilities/analytics/metrics/vocabulary.d.ts +1 -1
- package/dist/utilities/analytics/metrics/vocabulary.js +2 -2
- package/dist/utilities/analytics/reference/browser.d.ts +9 -9
- package/dist/utilities/analytics/reference/browser.js +16 -16
- package/dist/utilities/analytics/reference/index.d.ts +25 -23
- package/dist/utilities/analytics/reference/index.js +43 -34
- package/dist/utilities/symbolTools.d.ts +8 -6
- package/dist/utilities/symbolTools.js +21 -18
- package/dist/utils/io.d.ts +24 -6
- package/dist/utils/io.js +79 -25
- package/dist/utils/sqlite.d.ts +3 -1
- package/dist/utils/sqlite.js +7 -9
- package/dist/utils/zip.d.ts +7 -3
- package/dist/utils/zip.js +43 -43
- package/dist/validation/applePanelsValidator.d.ts +2 -1
- package/dist/validation/applePanelsValidator.js +10 -11
- package/dist/validation/astericsValidator.d.ts +2 -1
- package/dist/validation/astericsValidator.js +5 -4
- package/dist/validation/baseValidator.d.ts +2 -2
- package/dist/validation/baseValidator.js +5 -0
- package/dist/validation/dotValidator.d.ts +2 -1
- package/dist/validation/dotValidator.js +5 -4
- package/dist/validation/excelValidator.d.ts +2 -1
- package/dist/validation/excelValidator.js +5 -4
- package/dist/validation/gridsetValidator.d.ts +2 -1
- package/dist/validation/gridsetValidator.js +11 -22
- package/dist/validation/index.d.ts +2 -2
- package/dist/validation/index.js +5 -4
- package/dist/validation/obfValidator.d.ts +2 -1
- package/dist/validation/obfValidator.js +5 -4
- package/dist/validation/obfsetValidator.d.ts +2 -1
- package/dist/validation/obfsetValidator.js +5 -4
- package/dist/validation/opmlValidator.d.ts +2 -1
- package/dist/validation/opmlValidator.js +5 -4
- package/dist/validation/snapValidator.d.ts +2 -1
- package/dist/validation/snapValidator.js +10 -6
- package/dist/validation/touchChatValidator.d.ts +4 -6
- package/dist/validation/touchChatValidator.js +22 -12
- package/dist/validation/validationTypes.d.ts +8 -1
- package/package.json +1 -1
- package/dist/core/fileProcessor.d.ts +0 -7
- package/dist/core/fileProcessor.js +0 -57
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import * as xml2js from 'xml2js';
|
|
4
4
|
import JSZip from 'jszip';
|
|
5
5
|
import { BaseValidator } from './baseValidator';
|
|
6
|
-
import {
|
|
6
|
+
import { defaultFileAdapter, getBasename, toUint8Array } from '../utils/io';
|
|
7
7
|
import { openSqliteDatabase } from '../utils/sqlite';
|
|
8
8
|
/**
|
|
9
9
|
* Validator for Snap files (.spb, .sps)
|
|
@@ -16,11 +16,12 @@ export class SnapValidator extends BaseValidator {
|
|
|
16
16
|
/**
|
|
17
17
|
* Validate a Snap file from disk
|
|
18
18
|
*/
|
|
19
|
-
static async validateFile(filePath) {
|
|
19
|
+
static async validateFile(filePath, fileAdapter) {
|
|
20
|
+
const { readBinaryFromInput, getFileSize } = fileAdapter ?? defaultFileAdapter;
|
|
20
21
|
const validator = new SnapValidator();
|
|
21
|
-
const content = readBinaryFromInput(filePath);
|
|
22
|
-
const
|
|
23
|
-
return validator.validate(content, getBasename(filePath),
|
|
22
|
+
const content = await readBinaryFromInput(filePath);
|
|
23
|
+
const size = await getFileSize(filePath);
|
|
24
|
+
return validator.validate(content, getBasename(filePath), size);
|
|
24
25
|
}
|
|
25
26
|
/**
|
|
26
27
|
* Check if content is Snap format
|
|
@@ -158,7 +159,10 @@ export class SnapValidator extends BaseValidator {
|
|
|
158
159
|
await this.add_check('sqlite', 'valid SQLite database', async () => {
|
|
159
160
|
let cleanup;
|
|
160
161
|
try {
|
|
161
|
-
const result = await openSqliteDatabase(content, {
|
|
162
|
+
const result = await openSqliteDatabase(content, {
|
|
163
|
+
readonly: true,
|
|
164
|
+
fileAdapter: this._options.fileAdapter,
|
|
165
|
+
});
|
|
162
166
|
const db = result.db;
|
|
163
167
|
cleanup = result.cleanup;
|
|
164
168
|
const tableRows = db
|
|
@@ -205,7 +209,7 @@ export class SnapValidator extends BaseValidator {
|
|
|
205
209
|
}
|
|
206
210
|
finally {
|
|
207
211
|
if (cleanup) {
|
|
208
|
-
cleanup();
|
|
212
|
+
await cleanup();
|
|
209
213
|
}
|
|
210
214
|
}
|
|
211
215
|
});
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
4
4
|
import * as xml2js from 'xml2js';
|
|
5
5
|
import { BaseValidator } from './baseValidator';
|
|
6
|
-
import { decodeText,
|
|
7
|
-
import { openZipFromInput } from '../utils/zip';
|
|
6
|
+
import { decodeText, defaultFileAdapter, getBasename, toUint8Array, } from '../utils/io';
|
|
8
7
|
import { openSqliteDatabase } from '../utils/sqlite';
|
|
8
|
+
import { getZipAdapter } from '../utils/zip';
|
|
9
9
|
/**
|
|
10
10
|
* Validator for TouchChat files (.ce)
|
|
11
11
|
* TouchChat files are ZIP archives that contain a .c4v SQLite database.
|
|
@@ -18,23 +18,26 @@ export class TouchChatValidator extends BaseValidator {
|
|
|
18
18
|
/**
|
|
19
19
|
* Validate a TouchChat file from disk
|
|
20
20
|
*/
|
|
21
|
-
static async validateFile(filePath) {
|
|
21
|
+
static async validateFile(filePath, fileAdapter) {
|
|
22
|
+
const { readBinaryFromInput, getFileSize } = fileAdapter ?? defaultFileAdapter;
|
|
22
23
|
const validator = new TouchChatValidator();
|
|
23
|
-
const content = readBinaryFromInput(filePath);
|
|
24
|
-
const
|
|
25
|
-
return validator.validate(content, getBasename(filePath),
|
|
24
|
+
const content = await readBinaryFromInput(filePath);
|
|
25
|
+
const size = await getFileSize(filePath);
|
|
26
|
+
return validator.validate(content, getBasename(filePath), size);
|
|
26
27
|
}
|
|
27
28
|
/**
|
|
28
29
|
* Check if content is TouchChat format
|
|
29
30
|
*/
|
|
30
|
-
static async identifyFormat(content, filename, zipAdapter) {
|
|
31
|
+
static async identifyFormat(content, filename, fileAdapter = defaultFileAdapter, zipAdapter) {
|
|
31
32
|
const name = filename.toLowerCase();
|
|
32
33
|
if (name.endsWith('.ce')) {
|
|
33
34
|
return true;
|
|
34
35
|
}
|
|
35
36
|
// Try to parse as ZIP and check for .c4v database
|
|
36
37
|
try {
|
|
37
|
-
const
|
|
38
|
+
const zip = zipAdapter
|
|
39
|
+
? await zipAdapter(content)
|
|
40
|
+
: await getZipAdapter(content, fileAdapter);
|
|
38
41
|
const entries = zip.listFiles();
|
|
39
42
|
if (entries.some((entry) => entry.toLowerCase().endsWith('.c4v'))) {
|
|
40
43
|
return true;
|
|
@@ -66,7 +69,9 @@ export class TouchChatValidator extends BaseValidator {
|
|
|
66
69
|
}
|
|
67
70
|
});
|
|
68
71
|
const looksLikeXml = this.isXmlBuffer(content);
|
|
69
|
-
const zipped = looksLikeXml
|
|
72
|
+
const zipped = looksLikeXml
|
|
73
|
+
? false
|
|
74
|
+
: await this.tryValidateZipSqlite(content, this._options.fileAdapter, this._options.zipAdapter);
|
|
70
75
|
if (!zipped) {
|
|
71
76
|
let xmlObj = null;
|
|
72
77
|
await this.add_check('xml_parse', 'valid XML', async () => {
|
|
@@ -246,11 +251,13 @@ export class TouchChatValidator extends BaseValidator {
|
|
|
246
251
|
}
|
|
247
252
|
return bytes[start] === 0x3c; // '<'
|
|
248
253
|
}
|
|
249
|
-
async tryValidateZipSqlite(content) {
|
|
254
|
+
async tryValidateZipSqlite(content, fileAdapter = defaultFileAdapter, zipAdapter) {
|
|
250
255
|
let usedZip = false;
|
|
251
256
|
await this.add_check('zip', 'TouchChat ZIP package', async () => {
|
|
252
257
|
try {
|
|
253
|
-
const
|
|
258
|
+
const zip = zipAdapter
|
|
259
|
+
? await zipAdapter(content)
|
|
260
|
+
: await getZipAdapter(content, fileAdapter);
|
|
254
261
|
const entries = zip.listFiles();
|
|
255
262
|
const vocabEntry = entries.find((name) => name.toLowerCase().endsWith('.c4v'));
|
|
256
263
|
if (!vocabEntry) {
|
|
@@ -275,7 +282,10 @@ export class TouchChatValidator extends BaseValidator {
|
|
|
275
282
|
await this.add_check('sqlite', 'valid TouchChat SQLite database', async () => {
|
|
276
283
|
let cleanup;
|
|
277
284
|
try {
|
|
278
|
-
const result = await openSqliteDatabase(content, {
|
|
285
|
+
const result = await openSqliteDatabase(content, {
|
|
286
|
+
readonly: true,
|
|
287
|
+
fileAdapter: this._options.fileAdapter,
|
|
288
|
+
});
|
|
279
289
|
const db = result.db;
|
|
280
290
|
cleanup = result.cleanup;
|
|
281
291
|
const tableRows = db
|
|
@@ -325,7 +335,7 @@ export class TouchChatValidator extends BaseValidator {
|
|
|
325
335
|
}
|
|
326
336
|
finally {
|
|
327
337
|
if (cleanup) {
|
|
328
|
-
cleanup();
|
|
338
|
+
await cleanup();
|
|
329
339
|
}
|
|
330
340
|
}
|
|
331
341
|
});
|
package/dist/cli/index.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
-
};
|
|
6
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
4
|
const commander_1 = require("commander");
|
|
8
5
|
const prettyPrint_1 = require("./prettyPrint");
|
|
@@ -10,13 +7,14 @@ const analyze_1 = require("../core/analyze");
|
|
|
10
7
|
const history_1 = require("../utilities/analytics/history");
|
|
11
8
|
const analytics_1 = require("../utilities/analytics");
|
|
12
9
|
const aac_1 = require("../types/aac");
|
|
13
|
-
const
|
|
14
|
-
const
|
|
10
|
+
const io_1 = require("../utils/io");
|
|
11
|
+
const node_fs_1 = require("node:fs");
|
|
12
|
+
const { pathExists, isDirectory, join, basename, writeTextToPath } = io_1.defaultFileAdapter;
|
|
15
13
|
// Helper function to detect format from file/folder path
|
|
16
|
-
function detectFormat(filePath) {
|
|
14
|
+
async function detectFormat(filePath) {
|
|
17
15
|
// Check if it's a folder ending with .ascconfig
|
|
18
|
-
if (
|
|
19
|
-
|
|
16
|
+
if ((await pathExists(filePath)) &&
|
|
17
|
+
(await isDirectory(filePath)) &&
|
|
20
18
|
filePath.endsWith('.ascconfig')) {
|
|
21
19
|
return 'ascconfig';
|
|
22
20
|
}
|
|
@@ -28,7 +26,7 @@ function detectFormat(filePath) {
|
|
|
28
26
|
return 'gridset';
|
|
29
27
|
}
|
|
30
28
|
// Otherwise use file extension
|
|
31
|
-
return
|
|
29
|
+
return (0, io_1.extname)(filePath).slice(1);
|
|
32
30
|
}
|
|
33
31
|
// Helper function to parse filtering options from CLI arguments
|
|
34
32
|
function parseFilteringOptions(options) {
|
|
@@ -66,7 +64,7 @@ function parseFilteringOptions(options) {
|
|
|
66
64
|
return processorOptions;
|
|
67
65
|
}
|
|
68
66
|
// Set version from package.json
|
|
69
|
-
const packageJson = JSON.parse(
|
|
67
|
+
const packageJson = JSON.parse((0, node_fs_1.readFileSync)(join(__dirname, '../../package.json'), 'utf8'));
|
|
70
68
|
commander_1.program.version(packageJson.version);
|
|
71
69
|
commander_1.program
|
|
72
70
|
.command('analyze <file>')
|
|
@@ -82,7 +80,7 @@ commander_1.program
|
|
|
82
80
|
// Parse filtering options
|
|
83
81
|
const filteringOptions = parseFilteringOptions(options);
|
|
84
82
|
// Auto-detect format if not specified
|
|
85
|
-
const format = options.format || detectFormat(file);
|
|
83
|
+
const format = options.format || (await detectFormat(file));
|
|
86
84
|
const processor = (0, analyze_1.getProcessor)(format, filteringOptions);
|
|
87
85
|
const tree = await processor.loadIntoTree(file);
|
|
88
86
|
const result = {
|
|
@@ -117,7 +115,7 @@ commander_1.program
|
|
|
117
115
|
// Parse filtering options
|
|
118
116
|
const filteringOptions = parseFilteringOptions(options);
|
|
119
117
|
// Auto-detect format if not specified
|
|
120
|
-
const format = options.format || detectFormat(file);
|
|
118
|
+
const format = options.format || (await detectFormat(file));
|
|
121
119
|
const processor = (0, analyze_1.getProcessor)(format, filteringOptions);
|
|
122
120
|
const texts = await processor.extractTexts(file);
|
|
123
121
|
if (!options.quiet) {
|
|
@@ -167,7 +165,7 @@ commander_1.program
|
|
|
167
165
|
// Parse filtering options
|
|
168
166
|
const filteringOptions = parseFilteringOptions(options);
|
|
169
167
|
// Auto-detect input format
|
|
170
|
-
const inputFormat = detectFormat(input);
|
|
168
|
+
const inputFormat = await detectFormat(input);
|
|
171
169
|
const inputProcessor = (0, analyze_1.getProcessor)(inputFormat, filteringOptions);
|
|
172
170
|
// Load the tree (handle both files and folders)
|
|
173
171
|
const tree = await inputProcessor.loadIntoTree(input);
|
|
@@ -208,7 +206,7 @@ commander_1.program
|
|
|
208
206
|
.action(async (file, options) => {
|
|
209
207
|
try {
|
|
210
208
|
// Auto-detect format if not specified
|
|
211
|
-
const format = options.format || detectFormat(file);
|
|
209
|
+
const format = options.format || (await detectFormat(file));
|
|
212
210
|
// Get processor with gridset password if provided
|
|
213
211
|
const processorOptions = {};
|
|
214
212
|
if (options.gridsetPassword) {
|
|
@@ -288,21 +286,21 @@ commander_1.program
|
|
|
288
286
|
.option('--export-date <iso>', 'Export date for baton export (ISO string)')
|
|
289
287
|
.option('--encryption <mode>', 'Encryption label for baton export', 'none')
|
|
290
288
|
.option('--version <version>', 'Baton export version', '1.0')
|
|
291
|
-
.action((input, options) => {
|
|
289
|
+
.action(async (input, options) => {
|
|
292
290
|
try {
|
|
293
|
-
if (!
|
|
291
|
+
if (!(await pathExists(input))) {
|
|
294
292
|
throw new Error(`File not found: ${input}`);
|
|
295
293
|
}
|
|
296
294
|
const normalizedSource = (options.source || 'auto').toLowerCase();
|
|
297
|
-
const ext =
|
|
298
|
-
const isGrid3Db = ext === '.sqlite' ||
|
|
295
|
+
const ext = (0, io_1.extname)(input).toLowerCase();
|
|
296
|
+
const isGrid3Db = ext === '.sqlite' || basename(input).toLowerCase() === 'history.sqlite';
|
|
299
297
|
const isSnap = ext === '.sps' || ext === '.spb';
|
|
300
298
|
let entries;
|
|
301
299
|
if (normalizedSource === 'grid3' || (normalizedSource === 'auto' && isGrid3Db)) {
|
|
302
|
-
entries = (0, history_1.readGrid3History)(input);
|
|
300
|
+
entries = await (0, history_1.readGrid3History)(input);
|
|
303
301
|
}
|
|
304
302
|
else if (normalizedSource === 'snap' || (normalizedSource === 'auto' && isSnap)) {
|
|
305
|
-
entries = (0, history_1.readSnapUsage)(input);
|
|
303
|
+
entries = await (0, history_1.readSnapUsage)(input);
|
|
306
304
|
}
|
|
307
305
|
else {
|
|
308
306
|
throw new Error('Unable to detect history source. Use --source grid3 or --source snap.');
|
|
@@ -322,7 +320,7 @@ commander_1.program
|
|
|
322
320
|
}
|
|
323
321
|
const output = JSON.stringify(payload, null, 2);
|
|
324
322
|
if (options.out) {
|
|
325
|
-
|
|
323
|
+
await writeTextToPath(options.out, output);
|
|
326
324
|
}
|
|
327
325
|
else {
|
|
328
326
|
console.log(output);
|
|
@@ -353,7 +351,7 @@ commander_1.program
|
|
|
353
351
|
.action(async (file, options) => {
|
|
354
352
|
try {
|
|
355
353
|
const filteringOptions = parseFilteringOptions(options);
|
|
356
|
-
const format = options.format || detectFormat(file);
|
|
354
|
+
const format = options.format || (await detectFormat(file));
|
|
357
355
|
const processor = (0, analyze_1.getProcessor)(format, filteringOptions);
|
|
358
356
|
const tree = await processor.loadIntoTree(file);
|
|
359
357
|
const accessMethod = (options.accessMethod || 'direct').toLowerCase();
|
|
@@ -408,7 +406,7 @@ commander_1.program
|
|
|
408
406
|
let care = undefined;
|
|
409
407
|
if (options.care) {
|
|
410
408
|
const comparison = new analytics_1.ComparisonAnalyzer();
|
|
411
|
-
care = comparison.compare(metrics, metrics, {
|
|
409
|
+
care = await comparison.compare(metrics, metrics, {
|
|
412
410
|
includeSentences: true,
|
|
413
411
|
usePrediction: !!options.usePrediction,
|
|
414
412
|
scanningConfig,
|
|
@@ -426,7 +424,7 @@ commander_1.program
|
|
|
426
424
|
};
|
|
427
425
|
const output = options.pretty ? JSON.stringify(result, null, 2) : JSON.stringify(result);
|
|
428
426
|
if (options.out) {
|
|
429
|
-
|
|
427
|
+
await writeTextToPath(options.out, output);
|
|
430
428
|
}
|
|
431
429
|
else {
|
|
432
430
|
console.log(output);
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
import { AACTree, AACButton } from './treeStructure';
|
|
43
43
|
import { StringCasing } from './stringCasing';
|
|
44
44
|
import { ValidationResult } from '../validation/validationTypes';
|
|
45
|
-
import { BinaryOutput, ProcessorInput } from '../utils/io';
|
|
46
|
-
import
|
|
47
|
-
export interface
|
|
45
|
+
import { BinaryOutput, FileAdapter, ProcessorInput } from '../utils/io';
|
|
46
|
+
import { ZipAdapter } from '../utils/zip';
|
|
47
|
+
export interface ProcessorConfig {
|
|
48
48
|
excludeNavigationButtons?: boolean;
|
|
49
49
|
excludeSystemButtons?: boolean;
|
|
50
50
|
gridsetPassword?: string;
|
|
@@ -53,10 +53,10 @@ export interface ProcessorOptions {
|
|
|
53
53
|
grid3SymbolDir?: string;
|
|
54
54
|
grid3Path?: string;
|
|
55
55
|
grid3Locale?: string;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}>;
|
|
56
|
+
fileAdapter: FileAdapter;
|
|
57
|
+
zipAdapter: (input?: ProcessorInput, fileAdapter?: FileAdapter) => Promise<ZipAdapter>;
|
|
59
58
|
}
|
|
59
|
+
export type ProcessorOptions = Partial<ProcessorConfig>;
|
|
60
60
|
export interface ExtractedString {
|
|
61
61
|
string: string;
|
|
62
62
|
vocabPlacementMeta: VocabPlacementMetadata;
|
|
@@ -89,7 +89,7 @@ export interface SourceString {
|
|
|
89
89
|
vocabplacementmetadata: VocabPlacementMetadata;
|
|
90
90
|
}
|
|
91
91
|
declare abstract class BaseProcessor {
|
|
92
|
-
protected options:
|
|
92
|
+
protected options: ProcessorConfig;
|
|
93
93
|
constructor(options?: ProcessorOptions);
|
|
94
94
|
abstract extractTexts(filePathOrBuffer: ProcessorInput): Promise<string[]>;
|
|
95
95
|
abstract loadIntoTree(filePathOrBuffer: ProcessorInput): Promise<AACTree>;
|
|
@@ -44,6 +44,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
44
44
|
exports.BaseProcessor = void 0;
|
|
45
45
|
const treeStructure_1 = require("./treeStructure");
|
|
46
46
|
const stringCasing_1 = require("./stringCasing");
|
|
47
|
+
const io_1 = require("../utils/io");
|
|
48
|
+
const zip_1 = require("../utils/zip");
|
|
47
49
|
class BaseProcessor {
|
|
48
50
|
constructor(options = {}) {
|
|
49
51
|
// Default configuration: exclude navigation/system buttons
|
|
@@ -51,6 +53,8 @@ class BaseProcessor {
|
|
|
51
53
|
excludeNavigationButtons: true,
|
|
52
54
|
excludeSystemButtons: true,
|
|
53
55
|
preserveAllButtons: false,
|
|
56
|
+
fileAdapter: io_1.defaultFileAdapter,
|
|
57
|
+
zipAdapter: zip_1.getZipAdapter,
|
|
54
58
|
...options,
|
|
55
59
|
};
|
|
56
60
|
}
|
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.ApplePanelsProcessor = void 0;
|
|
7
7
|
const baseProcessor_1 = require("../core/baseProcessor");
|
|
8
8
|
const treeStructure_1 = require("../core/treeStructure");
|
|
9
|
-
// Removed unused import: FileProcessor
|
|
10
9
|
const plist_1 = __importDefault(require("plist"));
|
|
11
10
|
const validationTypes_1 = require("../validation/validationTypes");
|
|
12
11
|
const io_1 = require("../utils/io");
|
|
@@ -92,17 +91,15 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
92
91
|
return texts;
|
|
93
92
|
}
|
|
94
93
|
async loadIntoTree(filePathOrBuffer) {
|
|
95
|
-
|
|
94
|
+
const { readBinaryFromInput, readTextFromInput, pathExists, getFileSize, join } = this.options.fileAdapter;
|
|
96
95
|
const filename = typeof filePathOrBuffer === 'string' ? (0, io_1.getBasename)(filePathOrBuffer) : 'upload.plist';
|
|
97
96
|
let buffer;
|
|
98
97
|
try {
|
|
99
98
|
if (typeof filePathOrBuffer === 'string') {
|
|
100
|
-
const fs = (0, io_1.getFs)();
|
|
101
|
-
const path = (0, io_1.getPath)();
|
|
102
99
|
if (filePathOrBuffer.endsWith('.ascconfig')) {
|
|
103
|
-
const panelDefsPath =
|
|
104
|
-
if (
|
|
105
|
-
buffer =
|
|
100
|
+
const panelDefsPath = join(filePathOrBuffer, 'Contents', 'Resources', 'PanelDefinitions.plist');
|
|
101
|
+
if (await pathExists(panelDefsPath)) {
|
|
102
|
+
buffer = await readBinaryFromInput(panelDefsPath);
|
|
106
103
|
}
|
|
107
104
|
else {
|
|
108
105
|
const validation = (0, validationTypes_1.buildValidationResultFromMessage)({
|
|
@@ -117,13 +114,13 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
117
114
|
}
|
|
118
115
|
}
|
|
119
116
|
else {
|
|
120
|
-
buffer =
|
|
117
|
+
buffer = await readBinaryFromInput(filePathOrBuffer);
|
|
121
118
|
}
|
|
122
119
|
}
|
|
123
120
|
else {
|
|
124
|
-
buffer =
|
|
121
|
+
buffer = await readBinaryFromInput(filePathOrBuffer);
|
|
125
122
|
}
|
|
126
|
-
const content =
|
|
123
|
+
const content = await readTextFromInput(buffer);
|
|
127
124
|
const parsedData = plist_1.default.parse(content);
|
|
128
125
|
let panelsData = [];
|
|
129
126
|
if (Array.isArray(parsedData.panels)) {
|
|
@@ -252,11 +249,12 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
252
249
|
const validation = (0, validationTypes_1.buildValidationResultFromMessage)({
|
|
253
250
|
filename,
|
|
254
251
|
filesize: typeof filePathOrBuffer === 'string'
|
|
255
|
-
? (() => {
|
|
256
|
-
|
|
257
|
-
|
|
252
|
+
? await (async () => {
|
|
253
|
+
return (await pathExists(filePathOrBuffer))
|
|
254
|
+
? await getFileSize(filePathOrBuffer)
|
|
255
|
+
: 0;
|
|
258
256
|
})()
|
|
259
|
-
: (
|
|
257
|
+
: (await readBinaryFromInput(filePathOrBuffer)).byteLength,
|
|
260
258
|
format: 'applepanels',
|
|
261
259
|
message: err?.message || 'Failed to parse Apple Panels file',
|
|
262
260
|
type: 'parse',
|
|
@@ -266,6 +264,7 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
266
264
|
}
|
|
267
265
|
}
|
|
268
266
|
async processTexts(filePathOrBuffer, translations, outputPath) {
|
|
267
|
+
const { readBinaryFromInput, join } = this.options.fileAdapter;
|
|
269
268
|
// Load the tree, apply translations, and save to new file
|
|
270
269
|
const tree = await this.loadIntoTree(filePathOrBuffer);
|
|
271
270
|
// Apply translations to all text content
|
|
@@ -315,15 +314,14 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
315
314
|
// Save the translated tree to the requested location and return its content
|
|
316
315
|
await this.saveFromTree(tree, outputPath);
|
|
317
316
|
if (outputPath.endsWith('.plist')) {
|
|
318
|
-
return
|
|
317
|
+
return await readBinaryFromInput(outputPath);
|
|
319
318
|
}
|
|
320
|
-
const path = (0, io_1.getPath)();
|
|
321
319
|
const configPath = outputPath.endsWith('.ascconfig') ? outputPath : `${outputPath}.ascconfig`;
|
|
322
|
-
const panelDefsPath =
|
|
323
|
-
return
|
|
320
|
+
const panelDefsPath = join(configPath, 'Contents', 'Resources', 'PanelDefinitions.plist');
|
|
321
|
+
return await readBinaryFromInput(panelDefsPath);
|
|
324
322
|
}
|
|
325
323
|
async saveFromTree(tree, outputPath) {
|
|
326
|
-
|
|
324
|
+
const { writeTextToPath, pathExists, mkDir, join, dirname } = this.options.fileAdapter;
|
|
327
325
|
// Support two output modes:
|
|
328
326
|
// 1) Single-file .plist (PanelDefinitions.plist content written directly)
|
|
329
327
|
// 2) Apple Panels bundle folder (*.ascconfig) with Contents/Resources structure
|
|
@@ -333,17 +331,15 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
333
331
|
let contentsPath = '';
|
|
334
332
|
let resourcesPath = '';
|
|
335
333
|
if (!isSinglePlist) {
|
|
336
|
-
const fs = (0, io_1.getFs)();
|
|
337
|
-
const path = (0, io_1.getPath)();
|
|
338
334
|
configPath = outputPath.endsWith('.ascconfig') ? outputPath : `${outputPath}.ascconfig`;
|
|
339
|
-
contentsPath =
|
|
340
|
-
resourcesPath =
|
|
341
|
-
if (!
|
|
342
|
-
|
|
343
|
-
if (!
|
|
344
|
-
|
|
345
|
-
if (!
|
|
346
|
-
|
|
335
|
+
contentsPath = join(configPath, 'Contents');
|
|
336
|
+
resourcesPath = join(contentsPath, 'Resources');
|
|
337
|
+
if (!(await pathExists(configPath)))
|
|
338
|
+
await mkDir(configPath, { recursive: true });
|
|
339
|
+
if (!(await pathExists(contentsPath)))
|
|
340
|
+
await mkDir(contentsPath, { recursive: true });
|
|
341
|
+
if (!(await pathExists(resourcesPath)))
|
|
342
|
+
await mkDir(resourcesPath, { recursive: true });
|
|
347
343
|
// Create Info.plist (bundle mode only)
|
|
348
344
|
const infoPlist = {
|
|
349
345
|
ASCConfigurationDisplayName: tree.metadata?.name || 'AAC Processors Export',
|
|
@@ -359,10 +355,10 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
359
355
|
`Generated by AAC Processors${tree.metadata?.author ? ` - Author: ${tree.metadata.author}` : ''}`,
|
|
360
356
|
};
|
|
361
357
|
const infoPlistContent = plist_1.default.build(infoPlist);
|
|
362
|
-
|
|
358
|
+
await writeTextToPath(join(contentsPath, 'Info.plist'), infoPlistContent);
|
|
363
359
|
// Create AssetIndex.plist (empty)
|
|
364
360
|
const assetIndexContent = plist_1.default.build({});
|
|
365
|
-
|
|
361
|
+
await writeTextToPath(join(resourcesPath, 'AssetIndex.plist'), assetIndexContent);
|
|
366
362
|
}
|
|
367
363
|
// Build PanelDefinitions content from tree
|
|
368
364
|
const panelsDict = {};
|
|
@@ -488,17 +484,14 @@ class ApplePanelsProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
488
484
|
const panelDefsContent = plist_1.default.build(panelDefinitions);
|
|
489
485
|
if (isSinglePlist) {
|
|
490
486
|
// Write single PanelDefinitions.plist file directly
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
496
|
-
(0, io_1.writeTextToPath)(outputPath, panelDefsContent);
|
|
487
|
+
const dir = dirname(outputPath);
|
|
488
|
+
if (!(await pathExists(dir)))
|
|
489
|
+
await mkDir(dir, { recursive: true });
|
|
490
|
+
await writeTextToPath(outputPath, panelDefsContent);
|
|
497
491
|
}
|
|
498
492
|
else {
|
|
499
493
|
// Write into bundle structure
|
|
500
|
-
|
|
501
|
-
(0, io_1.writeTextToPath)(path.join(resourcesPath, 'PanelDefinitions.plist'), panelDefsContent);
|
|
494
|
+
await writeTextToPath(join(resourcesPath, 'PanelDefinitions.plist'), panelDefsContent);
|
|
502
495
|
}
|
|
503
496
|
}
|
|
504
497
|
createApplePanelsAction(button) {
|
|
@@ -35,22 +35,22 @@ declare class AstericsGridProcessor extends BaseProcessor {
|
|
|
35
35
|
/**
|
|
36
36
|
* Add audio recording to a specific grid element
|
|
37
37
|
*/
|
|
38
|
-
addAudioToElement(filePath: string, elementId: string, audioData: Buffer, metadata?: string): void
|
|
38
|
+
addAudioToElement(filePath: string, elementId: string, audioData: Buffer, metadata?: string): Promise<void>;
|
|
39
39
|
/**
|
|
40
40
|
* Create a copy of the grid file with audio recordings added
|
|
41
41
|
*/
|
|
42
42
|
createAudioEnhancedGridFile(sourceFilePath: string, targetFilePath: string, audioMappings: Map<string, {
|
|
43
43
|
audioData: Buffer;
|
|
44
44
|
metadata?: string;
|
|
45
|
-
}>): void
|
|
45
|
+
}>): Promise<void>;
|
|
46
46
|
/**
|
|
47
47
|
* Extract all element IDs from the grid file for audio mapping
|
|
48
48
|
*/
|
|
49
|
-
getElementIds(filePathOrBuffer: ProcessorInput): string[]
|
|
49
|
+
getElementIds(filePathOrBuffer: ProcessorInput): Promise<string[]>;
|
|
50
50
|
/**
|
|
51
51
|
* Check if an element has audio recording
|
|
52
52
|
*/
|
|
53
|
-
hasAudioRecording(filePathOrBuffer: ProcessorInput, elementId: string): boolean
|
|
53
|
+
hasAudioRecording(filePathOrBuffer: ProcessorInput, elementId: string): Promise<boolean>;
|
|
54
54
|
/**
|
|
55
55
|
* Extract strings with metadata for aac-tools-platform compatibility
|
|
56
56
|
* Uses the generic implementation from BaseProcessor
|