diff --git a/.eslintrc.yaml b/.eslintrc.yaml new file mode 100644 index 0000000..c879c2a --- /dev/null +++ b/.eslintrc.yaml @@ -0,0 +1,7 @@ +env: + es6: true + node: true +extends: 'eslint:recommended' +parserOptions: + ecmaVersion: 2017 + sourceType: module diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..178135c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/dist/ diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..ddad482 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +printWidth: 100 +useTabs: true +semi: false +singleQuote: true +trailingComma: all diff --git a/package.json b/package.json new file mode 100644 index 0000000..6ef514b --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "memor", + "version": "0.1.0", + "description": "More memoization", + "main": "./dist/index.cjs.js", + "module": "./dist/index.es.js", + "files": ["dist"], + "engines": { + "node": ">=8" + }, + "repository": { + "type": "git", + "url": "https://github.com/Conduitry/memor.git" + }, + "author": "Conduitry", + "license": "MIT", + "bugs": { + "url": "https://github.com/Conduitry/memor/issues" + }, + "homepage": "https://cndtr.io/memor/" +} diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..0531c0f --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,7 @@ +export default { + input: './src/index.js', + output: [ + { file: './dist/index.cjs.js', format: 'cjs', sourcemap: true }, + { file: './dist/index.es.js', format: 'es', sourcemap: true }, + ], +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..ba75166 --- /dev/null +++ b/src/index.js @@ -0,0 +1 @@ +export { default as memoize } from './memoize.js' diff --git a/src/memoize.js b/src/memoize.js new file mode 100644 index 0000000..ceb6dbd --- /dev/null +++ b/src/memoize.js @@ -0,0 +1,48 @@ +let ARRAY = Symbol() +let POJO = Symbol() +let REGEXP = Symbol() +let DATE = Symbol() +let BUFFER = Symbol() + +let array +let lookup + +let recurse = obj => { + if (typeof obj === 'object' && obj !== null) { + let handler = lookup.get(Object.getPrototypeOf(obj)) + if (handler) { + handler(obj) + return + } + } + array.push(obj) +} + +lookup = new Map([ + [Array.prototype, obj => (array.push(ARRAY, obj.length), obj.forEach(recurse))], + [ + Object.prototype, + obj => ( + array.push(POJO, Object.keys(obj).length, ...Object.keys(obj)), + Object.values(obj).forEach(recurse) + ), + ], + [RegExp.prototype, obj => array.push(REGEXP, obj.source, obj.flags)], + [Date.prototype, obj => array.push(DATE, obj.getTime())], + [Buffer.prototype, obj => array.push(BUFFER, obj.toString('base64'))], +]) + +let data = {} + +export default func => (...args) => { + let here = data + array = [] + recurse([func, ...args]) + for (let key of array) { + let M = (typeof key === 'object' && key !== null) || typeof key === 'function' ? WeakMap : Map + if (!here[M.name]) here[M.name] = new M() + if (!here[M.name].has(key)) here[M.name].set(key, {}) + here = here[M.name].get(key) + } + return 'value' in here ? here.value : (here.value = func(...args)) +}