@willwade/aac-processors 0.1.0 → 0.1.2
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/processors/gridset/password.js +12 -6
- package/dist/browser/processors/gridset/symbols.js +62 -19
- package/dist/browser/processors/gridsetProcessor.js +10 -3
- package/dist/browser/processors/obfProcessor.js +6 -4
- package/dist/browser/validation/gridsetValidator.js +3 -2
- package/dist/processors/gridset/password.js +12 -9
- package/dist/processors/gridset/symbols.js +63 -46
- package/dist/processors/gridsetProcessor.js +10 -3
- package/dist/processors/obfProcessor.js +6 -4
- package/dist/validation/gridsetValidator.js +3 -2
- package/docs/PAGESET_GETTING_STARTED.md +185 -0
- package/examples/vitedemo/QUICKSTART.md +1 -0
- package/examples/vitedemo/index.html +160 -5
- package/examples/vitedemo/src/main.ts +367 -15
- package/examples/vitedemo/vite.config.ts +5 -1
- package/package.json +5 -3
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
function getExtension(source) {
|
|
2
|
+
const index = source.lastIndexOf('.');
|
|
3
|
+
if (index === -1)
|
|
4
|
+
return '';
|
|
5
|
+
return source.slice(index);
|
|
6
|
+
}
|
|
2
7
|
/**
|
|
3
8
|
* Resolve the password to use for Grid3 archives.
|
|
4
9
|
* Preference order:
|
|
@@ -8,17 +13,18 @@ import path from 'path';
|
|
|
8
13
|
export function resolveGridsetPassword(options, source) {
|
|
9
14
|
if (options?.gridsetPassword)
|
|
10
15
|
return options.gridsetPassword;
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
const envPassword = typeof process !== 'undefined' ? process.env?.GRIDSET_PASSWORD : undefined;
|
|
17
|
+
if (envPassword)
|
|
18
|
+
return envPassword;
|
|
13
19
|
if (typeof source === 'string') {
|
|
14
|
-
const ext =
|
|
20
|
+
const ext = getExtension(source).toLowerCase();
|
|
15
21
|
if (ext === '.gridsetx')
|
|
16
|
-
return
|
|
22
|
+
return envPassword;
|
|
17
23
|
}
|
|
18
24
|
return undefined;
|
|
19
25
|
}
|
|
20
26
|
export function resolveGridsetPasswordFromEnv() {
|
|
21
|
-
return process.env
|
|
27
|
+
return typeof process !== 'undefined' ? process.env?.GRIDSET_PASSWORD : undefined;
|
|
22
28
|
}
|
|
23
29
|
export function getZipEntriesWithPassword(zip, password) {
|
|
24
30
|
const entries = [];
|
|
@@ -12,9 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* This module provides symbol resolution and metadata extraction.
|
|
14
14
|
*/
|
|
15
|
-
import
|
|
16
|
-
import * as path from 'path';
|
|
17
|
-
import AdmZip from 'adm-zip';
|
|
15
|
+
import { getFs, getPath } from '../../utils/io';
|
|
18
16
|
/**
|
|
19
17
|
* Default Grid 3 installation paths by platform
|
|
20
18
|
*/
|
|
@@ -57,6 +55,37 @@ export const SYMBOL_LIBRARIES = {
|
|
|
57
55
|
* Default locale to use
|
|
58
56
|
*/
|
|
59
57
|
export const DEFAULT_LOCALE = 'en-GB';
|
|
58
|
+
function getNodeFs() {
|
|
59
|
+
try {
|
|
60
|
+
return getFs();
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
throw new Error('Symbol library access is not available in this environment.');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function getNodePath() {
|
|
67
|
+
try {
|
|
68
|
+
return getPath();
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
throw new Error('Path utilities are not available in this environment.');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
let cachedAdmZip = null;
|
|
75
|
+
function getAdmZip() {
|
|
76
|
+
if (cachedAdmZip)
|
|
77
|
+
return cachedAdmZip;
|
|
78
|
+
try {
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
80
|
+
const module = require('adm-zip');
|
|
81
|
+
const resolved = module.default || module;
|
|
82
|
+
cachedAdmZip = resolved;
|
|
83
|
+
return resolved;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
throw new Error('Symbol library access requires AdmZip in this environment.');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
60
89
|
/**
|
|
61
90
|
* Parse a symbol reference string
|
|
62
91
|
* @param reference - Symbol reference like "[widgit]/food/apple.png"
|
|
@@ -95,24 +124,30 @@ export function isSymbolReference(reference) {
|
|
|
95
124
|
* @returns Default Grid 3 path or empty string if not found
|
|
96
125
|
*/
|
|
97
126
|
export function getDefaultGrid3Path() {
|
|
98
|
-
const platform = process.platform;
|
|
127
|
+
const platform = (typeof process !== 'undefined' && process.platform ? process.platform : 'unknown');
|
|
99
128
|
const defaultPath = DEFAULT_GRID3_PATHS[platform] || '';
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
129
|
+
try {
|
|
130
|
+
const fs = getNodeFs();
|
|
131
|
+
if (defaultPath && fs.existsSync(defaultPath)) {
|
|
132
|
+
return defaultPath;
|
|
133
|
+
}
|
|
134
|
+
// Try to find Grid 3 in common locations
|
|
135
|
+
const commonPaths = [
|
|
136
|
+
'C:\\Program Files (x86)\\Smartbox\\Grid 3',
|
|
137
|
+
'C:\\Program Files\\Smartbox\\Grid 3',
|
|
138
|
+
'C:\\Program Files\\Smartbox\\Grid 3',
|
|
139
|
+
'/Applications/Grid 3.app',
|
|
140
|
+
'/opt/smartbox/grid3',
|
|
141
|
+
];
|
|
142
|
+
for (const testPath of commonPaths) {
|
|
143
|
+
if (fs.existsSync(testPath)) {
|
|
144
|
+
return testPath;
|
|
145
|
+
}
|
|
114
146
|
}
|
|
115
147
|
}
|
|
148
|
+
catch {
|
|
149
|
+
return '';
|
|
150
|
+
}
|
|
116
151
|
return '';
|
|
117
152
|
}
|
|
118
153
|
/**
|
|
@@ -122,6 +157,7 @@ export function getDefaultGrid3Path() {
|
|
|
122
157
|
* @returns Path to Symbol Libraries directory (e.g., "C:\...\Grid 3\Resources\Symbols")
|
|
123
158
|
*/
|
|
124
159
|
export function getSymbolLibrariesDir(grid3Path) {
|
|
160
|
+
const path = getNodePath();
|
|
125
161
|
return path.join(grid3Path, SYMBOLS_SUBDIR);
|
|
126
162
|
}
|
|
127
163
|
/**
|
|
@@ -132,6 +168,7 @@ export function getSymbolLibrariesDir(grid3Path) {
|
|
|
132
168
|
* @returns Path to symbol search indexes directory (e.g., "C:\...\Grid 3\Locale\en-GB\symbolsearch")
|
|
133
169
|
*/
|
|
134
170
|
export function getSymbolSearchIndexesDir(grid3Path, locale = DEFAULT_LOCALE) {
|
|
171
|
+
const path = getNodePath();
|
|
135
172
|
return path.join(grid3Path, SYMBOLSEARCH_SUBDIR, locale, 'symbolsearch');
|
|
136
173
|
}
|
|
137
174
|
/**
|
|
@@ -145,6 +182,7 @@ export function getAvailableSymbolLibraries(options = {}) {
|
|
|
145
182
|
return [];
|
|
146
183
|
}
|
|
147
184
|
const symbolsDir = getSymbolLibrariesDir(grid3Path);
|
|
185
|
+
const fs = getNodeFs();
|
|
148
186
|
if (!fs.existsSync(symbolsDir)) {
|
|
149
187
|
return [];
|
|
150
188
|
}
|
|
@@ -152,6 +190,7 @@ export function getAvailableSymbolLibraries(options = {}) {
|
|
|
152
190
|
const files = fs.readdirSync(symbolsDir);
|
|
153
191
|
for (const file of files) {
|
|
154
192
|
if (file.endsWith('.symbols')) {
|
|
193
|
+
const path = getNodePath();
|
|
155
194
|
const fullPath = path.join(symbolsDir, file);
|
|
156
195
|
const stats = fs.statSync(fullPath);
|
|
157
196
|
const libraryName = path.basename(file, '.symbols');
|
|
@@ -186,7 +225,9 @@ export function getSymbolLibraryInfo(libraryName, options = {}) {
|
|
|
186
225
|
libraryName + '.symbols',
|
|
187
226
|
];
|
|
188
227
|
for (const file of variations) {
|
|
228
|
+
const path = getNodePath();
|
|
189
229
|
const fullPath = path.join(symbolsDir, file);
|
|
230
|
+
const fs = getNodeFs();
|
|
190
231
|
if (fs.existsSync(fullPath)) {
|
|
191
232
|
const stats = fs.statSync(fullPath);
|
|
192
233
|
return {
|
|
@@ -233,6 +274,7 @@ export function resolveSymbolReference(reference, options = {}) {
|
|
|
233
274
|
}
|
|
234
275
|
try {
|
|
235
276
|
// .symbols files are ZIP archives
|
|
277
|
+
const AdmZip = getAdmZip();
|
|
236
278
|
const zip = new AdmZip(libraryInfo.pixFile);
|
|
237
279
|
// The path in the symbol reference becomes the path within the symbols/ folder
|
|
238
280
|
// e.g., [tawasl]/above bw.png becomes symbols/above bw.png
|
|
@@ -398,7 +440,8 @@ export function analyzeSymbolUsage(tree) {
|
|
|
398
440
|
*/
|
|
399
441
|
export function symbolReferenceToFilename(reference, cellX, cellY) {
|
|
400
442
|
const parsed = parseSymbolReference(reference);
|
|
401
|
-
const
|
|
443
|
+
const dotIndex = parsed.path.lastIndexOf('.');
|
|
444
|
+
const ext = dotIndex >= 0 ? parsed.path.slice(dotIndex) : '.png';
|
|
402
445
|
// Grid 3 format: {x}-{y}-0-text-0.{ext}
|
|
403
446
|
return `${cellX}-${cellY}-0-text-0${ext}`;
|
|
404
447
|
}
|
|
@@ -507,7 +507,14 @@ class GridsetProcessor extends BaseProcessor {
|
|
|
507
507
|
}
|
|
508
508
|
// Debug: log all entry names
|
|
509
509
|
console.log('[Gridset] Total zip entries:', entries.length);
|
|
510
|
-
const
|
|
510
|
+
const normalizeEntryName = (entryName) => entryName.replace(/\\/g, '/').toLowerCase();
|
|
511
|
+
const isGridXmlEntry = (entryName) => {
|
|
512
|
+
const normalized = normalizeEntryName(entryName);
|
|
513
|
+
if (!normalized.endsWith('grid.xml'))
|
|
514
|
+
return false;
|
|
515
|
+
return normalized.startsWith('grids/') || normalized.includes('/grids/');
|
|
516
|
+
};
|
|
517
|
+
const gridEntries = entries.filter((e) => isGridXmlEntry(e.entryName));
|
|
511
518
|
console.log('[Gridset] Grid XML entries found:', gridEntries.length);
|
|
512
519
|
if (gridEntries.length > 0) {
|
|
513
520
|
console.log('[Gridset] First few grid entries:', gridEntries.slice(0, 3).map((e) => e.entryName));
|
|
@@ -516,7 +523,7 @@ class GridsetProcessor extends BaseProcessor {
|
|
|
516
523
|
const gridNameToIdMap = new Map();
|
|
517
524
|
const gridIdToNameMap = new Map();
|
|
518
525
|
for (const entry of entries) {
|
|
519
|
-
if (
|
|
526
|
+
if (isGridXmlEntry(entry.entryName)) {
|
|
520
527
|
try {
|
|
521
528
|
const xmlContent = decodeText(await readEntryBuffer(entry));
|
|
522
529
|
const data = parser.parse(xmlContent);
|
|
@@ -549,7 +556,7 @@ class GridsetProcessor extends BaseProcessor {
|
|
|
549
556
|
// Second pass: process each grid file in the gridset
|
|
550
557
|
for (const entry of entries) {
|
|
551
558
|
// Only process files named grid.xml under Grids/ (any subdir)
|
|
552
|
-
if (
|
|
559
|
+
if (isGridXmlEntry(entry.entryName)) {
|
|
553
560
|
let xmlContent;
|
|
554
561
|
try {
|
|
555
562
|
const buffer = await readEntryBuffer(entry);
|
|
@@ -341,7 +341,7 @@ class ObfProcessor extends BaseProcessor {
|
|
|
341
341
|
return null;
|
|
342
342
|
}
|
|
343
343
|
// If input is a string path and ends with .obf, treat as JSON
|
|
344
|
-
if (typeof filePathOrBuffer === 'string' && filePathOrBuffer.endsWith('.obf')) {
|
|
344
|
+
if (typeof filePathOrBuffer === 'string' && filePathOrBuffer.toLowerCase().endsWith('.obf')) {
|
|
345
345
|
try {
|
|
346
346
|
const content = readTextFromInput(filePathOrBuffer);
|
|
347
347
|
const boardData = tryParseObfJson(content);
|
|
@@ -393,8 +393,10 @@ class ObfProcessor extends BaseProcessor {
|
|
|
393
393
|
}
|
|
394
394
|
// Otherwise, try as ZIP (.obz). Detect likely zip signature first; throw if neither JSON nor ZIP
|
|
395
395
|
function isLikelyZip(input) {
|
|
396
|
-
if (typeof input === 'string')
|
|
397
|
-
|
|
396
|
+
if (typeof input === 'string') {
|
|
397
|
+
const lowered = input.toLowerCase();
|
|
398
|
+
return lowered.endsWith('.zip') || lowered.endsWith('.obz');
|
|
399
|
+
}
|
|
398
400
|
const bytes = readBinaryFromInput(input);
|
|
399
401
|
return bytes.length >= 2 && bytes[0] === 0x50 && bytes[1] === 0x4b;
|
|
400
402
|
}
|
|
@@ -420,7 +422,7 @@ class ObfProcessor extends BaseProcessor {
|
|
|
420
422
|
zip.forEach((relativePath, file) => {
|
|
421
423
|
if (file.dir)
|
|
422
424
|
return;
|
|
423
|
-
if (relativePath.endsWith('.obf')) {
|
|
425
|
+
if (relativePath.toLowerCase().endsWith('.obf')) {
|
|
424
426
|
obfEntries.push({ name: relativePath, file });
|
|
425
427
|
}
|
|
426
428
|
});
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/require-await */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
4
|
-
import * as fs from 'fs';
|
|
5
|
-
import * as path from 'path';
|
|
6
4
|
import * as xml2js from 'xml2js';
|
|
7
5
|
import JSZip from 'jszip';
|
|
8
6
|
import { BaseValidator } from './baseValidator';
|
|
7
|
+
import { getFs, getPath } from '../utils/io';
|
|
9
8
|
/**
|
|
10
9
|
* Validator for Grid3/Smartbox Gridset files (.gridset, .gridsetx)
|
|
11
10
|
*/
|
|
@@ -18,6 +17,8 @@ export class GridsetValidator extends BaseValidator {
|
|
|
18
17
|
*/
|
|
19
18
|
static async validateFile(filePath) {
|
|
20
19
|
const validator = new GridsetValidator();
|
|
20
|
+
const fs = getFs();
|
|
21
|
+
const path = getPath();
|
|
21
22
|
const content = fs.readFileSync(filePath);
|
|
22
23
|
const stats = fs.statSync(filePath);
|
|
23
24
|
return validator.validate(content, path.basename(filePath), stats.size);
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.resolveGridsetPassword = resolveGridsetPassword;
|
|
7
4
|
exports.resolveGridsetPasswordFromEnv = resolveGridsetPasswordFromEnv;
|
|
8
5
|
exports.getZipEntriesWithPassword = getZipEntriesWithPassword;
|
|
9
|
-
|
|
6
|
+
function getExtension(source) {
|
|
7
|
+
const index = source.lastIndexOf('.');
|
|
8
|
+
if (index === -1)
|
|
9
|
+
return '';
|
|
10
|
+
return source.slice(index);
|
|
11
|
+
}
|
|
10
12
|
/**
|
|
11
13
|
* Resolve the password to use for Grid3 archives.
|
|
12
14
|
* Preference order:
|
|
@@ -16,17 +18,18 @@ const path_1 = __importDefault(require("path"));
|
|
|
16
18
|
function resolveGridsetPassword(options, source) {
|
|
17
19
|
if (options?.gridsetPassword)
|
|
18
20
|
return options.gridsetPassword;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
const envPassword = typeof process !== 'undefined' ? process.env?.GRIDSET_PASSWORD : undefined;
|
|
22
|
+
if (envPassword)
|
|
23
|
+
return envPassword;
|
|
21
24
|
if (typeof source === 'string') {
|
|
22
|
-
const ext =
|
|
25
|
+
const ext = getExtension(source).toLowerCase();
|
|
23
26
|
if (ext === '.gridsetx')
|
|
24
|
-
return
|
|
27
|
+
return envPassword;
|
|
25
28
|
}
|
|
26
29
|
return undefined;
|
|
27
30
|
}
|
|
28
31
|
function resolveGridsetPasswordFromEnv() {
|
|
29
|
-
return process.env
|
|
32
|
+
return typeof process !== 'undefined' ? process.env?.GRIDSET_PASSWORD : undefined;
|
|
30
33
|
}
|
|
31
34
|
function getZipEntriesWithPassword(zip, password) {
|
|
32
35
|
const entries = [];
|
|
@@ -13,32 +13,6 @@
|
|
|
13
13
|
*
|
|
14
14
|
* This module provides symbol resolution and metadata extraction.
|
|
15
15
|
*/
|
|
16
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
|
-
if (k2 === undefined) k2 = k;
|
|
18
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
19
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
20
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
21
|
-
}
|
|
22
|
-
Object.defineProperty(o, k2, desc);
|
|
23
|
-
}) : (function(o, m, k, k2) {
|
|
24
|
-
if (k2 === undefined) k2 = k;
|
|
25
|
-
o[k2] = m[k];
|
|
26
|
-
}));
|
|
27
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
28
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
29
|
-
}) : function(o, v) {
|
|
30
|
-
o["default"] = v;
|
|
31
|
-
});
|
|
32
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
33
|
-
if (mod && mod.__esModule) return mod;
|
|
34
|
-
var result = {};
|
|
35
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
36
|
-
__setModuleDefault(result, mod);
|
|
37
|
-
return result;
|
|
38
|
-
};
|
|
39
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
40
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
41
|
-
};
|
|
42
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
17
|
exports.DEFAULT_LOCALE = exports.SYMBOL_LIBRARIES = void 0;
|
|
44
18
|
exports.parseSymbolReference = parseSymbolReference;
|
|
@@ -59,9 +33,7 @@ exports.analyzeSymbolUsage = analyzeSymbolUsage;
|
|
|
59
33
|
exports.symbolReferenceToFilename = symbolReferenceToFilename;
|
|
60
34
|
exports.getSymbolsDir = getSymbolsDir;
|
|
61
35
|
exports.getSymbolSearchDir = getSymbolSearchDir;
|
|
62
|
-
const
|
|
63
|
-
const path = __importStar(require("path"));
|
|
64
|
-
const adm_zip_1 = __importDefault(require("adm-zip"));
|
|
36
|
+
const io_1 = require("../../utils/io");
|
|
65
37
|
/**
|
|
66
38
|
* Default Grid 3 installation paths by platform
|
|
67
39
|
*/
|
|
@@ -104,6 +76,37 @@ exports.SYMBOL_LIBRARIES = {
|
|
|
104
76
|
* Default locale to use
|
|
105
77
|
*/
|
|
106
78
|
exports.DEFAULT_LOCALE = 'en-GB';
|
|
79
|
+
function getNodeFs() {
|
|
80
|
+
try {
|
|
81
|
+
return (0, io_1.getFs)();
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
throw new Error('Symbol library access is not available in this environment.');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function getNodePath() {
|
|
88
|
+
try {
|
|
89
|
+
return (0, io_1.getPath)();
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
throw new Error('Path utilities are not available in this environment.');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
let cachedAdmZip = null;
|
|
96
|
+
function getAdmZip() {
|
|
97
|
+
if (cachedAdmZip)
|
|
98
|
+
return cachedAdmZip;
|
|
99
|
+
try {
|
|
100
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
101
|
+
const module = require('adm-zip');
|
|
102
|
+
const resolved = module.default || module;
|
|
103
|
+
cachedAdmZip = resolved;
|
|
104
|
+
return resolved;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
throw new Error('Symbol library access requires AdmZip in this environment.');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
107
110
|
/**
|
|
108
111
|
* Parse a symbol reference string
|
|
109
112
|
* @param reference - Symbol reference like "[widgit]/food/apple.png"
|
|
@@ -142,23 +145,29 @@ function isSymbolReference(reference) {
|
|
|
142
145
|
* @returns Default Grid 3 path or empty string if not found
|
|
143
146
|
*/
|
|
144
147
|
function getDefaultGrid3Path() {
|
|
145
|
-
const platform = process.platform;
|
|
148
|
+
const platform = (typeof process !== 'undefined' && process.platform ? process.platform : 'unknown');
|
|
146
149
|
const defaultPath = DEFAULT_GRID3_PATHS[platform] || '';
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const commonPaths = [
|
|
152
|
-
'C:\\Program Files (x86)\\Smartbox\\Grid 3',
|
|
153
|
-
'C:\\Program Files\\Smartbox\\Grid 3',
|
|
154
|
-
'C:\\Program Files\\Smartbox\\Grid 3',
|
|
155
|
-
'/Applications/Grid 3.app',
|
|
156
|
-
'/opt/smartbox/grid3',
|
|
157
|
-
];
|
|
158
|
-
for (const testPath of commonPaths) {
|
|
159
|
-
if (fs.existsSync(testPath)) {
|
|
160
|
-
return testPath;
|
|
150
|
+
try {
|
|
151
|
+
const fs = getNodeFs();
|
|
152
|
+
if (defaultPath && fs.existsSync(defaultPath)) {
|
|
153
|
+
return defaultPath;
|
|
161
154
|
}
|
|
155
|
+
// Try to find Grid 3 in common locations
|
|
156
|
+
const commonPaths = [
|
|
157
|
+
'C:\\Program Files (x86)\\Smartbox\\Grid 3',
|
|
158
|
+
'C:\\Program Files\\Smartbox\\Grid 3',
|
|
159
|
+
'C:\\Program Files\\Smartbox\\Grid 3',
|
|
160
|
+
'/Applications/Grid 3.app',
|
|
161
|
+
'/opt/smartbox/grid3',
|
|
162
|
+
];
|
|
163
|
+
for (const testPath of commonPaths) {
|
|
164
|
+
if (fs.existsSync(testPath)) {
|
|
165
|
+
return testPath;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return '';
|
|
162
171
|
}
|
|
163
172
|
return '';
|
|
164
173
|
}
|
|
@@ -169,6 +178,7 @@ function getDefaultGrid3Path() {
|
|
|
169
178
|
* @returns Path to Symbol Libraries directory (e.g., "C:\...\Grid 3\Resources\Symbols")
|
|
170
179
|
*/
|
|
171
180
|
function getSymbolLibrariesDir(grid3Path) {
|
|
181
|
+
const path = getNodePath();
|
|
172
182
|
return path.join(grid3Path, SYMBOLS_SUBDIR);
|
|
173
183
|
}
|
|
174
184
|
/**
|
|
@@ -179,6 +189,7 @@ function getSymbolLibrariesDir(grid3Path) {
|
|
|
179
189
|
* @returns Path to symbol search indexes directory (e.g., "C:\...\Grid 3\Locale\en-GB\symbolsearch")
|
|
180
190
|
*/
|
|
181
191
|
function getSymbolSearchIndexesDir(grid3Path, locale = exports.DEFAULT_LOCALE) {
|
|
192
|
+
const path = getNodePath();
|
|
182
193
|
return path.join(grid3Path, SYMBOLSEARCH_SUBDIR, locale, 'symbolsearch');
|
|
183
194
|
}
|
|
184
195
|
/**
|
|
@@ -192,6 +203,7 @@ function getAvailableSymbolLibraries(options = {}) {
|
|
|
192
203
|
return [];
|
|
193
204
|
}
|
|
194
205
|
const symbolsDir = getSymbolLibrariesDir(grid3Path);
|
|
206
|
+
const fs = getNodeFs();
|
|
195
207
|
if (!fs.existsSync(symbolsDir)) {
|
|
196
208
|
return [];
|
|
197
209
|
}
|
|
@@ -199,6 +211,7 @@ function getAvailableSymbolLibraries(options = {}) {
|
|
|
199
211
|
const files = fs.readdirSync(symbolsDir);
|
|
200
212
|
for (const file of files) {
|
|
201
213
|
if (file.endsWith('.symbols')) {
|
|
214
|
+
const path = getNodePath();
|
|
202
215
|
const fullPath = path.join(symbolsDir, file);
|
|
203
216
|
const stats = fs.statSync(fullPath);
|
|
204
217
|
const libraryName = path.basename(file, '.symbols');
|
|
@@ -233,7 +246,9 @@ function getSymbolLibraryInfo(libraryName, options = {}) {
|
|
|
233
246
|
libraryName + '.symbols',
|
|
234
247
|
];
|
|
235
248
|
for (const file of variations) {
|
|
249
|
+
const path = getNodePath();
|
|
236
250
|
const fullPath = path.join(symbolsDir, file);
|
|
251
|
+
const fs = getNodeFs();
|
|
237
252
|
if (fs.existsSync(fullPath)) {
|
|
238
253
|
const stats = fs.statSync(fullPath);
|
|
239
254
|
return {
|
|
@@ -280,7 +295,8 @@ function resolveSymbolReference(reference, options = {}) {
|
|
|
280
295
|
}
|
|
281
296
|
try {
|
|
282
297
|
// .symbols files are ZIP archives
|
|
283
|
-
const
|
|
298
|
+
const AdmZip = getAdmZip();
|
|
299
|
+
const zip = new AdmZip(libraryInfo.pixFile);
|
|
284
300
|
// The path in the symbol reference becomes the path within the symbols/ folder
|
|
285
301
|
// e.g., [tawasl]/above bw.png becomes symbols/above bw.png
|
|
286
302
|
const symbolPath = `symbols/${parsed.path}`;
|
|
@@ -445,7 +461,8 @@ function analyzeSymbolUsage(tree) {
|
|
|
445
461
|
*/
|
|
446
462
|
function symbolReferenceToFilename(reference, cellX, cellY) {
|
|
447
463
|
const parsed = parseSymbolReference(reference);
|
|
448
|
-
const
|
|
464
|
+
const dotIndex = parsed.path.lastIndexOf('.');
|
|
465
|
+
const ext = dotIndex >= 0 ? parsed.path.slice(dotIndex) : '.png';
|
|
449
466
|
// Grid 3 format: {x}-{y}-0-text-0.{ext}
|
|
450
467
|
return `${cellX}-${cellY}-0-text-0${ext}`;
|
|
451
468
|
}
|
|
@@ -533,7 +533,14 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
533
533
|
}
|
|
534
534
|
// Debug: log all entry names
|
|
535
535
|
console.log('[Gridset] Total zip entries:', entries.length);
|
|
536
|
-
const
|
|
536
|
+
const normalizeEntryName = (entryName) => entryName.replace(/\\/g, '/').toLowerCase();
|
|
537
|
+
const isGridXmlEntry = (entryName) => {
|
|
538
|
+
const normalized = normalizeEntryName(entryName);
|
|
539
|
+
if (!normalized.endsWith('grid.xml'))
|
|
540
|
+
return false;
|
|
541
|
+
return normalized.startsWith('grids/') || normalized.includes('/grids/');
|
|
542
|
+
};
|
|
543
|
+
const gridEntries = entries.filter((e) => isGridXmlEntry(e.entryName));
|
|
537
544
|
console.log('[Gridset] Grid XML entries found:', gridEntries.length);
|
|
538
545
|
if (gridEntries.length > 0) {
|
|
539
546
|
console.log('[Gridset] First few grid entries:', gridEntries.slice(0, 3).map((e) => e.entryName));
|
|
@@ -542,7 +549,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
542
549
|
const gridNameToIdMap = new Map();
|
|
543
550
|
const gridIdToNameMap = new Map();
|
|
544
551
|
for (const entry of entries) {
|
|
545
|
-
if (
|
|
552
|
+
if (isGridXmlEntry(entry.entryName)) {
|
|
546
553
|
try {
|
|
547
554
|
const xmlContent = (0, io_1.decodeText)(await readEntryBuffer(entry));
|
|
548
555
|
const data = parser.parse(xmlContent);
|
|
@@ -575,7 +582,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
575
582
|
// Second pass: process each grid file in the gridset
|
|
576
583
|
for (const entry of entries) {
|
|
577
584
|
// Only process files named grid.xml under Grids/ (any subdir)
|
|
578
|
-
if (
|
|
585
|
+
if (isGridXmlEntry(entry.entryName)) {
|
|
579
586
|
let xmlContent;
|
|
580
587
|
try {
|
|
581
588
|
const buffer = await readEntryBuffer(entry);
|
|
@@ -367,7 +367,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
367
367
|
return null;
|
|
368
368
|
}
|
|
369
369
|
// If input is a string path and ends with .obf, treat as JSON
|
|
370
|
-
if (typeof filePathOrBuffer === 'string' && filePathOrBuffer.endsWith('.obf')) {
|
|
370
|
+
if (typeof filePathOrBuffer === 'string' && filePathOrBuffer.toLowerCase().endsWith('.obf')) {
|
|
371
371
|
try {
|
|
372
372
|
const content = (0, io_1.readTextFromInput)(filePathOrBuffer);
|
|
373
373
|
const boardData = tryParseObfJson(content);
|
|
@@ -419,8 +419,10 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
419
419
|
}
|
|
420
420
|
// Otherwise, try as ZIP (.obz). Detect likely zip signature first; throw if neither JSON nor ZIP
|
|
421
421
|
function isLikelyZip(input) {
|
|
422
|
-
if (typeof input === 'string')
|
|
423
|
-
|
|
422
|
+
if (typeof input === 'string') {
|
|
423
|
+
const lowered = input.toLowerCase();
|
|
424
|
+
return lowered.endsWith('.zip') || lowered.endsWith('.obz');
|
|
425
|
+
}
|
|
424
426
|
const bytes = (0, io_1.readBinaryFromInput)(input);
|
|
425
427
|
return bytes.length >= 2 && bytes[0] === 0x50 && bytes[1] === 0x4b;
|
|
426
428
|
}
|
|
@@ -446,7 +448,7 @@ class ObfProcessor extends baseProcessor_1.BaseProcessor {
|
|
|
446
448
|
zip.forEach((relativePath, file) => {
|
|
447
449
|
if (file.dir)
|
|
448
450
|
return;
|
|
449
|
-
if (relativePath.endsWith('.obf')) {
|
|
451
|
+
if (relativePath.toLowerCase().endsWith('.obf')) {
|
|
450
452
|
obfEntries.push({ name: relativePath, file });
|
|
451
453
|
}
|
|
452
454
|
});
|
|
@@ -30,11 +30,10 @@ exports.GridsetValidator = void 0;
|
|
|
30
30
|
/* eslint-disable @typescript-eslint/require-await */
|
|
31
31
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
32
32
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
33
|
-
const fs = __importStar(require("fs"));
|
|
34
|
-
const path = __importStar(require("path"));
|
|
35
33
|
const xml2js = __importStar(require("xml2js"));
|
|
36
34
|
const jszip_1 = __importDefault(require("jszip"));
|
|
37
35
|
const baseValidator_1 = require("./baseValidator");
|
|
36
|
+
const io_1 = require("../utils/io");
|
|
38
37
|
/**
|
|
39
38
|
* Validator for Grid3/Smartbox Gridset files (.gridset, .gridsetx)
|
|
40
39
|
*/
|
|
@@ -47,6 +46,8 @@ class GridsetValidator extends baseValidator_1.BaseValidator {
|
|
|
47
46
|
*/
|
|
48
47
|
static async validateFile(filePath) {
|
|
49
48
|
const validator = new GridsetValidator();
|
|
49
|
+
const fs = (0, io_1.getFs)();
|
|
50
|
+
const path = (0, io_1.getPath)();
|
|
50
51
|
const content = fs.readFileSync(filePath);
|
|
51
52
|
const stats = fs.statSync(filePath);
|
|
52
53
|
return validator.validate(content, path.basename(filePath), stats.size);
|