diff --git a/.gitignore b/.gitignore
index d16c893..cd61559 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
dist
+.coverage
.solid
.output
.vercel
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..5fc0918
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,41 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "bun",
+ "request": "launch",
+ "name": "Debug Bun",
+ // The path to a JavaScript or TypeScript file to run.
+ "program": "${file}",
+ // The arguments to pass to the program, if any.
+ "args": [],
+ // The working directory of the program.
+ "cwd": "${workspaceFolder}",
+ // The environment variables to pass to the program.
+ "env": {},
+ // If the environment variables should not be inherited from the parent process.
+ "strictEnv": false,
+ // If the program should be run in watch mode.
+ // This is equivalent to passing `--watch` to the `bun` executable.
+ // You can also set this to "hot" to enable hot reloading using `--hot`.
+ "watchMode": false,
+ // If the debugger should stop on the first line of the program.
+ "stopOnEntry": false,
+ // If the debugger should be disabled. (for example, breakpoints will not be hit)
+ "noDebug": false,
+ // The path to the `bun` executable, defaults to your `PATH` environment variable.
+ "runtime": "bun",
+ // The arguments to pass to the `bun` executable, if any.
+ // Unlike `args`, these are passed to the executable itself, not the program.
+ "runtimeArgs": [],
+ },
+ {
+ "type": "bun",
+ "request": "attach",
+ "name": "Attach to Bun",
+ // The URL of the WebSocket inspector to attach to.
+ // This value can be retreived by using `bun --inspect`.
+ "url": "ws://localhost:6499/",
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..e57826f
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,10 @@
+{
+ // The path to the `bun` executable.
+ "bun.runtime": "/path/to/bun",
+ "bun.debugTerminal": {
+ // If support for Bun should be added to the default "JavaScript Debug Terminal".
+ "enabled": true,
+ // If the debugger should stop on the first line of the program.
+ "stopOnEntry": false,
+ }
+}
\ No newline at end of file
diff --git a/app.config.ts b/app.config.ts
index d2f21f0..9c8e86f 100644
--- a/app.config.ts
+++ b/app.config.ts
@@ -7,69 +7,64 @@ export default defineConfig({
cspNonce: 'KAAS_IS_AWESOME',
},
plugins: [
- VitePWA({
- strategies: 'injectManifest',
- mode: 'development',
+ // VitePWA({
+ // strategies: 'injectManifest',
+ // registerType: 'autoUpdate',
+ // injectRegister: false,
- registerType: 'autoUpdate',
- injectRegister: false,
+ // workbox: {
+ // globPatterns: ['**/*.{js,css,html,svg,png,svg,ico}'],
+ // cleanupOutdatedCaches: true,
+ // clientsClaim: true,
+ // },
+ // injectManifest: {
+ // globPatterns: ['**/*.{js,css,html,svg,png,svg,ico}'],
+ // },
- // pwaAssets: { disabled: false, config: true, htmlPreset: '2023', overrideManifestIcons: true },
- workbox: {
- globPatterns: ['**/*.{js,css,html,svg,png,svg,ico}'],
- cleanupOutdatedCaches: true,
- clientsClaim: true,
- },
- injectManifest: {
- globPatterns: ['**/*.{js,css,html,svg,png,svg,ico}'],
- },
+ // manifest: {
+ // name: 'Calque - manage your i18n files',
+ // short_name: 'KAAS',
+ // description: 'Simple tool for maitaining i18n files',
+ // icons: [
+ // {
+ // src: '/images/favicon.dark.svg',
+ // type: 'image/svg+xml',
+ // sizes: 'any'
+ // }
+ // ],
+ // display_override: ['window-controls-overlay'],
+ // screenshots: [
+ // {
+ // src: '/images/screenshots/narrow.png',
+ // type: 'image/png',
+ // sizes: '538x1133',
+ // form_factor: 'narrow'
+ // },
+ // {
+ // src: '/images/screenshots/wide.png',
+ // type: 'image/png',
+ // sizes: '2092x1295',
+ // form_factor: 'wide'
+ // }
+ // ],
+ // file_handlers: [
+ // {
+ // action: '/edit',
+ // accept: {
+ // 'text/*': [
+ // '.json'
+ // ]
+ // }
+ // }
+ // ]
+ // },
- base: '/',
- manifest: {
- name: 'Calque - manage your i18n files',
- short_name: 'KAAS',
- description: 'Simple tool for maitaining i18n files',
- icons: [
- {
- src: '/images/favicon.dark.svg',
- type: 'image/svg+xml',
- sizes: 'any'
- }
- ],
- display_override: ['window-controls-overlay'],
- screenshots: [
- {
- src: '/images/screenshots/narrow.png',
- type: 'image/png',
- sizes: '538x1133',
- form_factor: 'narrow'
- },
- {
- src: '/images/screenshots/wide.png',
- type: 'image/png',
- sizes: '2092x1295',
- form_factor: 'wide'
- }
- ],
- file_handlers: [
- {
- action: '/edit',
- accept: {
- 'text/*': [
- '.json'
- ]
- }
- }
- ]
- },
-
- devOptions: {
- enabled: true,
- type: 'module',
- navigateFallback: 'index.html',
- resolveTempFolder: () => './.output/public',
- },
- }),
+ // devOptions: {
+ // enabled: true,
+ // type: 'module',
+ // navigateFallback: 'index.html',
+ // },
+ // }),
],
},
solid: {
@@ -81,8 +76,5 @@ export default defineConfig({
prerender: {
crawlLinks: true,
},
- routeRules: {
- '/manifest.json': { static: true }
- },
},
});
diff --git a/bun.lockb b/bun.lockb
index 624c3fe..ff7924a 100644
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/bunfig.toml b/bunfig.toml
new file mode 100644
index 0000000..67811e5
--- /dev/null
+++ b/bunfig.toml
@@ -0,0 +1,5 @@
+[test]
+coverage = true
+coverageReporter = ['text', 'lcov']
+coverageDir = './.coverage'
+preload = "./test.config.ts"
diff --git a/package.json b/package.json
index a11bdce..d3ce423 100644
--- a/package.json
+++ b/package.json
@@ -18,18 +18,20 @@
"dev": "vinxi dev",
"build": "vinxi build",
"start": "vinxi start",
- "version": "vinxi version",
- "test": "vitest"
+ "version": "vinxi version"
},
"type": "module",
"devDependencies": {
+ "@happy-dom/global-registrator": "^15.11.0",
+ "@sinonjs/fake-timers": "^13.0.5",
"@solidjs/testing-library": "^0.8.10",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/user-event": "^14.5.2",
+ "@types/sinonjs__fake-timers": "^8.1.5",
"@types/wicg-file-system-access": "^2023.10.5",
+ "bun-types": "^1.1.34",
"jsdom": "^25.0.1",
"vite-plugin-pwa": "^0.20.5",
- "vitest": "^2.1.4",
"workbox-window": "^7.3.0"
}
}
\ No newline at end of file
diff --git a/src/components/colorschemepicker.spec.tsx b/src/components/colorschemepicker.spec.tsx
new file mode 100644
index 0000000..037adc9
--- /dev/null
+++ b/src/components/colorschemepicker.spec.tsx
@@ -0,0 +1,11 @@
+import { describe, it, expect } from 'bun:test';
+import { render } from "@solidjs/testing-library"
+import { ColorSchemePicker } from "./colorschemepicker";
+
+// describe('', () => {
+// it('should render', async () => {
+// render(() => );
+
+// expect(true).toBe(true);
+// });
+// });
\ No newline at end of file
diff --git a/src/utilities.spec.ts b/src/utilities.spec.ts
index 46e096c..6b87caf 100644
--- a/src/utilities.spec.ts
+++ b/src/utilities.spec.ts
@@ -1,22 +1,430 @@
-import { expect, describe, it, beforeEach, vi } from "vitest"
-import { debounce } from "./utilities"
+import { describe, beforeEach, it, expect, mock, afterAll, spyOn } from 'bun:test';
+import { debounce, deepCopy, deepDiff, filter, map, MutarionKind, splitAt } from './utilities';
+import { install } from '@sinonjs/fake-timers';
+
+type MilliSeconds = number;
+const useFakeTimers = () => {
+ const clock = install();
+
+ beforeEach(() => clock.reset());
+ afterAll(() => clock.uninstall());
+
+ return {
+ tick(timeToAdvance: MilliSeconds) {
+ clock.tick(timeToAdvance);
+ },
+ };
+};
+const first = (iterable: Iterable): T | undefined => {
+ for (const value of iterable) {
+ return value;
+ }
+}
+
+describe('splitAt', () => {
+ it('should split the given string at the given index', async () => {
+ // Arrange
+ const given = 'this.is.some.concatenated.string';
+ const expected = [
+ 'this.is.some.concatenated',
+ 'string',
+ ] as const;
+
+ // Act
+ const [a, b] = splitAt(given, given.lastIndexOf('.'));
+
+ // Assert
+ expect(a).toBe(expected[0]);
+ expect(b).toBe(expected[1]);
+ });
+
+ it('should return an empty second result when the index is negative', async () => {
+ // Arrange
+ const given = 'this.is.some.concatenated.string';
+ const expected = [
+ 'this.is.some.concatenated.string',
+ '',
+ ] as const;
+
+ // Act
+ const [a, b] = splitAt(given, -1);
+
+ // Assert
+ expect(a).toBe(expected[0]);
+ expect(b).toBe(expected[1]);
+ });
+
+ it('should return an empty second result when the index is larger then subject length', async () => {
+ // Arrange
+ const given = 'this.is.some.concatenated.string';
+ const expected = [
+ 'this.is.some.concatenated.string',
+ '',
+ ] as const;
+
+ // Act
+ const [a, b] = splitAt(given, given.length * 2);
+
+ // Assert
+ expect(a).toBe(expected[0]);
+ expect(b).toBe(expected[1]);
+ });
+});
describe('debounce', () => {
- beforeEach(() => {
- vi.useFakeTimers();
- })
+ const { tick } = useFakeTimers();
it('should run the given callback after the provided time', async () => {
// Arrange
- const callback = vi.fn(() => { });
+ const callback = mock(() => { });
const delay = 1000;
const debounced = debounce(callback, delay);
// Act
debounced();
- vi.runAllTimers();
+ tick(delay);
// Assert
- expect(callback).toHaveBeenCalled();
+ expect(callback).toHaveBeenCalledTimes(1);
});
-});
\ No newline at end of file
+
+ it('should reset if another call is made', async () => {
+ // Arrange
+ const callback = mock(() => { });
+ const delay = 1000;
+ const debounced = debounce(callback, delay);
+
+ // Act
+ debounced();
+ tick(delay / 2);
+ debounced();
+ tick(delay);
+
+ // Assert
+ expect(callback).toHaveBeenCalledTimes(1);
+ });
+});
+
+describe('deepCopy', () => {
+ it('can skip values passed by reference (non-objects, null, and undefined)', async () => {
+ // arrange
+ const given = 'some string';
+
+ // Act
+ const actual = deepCopy(given);
+
+ // Arrange
+ expect(actual).toBe(given);
+ });
+
+ it('should return a value that does not point to same memory', async () => {
+ // Arrange
+ const given = {};
+
+ // Act
+ const actual = deepCopy(given);
+
+ // Assert
+ expect(actual).not.toBe(given);
+ });
+
+ it('should handle Date types', async () => {
+ // Arrange
+ const given = new Date();
+
+ // Act
+ const actual = deepCopy(given);
+
+ // Assert
+ expect(actual).not.toBe(given);
+ });
+
+ it('should handle Arrays', async () => {
+ // Arrange
+ const given: any[] = [];
+
+ // Act
+ const actual = deepCopy(given);
+
+ // Assert
+ expect(actual).not.toBe(given);
+ });
+
+ it('should handle Sets', async () => {
+ // Arrange
+ const given = new Set();
+
+ // Act
+ const actual = deepCopy(given);
+
+ // Assert
+ expect(actual).not.toBe(given);
+ });
+
+ it('should handle Maps', async () => {
+ // Arrange
+ const given = new Map();
+
+ // Act
+ const actual = deepCopy(given);
+
+ // Assert
+ expect(actual).not.toBe(given);
+ });
+
+ it('should return a value that does not point to same memory for nested properties', async () => {
+ // Arrange
+ const given = {
+ some: {
+ deep: {
+ value: {}
+ }
+ }
+ };
+
+ // Act
+ const actual = deepCopy(given);
+
+ // Assert
+ expect(actual.some.deep.value).not.toBe(given.some.deep.value);
+ });
+});
+
+describe('deepDiff', () => {
+ it('should immedietly return when either `a` is not iterable', async () => {
+ // arrange
+ const a: any = 0;
+ const b = {};
+ const spy = spyOn(console, 'error').mockReturnValue(undefined);
+
+ // Act
+ const actual = deepDiff(a, b).toArray();
+
+ // Arrange
+ expect(actual).toEqual([]);
+ expect(spy).toHaveBeenCalled();
+ });
+
+ it('should immedietly return when either `b` is not iterable', async () => {
+ // arrange
+ const a = {};
+ const b: any = 0;
+ const spy = spyOn(console, 'error').mockReturnValue(undefined);
+
+ // Act
+ const actual = deepDiff(a, b).toArray();
+
+ // Arrange
+ expect(actual).toEqual([]);
+ expect(spy).toHaveBeenCalled();
+ });
+
+ it('should yield no results when both a and b are empty', async () => {
+ // arrange
+ const a = {};
+ const b = {};
+
+ // Act
+ const actual = deepDiff(a, b).toArray();
+
+ // Arrange
+ expect(actual).toEqual([]);
+ });
+
+ it('should yield no results when both a and b are equal', async () => {
+ // arrange
+ const a = { key: 'value' };
+ const b = { key: 'value' };
+
+ // Act
+ const actual = deepDiff(a, b).toArray();
+
+ // Arrange
+ expect(actual).toEqual([]);
+ });
+
+ it('should yield a mutation of type create when `b` contains a key that `a` does not', async () => {
+ // arrange
+ const a = {};
+ const b = { key: 'value' };
+
+ // Act
+ const actual = first(deepDiff(a, b));
+
+ // Arrange
+ expect(actual).toEqual({ kind: MutarionKind.Create, key: 'key', value: 'value' });
+ });
+
+ it('should yield a mutation of type delete when `a` contains a key that `b` does not', async () => {
+ // arrange
+ const a = { key: 'value' };
+ const b = {};
+
+ // Act
+ const actual = first(deepDiff(a, b));
+
+ // Arrange
+ expect(actual).toEqual({ kind: MutarionKind.Delete, key: 'key' });
+ });
+
+ it('should yield a mutation of type update when the value of a key in `a` is not equal to the value of the same key in `b`', async () => {
+ // arrange
+ const a = { key: 'old' };
+ const b = { key: 'new' };
+
+ // Act
+ const actual = first(deepDiff(a, b));
+
+ // Arrange
+ expect(actual).toEqual({ kind: MutarionKind.Update, key: 'key', original: 'old', value: 'new' });
+ });
+
+ it('should iterate over nested values', async () => {
+ // arrange
+ const a = { some: { nested: { key: 'old' } } };
+ const b = { some: { nested: { key: 'new' } } };
+
+ // Act
+ const actual = deepDiff(a, b).toArray();
+
+ // Arrange
+ expect(actual).toEqual([{ kind: MutarionKind.Update, key: 'some.nested.key', original: 'old', value: 'new' }]);
+ });
+
+ it('should handle deleted keys', async () => {
+ // arrange
+ const a = { key1: 'value1', key2: 'value2', key3: 'value3', key4: 'value4', key5: 'value5' };
+ const b = { key1: 'value1', key4: 'value4', key5: 'value5' };
+
+ // Act
+ const actual = deepDiff(a, b).toArray();
+
+ // Arrange
+ expect(actual).toEqual([
+ { kind: MutarionKind.Delete, key: 'key2' },
+ { kind: MutarionKind.Delete, key: 'key3' },
+ ]);
+ });
+
+ it('should handle created keys', async () => {
+ // arrange
+ const a = { key1: 'value1', key4: 'value4', key5: 'value5' };
+ const b = { key1: 'value1', key2: 'value2', key3: 'value3', key4: 'value4', key5: 'value5' };
+
+ // Act
+ const actual = deepDiff(a, b).toArray();
+
+ // Arrange
+ expect(actual).toEqual([
+ { kind: MutarionKind.Create, key: 'key2', value: 'value2' },
+ { kind: MutarionKind.Create, key: 'key3', value: 'value3' },
+ ]);
+ });
+
+ it('should handle renamed keys', async () => {
+ // arrange
+ const a = { key1: 'value1', key2_old: 'value2', key3: 'value3' };
+ const b = { key1: 'value1', key2_new: 'value2', key3: 'value3', };
+
+ // Act
+ const actual = deepDiff(a, b).toArray();
+
+ // Arrange
+ expect(actual).toEqual([
+ { kind: MutarionKind.Delete, key: 'key2_old' },
+ { kind: MutarionKind.Create, key: 'key2_new', value: 'value2' },
+ ]);
+ });
+
+ it('should handle `Array` values', async () => {
+ // arrange
+ const a = { key: [1] };
+ const b = { key: [2] };
+
+ // Act
+ const actual = deepDiff(a, b).toArray();
+
+ // Arrange
+ expect(actual).toEqual([
+ { kind: MutarionKind.Update, key: 'key.0', original: 1, value: 2 },
+ ]);
+ });
+
+ it('should handle `Set` values', async () => {
+ // arrange
+ const a = { key: new Set([1, 2, 3]) };
+ const b = { key: new Set([1, 5, 3]) };
+
+ // Act
+ const actual = deepDiff(a, b).toArray();
+
+ // Arrange
+ expect(actual).toEqual([
+ { kind: MutarionKind.Delete, key: 'key.2' },
+ { kind: MutarionKind.Create, key: 'key.5', value: 5 },
+ ]);
+ });
+
+ it('should handle `Map` values', async () => {
+ // arrange
+ const a = { key: new Map([['key', 'old']]) };
+ const b = { key: new Map([['key', 'new']]) };
+
+ // Act
+ const actual = deepDiff(a, b).toArray();
+
+ // Arrange
+ expect(actual).toEqual([
+ { kind: MutarionKind.Update, key: 'key.key', original: 'old', value: 'new' },
+ ]);
+ });
+});
+
+describe('filter', () => {
+ it('should yield a value when the predicate returns true', async () => {
+ // arrange
+ const generator = async function* () {
+ for (const i of new Array(10).fill('').map((_, i) => i)) {
+ yield i;
+ }
+ };
+ const predicate = (i: number) => i % 2 === 0;
+
+ // Act
+ const actual = await Array.fromAsync(filter(generator(), predicate as any));
+
+ // Arrange
+ expect(actual).toEqual([0, 2, 4, 6, 8]);
+ });
+});
+
+describe('map', () => {
+ const generator = async function* () {
+ for (const i of new Array(10).fill('').map((_, i) => i)) {
+ yield i;
+ }
+ };
+
+ it('should yield a value when the predicate returns true', async () => {
+ // arrange
+ const mapFn = (i: number) => `nr ${i}`;
+
+ // Act
+ const actual = await Array.fromAsync(map(generator(), mapFn));
+
+ // Arrange
+ expect(actual).toEqual([
+ 'nr 0',
+ 'nr 1',
+ 'nr 2',
+ 'nr 3',
+ 'nr 4',
+ 'nr 5',
+ 'nr 6',
+ 'nr 7',
+ 'nr 8',
+ 'nr 9',
+ ]);
+ });
+});
+
diff --git a/src/utilities.ts b/src/utilities.ts
index b5e000b..8408a4e 100644
--- a/src/utilities.ts
+++ b/src/utilities.ts
@@ -1,5 +1,13 @@
export const splitAt = (subject: string, index: number): readonly [string, string] => {
- return [subject.slice(0, index), subject.slice(index + 1)] as const;
+ if (index < 0) {
+ return [subject, ''];
+ }
+
+ if (index > subject.length) {
+ return [subject, ''];
+ }
+
+ return [subject.slice(0, index), subject.slice(index + 1)];
};
export const debounce = void>(callback: T, delay: number): ((...args: Parameters) => void) => {
@@ -53,23 +61,19 @@ export type Mutation = { key: string } & (Created | Updated | Deleted);
export function* deepDiff(a: T1, b: T2, path: string[] = []): Generator {
if (!isIterable(a) || !isIterable(b)) {
- console.log('Edge cases', a, b);
+ console.error('Edge cases', a, b);
return;
}
for (const [[keyA, valueA], [keyB, valueB]] of zip(entriesOf(a), entriesOf(b))) {
- if (!keyA && !keyB) {
- throw new Error('this code should not be reachable, there is a bug with an unhandled/unknown edge case');
- }
-
- if (!keyA && keyB) {
+ if (keyA === undefined && keyB) {
yield { key: path.concat(keyB.toString()).join('.'), kind: MutarionKind.Create, value: valueB };
continue;
}
- if (keyA && !keyB) {
+ if (keyA && keyB === undefined) {
yield { key: path.concat(keyA.toString()).join('.'), kind: MutarionKind.Delete };
continue;
@@ -112,40 +116,42 @@ const entriesOf = (subject: object): Iterable =
return Object.entries(subject);
};
-const zip = function* (a: Iterable, b: Iterable): Generator {
+
+type ZippedPair =
+ | readonly [readonly [string | number, any], readonly [string | number, any]]
+ | readonly [readonly [undefined, undefined], readonly [string | number, any]]
+ | readonly [readonly [string | number, any], readonly [undefined, undefined]]
+ ;
+const zip = function* (a: Iterable, b: Iterable): Generator {
const iterA = bufferredIterator(a);
const iterB = bufferredIterator(b);
- const EMPTY = [undefined, undefined] as [string | number | undefined, any];
+ const EMPTY = [undefined, undefined] as const;
while (!iterA.done || !iterB.done) {
// if we have a match on the keys of a and b we can simply consume and yield
if (iterA.current.key === iterB.current.key) {
+ // When we match keys it could have happened that
+ // there are as many keys added as there are deleted,
+ // therefor we can now flush both a and b because we are aligned
+ yield* iterA.flush().map(entry => [entry, EMPTY] as const);
+ yield* iterB.flush().map(entry => [EMPTY, entry] as const);
+
yield [iterA.consume(), iterB.consume()];
}
// key of a aligns with last key in buffer b
// conclusion: a has key(s) that b does not
else if (iterA.current.key === iterB.top.key) {
- const a = iterA.pop()!;
-
- for (const [key, value] of iterA.flush()) {
- yield [[key, value], EMPTY];
- }
-
- yield [a, iterB.consume()];
+ yield* iterA.flush().map(entry => [entry, EMPTY] as const);
+ yield [iterA.consume(), iterB.consume()];
}
// the reverse case, key of b is aligns with the last key in buffer a
// conclusion: a is missing key(s) the b does have
else if (iterB.current.key === iterA.top.key) {
- const b = iterB.pop()!;
-
- for (const [key, value] of iterB.flush()) {
- yield [EMPTY, [key, value]];
- }
-
- yield [iterA.consume(), b];
+ yield* iterB.flush().map(entry => [EMPTY, entry] as const);
+ yield [iterA.consume(), iterB.consume()];
}
else if (iterA.done && !iterB.done) {
@@ -168,7 +174,6 @@ const zip = function* (a: Iterable, b: Iterable
const bufferredIterator = (subject: Iterable) => {
const iterator = Iterator.from(subject);
const buffer: T[] = [];
- let cursor: number = 0;
let done = false;
const next = () => {
@@ -176,7 +181,7 @@ const bufferredIterator = (subject: I
done = res.done ?? false;
if (!done) {
- cursor = buffer.push(res.value) - 1;
+ buffer.push(res.value)
}
};
@@ -184,16 +189,10 @@ const bufferredIterator = (subject: I
return {
advance() {
- if (buffer.length > 0 && cursor < (buffer.length - 1)) {
- cursor++;
- }
- else {
- next();
- }
+ next();
},
consume() {
- cursor = 0;
const value = buffer.shift()!;
this.advance();
@@ -202,15 +201,9 @@ const bufferredIterator = (subject: I
},
flush(): T[] {
- cursor = 0;
+ const entries = buffer.splice(0, buffer.length - 1);
- return buffer.splice(0, buffer.length);
- },
-
- pop() {
- cursor--;
-
- return buffer.pop();
+ return entries;
},
get done() {
@@ -224,14 +217,10 @@ const bufferredIterator = (subject: I
},
get current() {
- const [key = undefined, value = undefined] = buffer.at(cursor) ?? [];
+ const [key = undefined, value = undefined] = buffer.at(-1) ?? [];
return { key, value };
},
-
- get entry() {
- return [this.current.key, this.current.value] as const;
- }
};
};
diff --git a/test.config.ts b/test.config.ts
new file mode 100644
index 0000000..9cae201
--- /dev/null
+++ b/test.config.ts
@@ -0,0 +1,3 @@
+import { GlobalRegistrator } from "@happy-dom/global-registrator";
+
+GlobalRegistrator.register();
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 65df43c..2464cc2 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -15,7 +15,8 @@
"@testing-library/jest-dom",
"@types/wicg-file-system-access",
"vinxi/types/client",
- "vite-plugin-pwa/solid"
+ "vite-plugin-pwa/solid",
+ "bun-types"
],
"isolatedModules": true,
"paths": {
diff --git a/vitest.config.ts b/vitest.config.ts
deleted file mode 100644
index a13a54d..0000000
--- a/vitest.config.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import solid from "vite-plugin-solid"
-import { defineConfig } from "vitest/config"
-
-export default defineConfig({
- plugins: [solid()],
- root: './src',
- resolve: {
- conditions: ["development", "browser"],
- },
-})
\ No newline at end of file