Skip to content

Commit

Permalink
V6 (#51)
Browse files Browse the repository at this point in the history
* first refactor

* convert `enum` to `const` for filesize

* update dependencies to latest

* restore additional helper support

* remove unused dependency

* add prettier config

* direct index assignment for `DocumentFragment`

* restore old playground file

* infrastructure cleanup

* update with new benchmarks

* quick attempt at using `JSON.stringify`

* only use `JSON.stringify` when necessary

* make element hash unique based on element type

* use `String.prototype.match()` instead of `RegExp.prototype.exec` for simplicity

* update dependencies

* simplify logic and avoid layer in stack when stringifying

* reduce code size by using `every` / `some`

* guarantee an argument passed for consistency

* code cleanup

* move constants to dedicated file, and remove layer for simple stringification

* remove no-longer-used `TO_STRING_CONSTANTS`

* update benchmarks

* have unique non-enumerable reference hashes, and eliminate unnecessary `JSON.stringify`

* use decrementing loop and pre-size arrays

* refactor build setup for better linting, typechecking, and use as a module

* fix `prettier` boinking on ESM

* update benchmarks to ESM

* simplify object hash for faster iteration

* enclose `Map` / `Set` in brackets for entries

* add support for primitive wrappers

* use string characters for hashable types, to avoid possible conflict with class values

* clean up benchmarks

* improve speed of `Event` hash

* use pipe instead of colon, for better rarity

* inline `sort` call for sets

* add `release-it` infrastructure

* clean up dependencies

* avoid sourcemaps for min file

* clean up fallback exposed types

* update CHANGELOG

* rerun benchmarks

* force latest version of `decompress-response`

* Release 6.0.0-beta.0

* refactor build setup to avoid separate `packageJson.js` file

* use string concatenation manually to avoid `.concat()` in TSC output

* simplify prefix creation

* consolidate namespaced construction into utility

* pass object class to `stringifyComplexType` to avoid local variable

* Release 6.0.0-beta.1

* bespoke handling of object types to reduce work

* update README

* add `WeakRef` support

* fix unused import

* add support for bigint typed arrays, as well as shared array buffers

* update README and CHANGELOG

* Release 6.0.0-beta.2

* update dependencies to latest

* update `.npmignore`

* small documentation fixes
  • Loading branch information
planttheidea authored Jan 9, 2023
1 parent ca4f310 commit 0513e68
Show file tree
Hide file tree
Showing 47 changed files with 5,247 additions and 5,398 deletions.
9 changes: 3 additions & 6 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@
"node": true,
"es6": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"extends": ["plugin:@typescript-eslint/recommended"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2021,
Expand All @@ -20,7 +16,8 @@

"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/explicit-module-boundary-types": 0,
"@typescript-eslint/no-explicit-any": 0
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-non-null-assertion": 0
},
"settings": {
"react": {
Expand Down
16 changes: 6 additions & 10 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
.idea
.nyc_output
.babelrc
.eslintrc
.gitignore
.npmignore
.prettierrc
.release-it*.json
__tests__
benchmarks
build
coverage
DEV_ONLY
node_modules
rollup.config.js
src
test
webpack
jest.config.js
*.csv
yarn*
__tests__
results_*.txt
jest.config.js
jest.init.js
webpack.config.js
tsconfig.json
yarn*
8 changes: 8 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"arrowParens": "always",
"bracketSpacing": true,
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all"
}
18 changes: 18 additions & 0 deletions .release-it.beta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"github": {
"release": true,
"tagName": "v${version}"
},
"npm": {
"tag": "next"
},
"preReleaseId": "beta",
"hooks": {
"before:init": [
"npm run lint",
"npm run typecheck",
"npm run test",
"npm run build"
]
}
}
14 changes: 14 additions & 0 deletions .release-it.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"github": {
"release": true,
"tagName": "v${version}"
},
"hooks": {
"before:init": [
"npm run lint",
"npm run typecheck",
"npm run test",
"npm run build"
]
}
}
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# hash-it CHANGELOG

## 6.0.0

**Breaking changes**

- Equality utilities (`is` / `is.any` / `is.all` / `is.not`) are no longer provided
- `Error` type hashes now include the message (previously only included stack)
- Non-enumerable type hashes (`Generator`, `Promise`, `WeakMap`, `WeakSet`) now hash uniquely based on reference
- `WeakMap` is now required at runtime (used as cache for circular references)

**Enhancements**

- Better support for system-specific loading (ESM vs CJS vs UMD)
- Added support for primitive wrappers (e.g. `new Number('123')`)
- Added support for more object classes
- `AsyncFunction`
- `AsyncGeneratorFunction`
- `BigInt64Array`
- `BigUint64Array`
- `GeneratorFunction`
- `SharedArrayBuffer`
- `WeakRef` (same limitations as those for `WeakMap` / `WeakSet`)

## 5.0.2

- Reduce code size by 29.29% (19.42% gzipped size)
Expand Down
151 changes: 82 additions & 69 deletions DEV_ONLY/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import 'regenerator-runtime/runtime';

import React from 'react';
import { render } from 'react-dom';
import { createRoot } from 'react-dom/client';
import hash from '../src';

document.body.style.backgroundColor = '#1d1d1d';
Expand All @@ -23,7 +21,7 @@ class StatefulComponent extends React.Component {

const StatelessComponent = () => <div>test</div>;

const a = {
const a: Record<string, any> = {
foo: 'bar',
};

Expand All @@ -33,13 +31,19 @@ const b = {

a.b = b;

function getArguments() {
return arguments;
}

const object = {
ReactStatefulClass: StatefulComponent,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
ReactStatefulElement: <StatefulComponent />,
ReactStatelessClass: StatelessComponent,
ReactStatelessElement: <StatelessComponent />,
// @ts-expect-error - arguments are not defined
arguments: getArguments('foo', 'bar'),
arr: ['foo', 'bar'],
arrayBuffer: new Uint16Array([1, 2, 3]).buffer,
bigint: BigInt(9007199254740991),
Expand All @@ -65,7 +69,7 @@ const object = {
func() {
alert('y');
},
*generator() {
*generator(): Generator<any, any, any> {
const value = yield 1;

yield value + 2;
Expand Down Expand Up @@ -97,28 +101,29 @@ const object = {
win: window,
};

const profile = (iterations = 100) => {
let index = -1;
// const profile = (iterations = 100) => {
// let index = -1;

console.profile('hash timing');
// console.profile('hash timing');

while (++index < iterations) {
hash(object);
hash(a);
// while (++index < iterations) {
// hash(object);
// hash(a);

for (const key in object) {
hash(object[key]);
}
// for (const key in object) {
// // @ts-expect-error - not worth it
// hash(object[key]);
// }

hash(document.body);
// this is the killer, so only profiled if you uncomment
// hash(window);
}
// hash(document.body);
// // this is the killer, so only profiled if you uncomment
// // hash(window);
// }

console.profileEnd('hash timing');
// console.profileEnd('hash timing');

console.log('Check the Profiles tab in DevTools to see the output.');
};
// console.log('Check the Profiles tab in DevTools to see the output.');
// };

// const benchmark = () => require('../benchmarks/index');

Expand Down Expand Up @@ -170,61 +175,69 @@ const visualValidation = () => {
console.log(object.win, hash(object.win));
};

const hashOnlyValidation = () => {
console.log(hash(object));
console.log(hash(a));
console.log(hash(object.string));
console.log(hash(object.num));
console.log(hash(object.bool));
console.log(hash(object.func));
console.log(hash(object.undef));
console.log(hash(object.nil));
console.log(hash(object.obj));
console.log(hash(object.arr));
console.log(hash(object.el));
console.log(hash(object.fragment));
console.log(hash(object.svg));
console.log(hash(object.math));
console.log(hash(object.regexp));
console.log(hash(object.event));
console.log(hash(object.nodeList));

// comment out for older browser testing
console.log(hash(object.symbol));
console.log(hash(object.err));
console.log(hash(object.map));
console.log(hash(object.set));
console.log(hash(object.weakMap));
console.log(hash(object.weakSet));
console.log(hash(object.arrayBuffer));
console.log(hash(object.dataView));
console.log(hash(object.float32Array));
console.log(hash(object.float64Array));
console.log(hash(object.generator));
console.log(hash(object.int8Array));
console.log(hash(object.int16Array));
console.log(hash(object.int32Array));
console.log(hash(object.promise));
console.log(hash(object.uint8Array));
console.log(hash(object.uint8ClampedArray));
console.log(hash(object.uint16Array));
console.log(hash(object.uint32Array));

console.log(hash(object.ReactStatefulClass));
console.log(hash(object.ReactStatefulElement));
console.log(hash(object.ReactStatelessClass));
console.log(hash(object.ReactStatelessElement));
console.log(hash(document.body));
console.log(hash(window));
};
// const hashOnlyValidation = () => {
// console.log(hash(object));
// console.log(hash(a));
// console.log(hash(object.string));
// console.log(hash(object.num));
// console.log(hash(object.bool));
// console.log(hash(object.func));
// console.log(hash(object.undef));
// console.log(hash(object.nil));
// console.log(hash(object.obj));
// console.log(hash(object.arr));
// console.log(hash(object.el));
// console.log(hash(object.fragment));
// console.log(hash(object.svg));
// console.log(hash(object.math));
// console.log(hash(object.regexp));
// console.log(hash(object.event));
// console.log(hash(object.nodeList));

// // comment out for older browser testing
// console.log(hash(object.symbol));
// console.log(hash(object.err));
// console.log(hash(object.map));
// console.log(hash(object.set));
// console.log(hash(object.weakMap));
// console.log(hash(object.weakSet));
// console.log(hash(object.arrayBuffer));
// console.log(hash(object.dataView));
// console.log(hash(object.float32Array));
// console.log(hash(object.float64Array));
// console.log(hash(object.generator));
// console.log(hash(object.int8Array));
// console.log(hash(object.int16Array));
// console.log(hash(object.int32Array));
// console.log(hash(object.promise));
// console.log(hash(object.uint8Array));
// console.log(hash(object.uint8ClampedArray));
// console.log(hash(object.uint16Array));
// console.log(hash(object.uint32Array));

// console.log(hash(object.ReactStatefulClass));
// console.log(hash(object.ReactStatefulElement));
// console.log(hash(object.ReactStatelessClass));
// console.log(hash(object.ReactStatelessElement));
// console.log(hash(document.body));
// console.log(hash(window));
// };

// benchmark();
// profile(1000);
visualValidation();
// hashOnlyValidation();

const promise = Promise.resolve(123);

console.log(hash(promise));
console.log(hash(promise));
console.log(hash(Promise.resolve(123)));

const div = document.createElement('div');

render(<div>Check the console for more details!</div>, div);
const root = createRoot(div);

document.body.appendChild(div);

root.render(<div>Check the console for more details!</div>);
Loading

0 comments on commit 0513e68

Please sign in to comment.