Skip to content

Commit 588d99c

Browse files
authored
Merge pull request #14 from willwade/fix-win-build-test
cross platform build and prettier fixes
2 parents 6a1bad5 + 1973aa2 commit 588d99c

11 files changed

Lines changed: 102 additions & 31 deletions

File tree

.eslintrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
{
3535
"singleQuote": true,
3636
"trailingComma": "es5",
37-
"printWidth": 100
37+
"printWidth": 100,
38+
"endOfLine": "auto"
3839
}
3940
]
4041
},

.prettierrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"endOfLine": "auto"
3+
}

package-lock.json

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
"build:all": "npm run build:node && npm run build:browser",
8989
"build:watch": "tsc -p tsconfig.node.json --watch",
9090
"clean": "rimraf dist coverage",
91-
"copy:assets": "cp -r src/utilities/analytics/reference/data dist/utilities/analytics/reference/",
91+
"copy:assets": "node scripts/copy-assets.js",
9292
"lint": "eslint \"src/**/*.{js,ts}\" \"test/**/*.{js,ts}\"",
9393
"lint:fix": "eslint \"src/**/*.{js,ts}\" \"test/**/*.{js,ts}\" --fix",
9494
"format": "prettier --write \"src/**/*.{js,ts}\" \"test/**/*.{js,ts}\" \"*.{js,ts,json,md}\"",

scripts/copy-assets.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
4+
const srcDir = path.join(__dirname, '..', 'src', 'utilities', 'analytics', 'reference', 'data');
5+
const destDir = path.join(__dirname, '..', 'dist', 'utilities', 'analytics', 'reference', 'data');
6+
7+
function copyRecursiveSync(src, dest) {
8+
if (!fs.existsSync(src)) {
9+
return;
10+
}
11+
fs.mkdirSync(dest, { recursive: true });
12+
const entries = fs.readdirSync(src, { withFileTypes: true });
13+
for (const entry of entries) {
14+
const from = path.join(src, entry.name);
15+
const to = path.join(dest, entry.name);
16+
if (entry.isDirectory()) {
17+
copyRecursiveSync(from, to);
18+
} else {
19+
fs.copyFileSync(from, to);
20+
}
21+
}
22+
}
23+
24+
copyRecursiveSync(srcDir, destDir);

src/processors/gridset/crypto.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,16 @@
1313
* @returns Decrypted and inflated buffer
1414
*/
1515
export function decryptGridsetEntry(buffer: Buffer, password?: string): Buffer {
16+
const nodeRequire =
17+
typeof require === 'function' ? require : (undefined as undefined | ((id: string) => any));
18+
if (!nodeRequire) {
19+
throw new Error('Crypto utilities are not available in this environment.');
20+
}
1621
// Dynamic require to avoid breaking in browser environments
17-
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-return
18-
const crypto = require('crypto');
19-
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-return
20-
const zlib = require('zlib');
22+
const cryptoModule = 'crypto';
23+
const zlibModule = 'zlib';
24+
const crypto = nodeRequire(cryptoModule);
25+
const zlib = nodeRequire(zlibModule);
2126

2227
const pwd = (password || 'Chocolate').padEnd(32, ' ');
2328
const key = Buffer.from(pwd.slice(0, 32), 'utf8');
@@ -43,10 +48,13 @@ export function decryptGridsetEntry(buffer: Buffer, password?: string): Buffer {
4348
*/
4449
export function isCryptoAvailable(): boolean {
4550
try {
46-
// eslint-disable-next-line @typescript-eslint/no-var-requires
47-
require('crypto');
48-
// eslint-disable-next-line @typescript-eslint/no-var-requires
49-
require('zlib');
51+
const nodeRequire =
52+
typeof require === 'function' ? require : (undefined as undefined | ((id: string) => any));
53+
if (!nodeRequire) return false;
54+
const cryptoModule = 'crypto';
55+
const zlibModule = 'zlib';
56+
nodeRequire(cryptoModule);
57+
nodeRequire(zlibModule);
5058
return true;
5159
} catch {
5260
return false;

src/processors/obfProcessor.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -227,12 +227,16 @@ class ObfProcessor extends BaseProcessor {
227227
const sourceButtons = boardData.buttons || [];
228228

229229
// Calculate page ID first (used to make button IDs unique)
230-
const pageId =
231-
_boardPath && _boardPath.endsWith('.obf') && !_boardPath.includes('/')
232-
? _boardPath // Zip entry - use filename to match navigation paths
233-
: boardData?.id
234-
? String(boardData.id)
235-
: _boardPath?.split('/').pop() || '';
230+
const isZipEntry =
231+
_boardPath &&
232+
_boardPath.endsWith('.obf') &&
233+
!_boardPath.includes('/') &&
234+
!_boardPath.includes('\\');
235+
const pageId = isZipEntry
236+
? _boardPath // Zip entry - use filename to match navigation paths
237+
: boardData?.id
238+
? String(boardData.id)
239+
: _boardPath?.split(/[/\\]/).pop() || '';
236240

237241
const buttons: AACButton[] = await Promise.all(
238242
sourceButtons.map(async (btn: ObfButton): Promise<AACButton> => {

src/processors/snapProcessor.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import Database from 'better-sqlite3';
1919
import path from 'path';
2020
import fs from 'fs';
2121
import crypto from 'crypto';
22+
import os from 'os';
2223
import { SnapValidator } from '../validation/snapValidator';
2324
import { ValidationResult } from '../validation/validationTypes';
2425
import { ProcessorInput } from '../utils/io';
@@ -104,13 +105,20 @@ class SnapProcessor extends BaseProcessor {
104105
async loadIntoTree(filePathOrBuffer: ProcessorInput): Promise<AACTree> {
105106
await Promise.resolve();
106107
const tree = new AACTree();
108+
let tempDir: string | null = null;
107109
const filePath =
108-
typeof filePathOrBuffer === 'string'
110+
typeof filePathOrBuffer !== 'string'
111+
? (() => {
112+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snap-'));
113+
return path.join(tempDir, 'input.spb');
114+
})()
115+
: filePathOrBuffer;
116+
117+
if (typeof filePathOrBuffer !== 'string') {
118+
const buffer = Buffer.isBuffer(filePathOrBuffer)
109119
? filePathOrBuffer
110-
: path.join(process.cwd(), 'temp.spb');
111-
112-
if (Buffer.isBuffer(filePathOrBuffer)) {
113-
fs.writeFileSync(filePath, filePathOrBuffer);
120+
: Buffer.from(filePathOrBuffer);
121+
fs.writeFileSync(filePath, buffer);
114122
}
115123

116124
let db: any = null;
@@ -722,11 +730,11 @@ class SnapProcessor extends BaseProcessor {
722730
}
723731

724732
// Clean up temporary file if created from buffer
725-
if (Buffer.isBuffer(filePathOrBuffer) && fs.existsSync(filePath)) {
733+
if (tempDir && fs.existsSync(tempDir)) {
726734
try {
727-
fs.unlinkSync(filePath);
735+
fs.rmSync(tempDir, { recursive: true, force: true });
728736
} catch (e) {
729-
console.warn('Failed to clean up temporary file:', e);
737+
console.warn('Failed to clean up temporary files:', e);
730738
}
731739
}
732740
}

src/utils/io.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,33 @@ export type BinaryOutput = Buffer | Uint8Array;
44

55
let cachedFs: typeof import('fs') | null = null;
66
let cachedPath: typeof import('path') | null = null;
7+
let cachedRequire: NodeRequire | null | undefined = undefined;
8+
9+
type NodeRequire = (id: string) => any;
10+
11+
function getNodeRequire(): NodeRequire {
12+
if (cachedRequire === undefined) {
13+
if (typeof require === 'function') {
14+
cachedRequire = require;
15+
} else if (typeof globalThis !== 'undefined') {
16+
const maybeRequire = (globalThis as { require?: unknown }).require;
17+
cachedRequire = typeof maybeRequire === 'function' ? (maybeRequire as NodeRequire) : null;
18+
} else {
19+
cachedRequire = null;
20+
}
21+
}
22+
if (!cachedRequire) {
23+
throw new Error('File system access is not available in this environment.');
24+
}
25+
return cachedRequire;
26+
}
727

828
export function getFs(): typeof import('fs') {
929
if (!cachedFs) {
1030
try {
11-
// eslint-disable-next-line @typescript-eslint/no-var-requires
12-
cachedFs = require('fs');
31+
const nodeRequire = getNodeRequire();
32+
const fsModule = 'fs';
33+
cachedFs = nodeRequire(fsModule);
1334
} catch {
1435
throw new Error('File system access is not available in this environment.');
1536
}
@@ -23,8 +44,9 @@ export function getFs(): typeof import('fs') {
2344
export function getPath(): typeof import('path') {
2445
if (!cachedPath) {
2546
try {
26-
// eslint-disable-next-line @typescript-eslint/no-var-requires
27-
cachedPath = require('path');
47+
const nodeRequire = getNodeRequire();
48+
const pathModule = 'path';
49+
cachedPath = nodeRequire(pathModule);
2850
} catch {
2951
throw new Error('Path utilities are not available in this environment.');
3052
}

test/obfProcessor.roundtrip.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import path from 'path';
44
import { ObfProcessor } from '../src/processors/obfProcessor';
55
import { AACTree, AACPage, AACButton } from '../src/core/treeStructure';
66

7-
jest.setTimeout(30000);
7+
jest.setTimeout(process.platform === 'win32' ? 60000 : 30000);
88

99
describe('OBFProcessor round-trip', () => {
1010
const obfPath: string = path.join(__dirname, 'assets/obf/example.obf');

0 commit comments

Comments
 (0)