Skip to content

Commit

Permalink
chore: wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Sec-ant committed Dec 15, 2024
1 parent 049a97f commit ca2bdca
Show file tree
Hide file tree
Showing 9 changed files with 304 additions and 128 deletions.
31 changes: 24 additions & 7 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,37 @@
},
"overrides": [
{
"include": ["imageData.d.ts"],
"include": [
"core.ts",
"full/index.ts",
"reader/index.ts",
"writer/index.ts"
],
"linter": {
"rules": {
"complexity": {
"noBannedTypes": "off"
"suspicious": {
"noConfusingVoidType": "off"
}
}
}
},
{
"include": ["*.json"],
"json": {
"parser": {
"allowTrailingCommas": true
"include": ["tests/**/*.ts"],
"linter": {
"rules": {
"performance": {
"noDelete": "off"
}
}
}
},
{
"include": ["imageData.d.ts"],
"linter": {
"rules": {
"complexity": {
"noBannedTypes": "off"
}
}
}
},
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@
"vitest": "^2.1.8"
},
"dependencies": {
"@types/emscripten": "^1.39.13"
"@types/emscripten": "^1.39.13",
"type-fest": "^4.30.1"
},
"overrides": {
"typedoc": {
Expand Down
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/bindings/barcodeFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export type WriteInputBarcodeFormat = TakeFirst<
>;

/**
* Barcode formats that may be returned in {@link ReadResult.format} in read functions.
* Barcode formats that may be returned in {@link ReadResult.format | `ReadResult.format`} in read functions.
*/
export type ReadOutputBarcodeFormat = BarcodeFormat | "None";

Expand Down
163 changes: 87 additions & 76 deletions src/core.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Merge } from "type-fest";
import {
type ReadResult,
type ReaderOptions,
Expand Down Expand Up @@ -56,38 +57,31 @@ export interface ZXingWriterModule extends EmscriptenModule {
*/
export interface ZXingFullModule extends ZXingReaderModule, ZXingWriterModule {}

export type ZXingModule<T extends ZXingModuleType = ZXingModuleType> =
T extends "reader"
? ZXingReaderModule
: T extends "writer"
? ZXingWriterModule
: T extends "full"
? ZXingFullModule
: ZXingReaderModule | ZXingWriterModule | ZXingFullModule;

export type ZXingReaderModuleFactory =
EmscriptenModuleFactory<ZXingReaderModule>;

export type ZXingWriterModuleFactory =
EmscriptenModuleFactory<ZXingWriterModule>;

export type ZXingFullModuleFactory = EmscriptenModuleFactory<ZXingFullModule>;

interface TypeModuleMap {
reader: [ZXingReaderModule, ZXingReaderModuleFactory];
writer: [ZXingWriterModule, ZXingWriterModuleFactory];
full: [ZXingFullModule, ZXingFullModuleFactory];
}

export type ZXingModule<T extends ZXingModuleType = ZXingModuleType> =
TypeModuleMap[T][0];

export type ZXingModuleFactory<T extends ZXingModuleType = ZXingModuleType> =
T extends "reader"
? ZXingReaderModuleFactory
: T extends "writer"
? ZXingWriterModuleFactory
: T extends "full"
? ZXingFullModuleFactory
:
| ZXingReaderModuleFactory
| ZXingWriterModuleFactory
| ZXingFullModuleFactory;
TypeModuleMap[T][1];

export type ZXingModuleOverrides = Partial<EmscriptenModule>;

export const VERSION = NPM_PACKAGE_VERSION;
export const ZXING_WASM_VERSION = NPM_PACKAGE_VERSION;

const defaultModuleOverrides: ZXingModuleOverrides = import.meta.env.PROD
const DEFAULT_MODULE_OVERRIDES: ZXingModuleOverrides = import.meta.env.PROD
? {
locateFile: (path, prefix) => {
const match = path.match(/_(.+?)\.wasm$/);
Expand All @@ -107,72 +101,85 @@ const defaultModuleOverrides: ZXingModuleOverrides = import.meta.env.PROD
},
};

interface ZXingWeakMapValue<T extends ZXingModuleType = ZXingModuleType> {
moduleOverrides: ZXingModuleOverrides;
modulePromise?: Promise<ZXingModule<T>>;
type CachedValue<T extends ZXingModuleType = ZXingModuleType> =
| [ZXingModuleOverrides]
| [ZXingModuleOverrides, Promise<ZXingModule<T>>];

const __CACHE__ = new WeakMap<ZXingModuleFactory, CachedValue>();

export interface PrepareZXingModuleOptions {
overrides?: ZXingModuleOverrides;
equalityFn?: (
cachedOverrides: ZXingModuleOverrides,
overrides: ZXingModuleOverrides,
) => boolean;
fireImmediately?: boolean;
}

type ZXingWeakMap = WeakMap<ZXingModuleFactory, ZXingWeakMapValue>;
export function prepareZXingModuleWithFactory<T extends ZXingModuleType>(
zxingModuleFactory: ZXingModuleFactory<T>,
options?: Merge<PrepareZXingModuleOptions, { fireImmediately?: false }>,
): void;

let zxingWeakMap: ZXingWeakMap = new WeakMap();
export function prepareZXingModuleWithFactory<T extends ZXingModuleType>(
zxingModuleFactory: ZXingModuleFactory<T>,
options: Merge<PrepareZXingModuleOptions, { fireImmediately: true }>,
): Promise<ZXingModule<T>>;

export function getZXingModuleWithFactory<T extends ZXingModuleType>(
export function prepareZXingModuleWithFactory<T extends ZXingModuleType>(
zxingModuleFactory: ZXingModuleFactory<T>,
zxingModuleOverrides?: ZXingModuleOverrides,
): Promise<ZXingModule<T>> {
const zxingWeakMapValue = zxingWeakMap.get(zxingModuleFactory) as
| ZXingWeakMapValue<T>
| undefined;

if (
zxingWeakMapValue?.modulePromise &&
(zxingModuleOverrides === undefined ||
Object.is(zxingModuleOverrides, zxingWeakMapValue.moduleOverrides))
) {
return zxingWeakMapValue.modulePromise;
}
options?: PrepareZXingModuleOptions,
): void | Promise<ZXingModule<T>>;

const resolvedModuleOverrides =
zxingModuleOverrides ??
zxingWeakMapValue?.moduleOverrides ??
defaultModuleOverrides;
export function prepareZXingModuleWithFactory<T extends ZXingModuleType>(
zxingModuleFactory: ZXingModuleFactory<T>,
{
overrides,
equalityFn = Object.is,
fireImmediately = false,
}: PrepareZXingModuleOptions = {},
) {
// look up the cached overrides and module promise
const [cachedOverrides, cachedPromise] = (__CACHE__.get(zxingModuleFactory) as
| CachedValue<T>
| undefined) ?? [DEFAULT_MODULE_OVERRIDES];

const modulePromise = zxingModuleFactory({
...resolvedModuleOverrides,
}) as Promise<ZXingModule<T>>;
// resolve the input overrides
const resolvedOverrides = overrides ?? cachedOverrides;

zxingWeakMap.set(zxingModuleFactory, {
moduleOverrides: resolvedModuleOverrides,
modulePromise,
});
let cacheHit: boolean | undefined;

return modulePromise;
}
// if the module is to be instantiated immediately
if (fireImmediately) {
// if cache is hit and a cached promise is available,
// return the cached promise directly
if (
cachedPromise &&
(cacheHit = equalityFn(cachedOverrides, resolvedOverrides))
) {
return cachedPromise;
}
// otherwise, instantiate the module
const modulePromise = zxingModuleFactory({
...resolvedOverrides,
}) as Promise<ZXingModule<T>>;
// cache the overrides and the promise
__CACHE__.set(zxingModuleFactory, [resolvedOverrides, modulePromise]);
// and return the promise
return modulePromise;
}

export function purgeZXingModule() {
zxingWeakMap = new WeakMap();
// otherwise only update the cache if the overrides have changed
if (!(cacheHit ?? equalityFn(cachedOverrides, resolvedOverrides))) {
__CACHE__.set(zxingModuleFactory, [resolvedOverrides]);
}
}

// export function setZXingModuleOverridesWithFactory<T extends ZXingModuleType>(
// zxingModuleFactory: ZXingModuleFactory<T>,
// zxingModuleOverrides: ZXingModuleOverrides,
// ) {
// zxingWeakMap.set(zxingModuleFactory, {
// moduleOverrides: zxingModuleOverrides,
// });
// }

export function setZXingModuleOverridesWithFactory<T extends ZXingModuleType>(
export function purgeZXingModuleWithFactory<T extends ZXingModuleType>(
zxingModuleFactory: ZXingModuleFactory<T>,
zxingModuleOverrides: ZXingModuleOverrides,
options?: {
fireImmediately?: boolean;
equalityFn?: (
prevOverrides: ZXingModuleOverrides,
currOverrides: ZXingModuleOverrides,
) => boolean;
},
) {}
) {
__CACHE__.delete(zxingModuleFactory);
}

export async function readBarcodesWithFactory<T extends "reader" | "full">(
zxingModuleFactory: ZXingModuleFactory<T>,
Expand All @@ -183,7 +190,9 @@ export async function readBarcodesWithFactory<T extends "reader" | "full">(
...defaultReaderOptions,
...readerOptions,
};
const zxingModule = await getZXingModuleWithFactory(zxingModuleFactory);
const zxingModule = await prepareZXingModuleWithFactory(zxingModuleFactory, {
fireImmediately: true,
});
let zxingReadResultVector: ZXingVector<ZXingReadResult>;
let bufferPtr: number;
if ("size" in input) {
Expand Down Expand Up @@ -231,7 +240,9 @@ export async function writeBarcodeWithFactory<T extends "writer" | "full">(
const zxingWriterOptions = writerOptionsToZXingWriterOptions(
requiredWriterOptions,
);
const zxingModule = await getZXingModuleWithFactory(zxingModuleFactory);
const zxingModule = await prepareZXingModuleWithFactory(zxingModuleFactory, {
fireImmediately: true,
});
if (typeof input === "string") {
return zxingWriteResultToWriteResult(
zxingModule.writeBarcodeFromText(input, zxingWriterOptions),
Expand Down
Loading

0 comments on commit ca2bdca

Please sign in to comment.