diff --git a/package-lock.json b/package-lock.json index 2853e08..f532bbf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,8 +36,7 @@ "ts-node": "^10.9.1", "tsup": "^7.2.0", "typedoc": "^0.25.1", - "typescript": "^5.2.2", - "underscore": "^1.13.6" + "typescript": "^5.2.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -9034,12 +9033,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "dev": true - }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", diff --git a/package.json b/package.json index 4995f60..759a730 100644 --- a/package.json +++ b/package.json @@ -84,8 +84,7 @@ "ts-node": "^10.9.1", "tsup": "^7.2.0", "typedoc": "^0.25.1", - "typescript": "^5.2.2", - "underscore": "^1.13.6" + "typescript": "^5.2.2" }, "keywords": [ "data", diff --git a/test/performance/data-structures/queue/deque.test.ts b/test/performance/data-structures/queue/deque.test.ts index 0939ff3..bf76aec 100644 --- a/test/performance/data-structures/queue/deque.test.ts +++ b/test/performance/data-structures/queue/deque.test.ts @@ -1,4 +1,4 @@ -import {Deque} from "../../../../src"; +import {Deque} from '../../../../src'; import * as Benchmark from 'benchmark'; export const suite = new Benchmark.Suite(); @@ -16,4 +16,4 @@ suite deque.push(i); deque.shift(); } - }) \ No newline at end of file + }); diff --git a/test/performance/data-structures/queue/queue.test.ts b/test/performance/data-structures/queue/queue.test.ts index 1546ad2..24d21c0 100644 --- a/test/performance/data-structures/queue/queue.test.ts +++ b/test/performance/data-structures/queue/queue.test.ts @@ -1,4 +1,4 @@ -import {Queue} from "../../../../src"; +import {Queue} from '../../../../src'; import * as Benchmark from 'benchmark'; @@ -17,4 +17,4 @@ suite queue.push(i); queue.shift(); } - }) \ No newline at end of file + }); diff --git a/test/performance/index.ts b/test/performance/index.ts index bf808d0..29f07b5 100644 --- a/test/performance/index.ts +++ b/test/performance/index.ts @@ -2,15 +2,17 @@ import * as Benchmark from 'benchmark'; import * as path from 'path'; import * as fs from 'fs'; import * as fastGlob from 'fast-glob'; -import {numberFix, render} from "./utils"; +import {numberFix, render} from './utils'; const reportDistPath = 'benchmark'; const testDir = path.join(__dirname, 'data-structures'); const testFiles = fastGlob.sync(path.join(testDir, '**', '*.test.ts')); -const report: { [key: string]: any } = {}; +const report: {[key: string]: any} = {}; -let testFileCount = 0, suiteCount = 0, completedCount = 0; +let testFileCount = 0, + suiteCount = 0, + completedCount = 0; testFiles.forEach((file: string) => { testFileCount++; console.log(`testing file ${file}`); @@ -24,28 +26,30 @@ testFiles.forEach((file: string) => { console.log(event.target.toString()); }); - suite.on('complete', function (this: Benchmark.Suite) { - completedCount++; - console.log('Fastest is ' + this.filter('fastest').map('name')); - report[testName] = this.map((test: Benchmark) => ({ - 'test name': test.name, - 'time consumption (ms)': numberFix((test.times.period * 1000), 2), - 'executions per second': numberFix(test.hz, 2), - 'executed times': numberFix(test.count, 2), - 'sample arithmetic mean (secs)': numberFix(test.stats.mean, 2), - 'sample deviation': numberFix(test.stats.deviation, 2), - })); + suite + .on('complete', function (this: Benchmark.Suite) { + completedCount++; + console.log('Fastest is ' + this.filter('fastest').map('name')); + report[testName] = this.map((test: Benchmark) => ({ + 'test name': test.name, + 'time consumption (ms)': numberFix(test.times.period * 1000, 2), + 'executions per second': numberFix(test.hz, 2), + 'executed times': numberFix(test.count, 2), + 'sample arithmetic mean (secs)': numberFix(test.stats.mean, 2), + 'sample deviation': numberFix(test.stats.deviation, 2) + })); + // report[testName] = this; + console.log( + `test file count: ${testFileCount}. suite count: ${suiteCount}. completed suite count: ${completedCount}` + ); + if (completedCount === suiteCount) { + if (!fs.existsSync(reportDistPath)) fs.mkdirSync(reportDistPath, {recursive: true}); - // report[testName] = this; - console.log(`test file count: ${testFileCount}. suite count: ${suiteCount}. completed suite count: ${completedCount}`) - if (completedCount === suiteCount) { - if (!fs.existsSync(reportDistPath)) fs.mkdirSync(reportDistPath, {recursive: true}); - - const filePath = path.join(reportDistPath, 'report.json'); - const htmlFilePath = path.join(reportDistPath, 'report.html'); - fs.writeFileSync(filePath, JSON.stringify(report, null, 2)); - let html = ` + const filePath = path.join(reportDistPath, 'report.json'); + const htmlFilePath = path.join(reportDistPath, 'report.html'); + fs.writeFileSync(filePath, JSON.stringify(report, null, 2)); + let html = ` @@ -76,32 +80,32 @@ testFiles.forEach((file: string) => { -
` - for (const r in report) { - if (report.hasOwnProperty(r)) { - html += render(report[r], { - '<>': 'table', - 'html': [ - { - '<>': 'tr', - 'html': [ - {'<>': 'td', 'html': '${name}'}, - {'<>': 'td', 'html': '${periodMS}'}, - {'<>': 'td', 'html': '${mean}'} - ] - } - ] - }); +
`; + for (const r in report) { + if (report.hasOwnProperty(r)) { + html += render(report[r], { + '<>': 'table', + html: [ + { + '<>': 'tr', + html: [ + {'<>': 'td', html: '${name}'}, + {'<>': 'td', html: '${periodMS}'}, + {'<>': 'td', html: '${mean}'} + ] + } + ] + }); + } } - } - html += `
+ html += `
`; - fs.writeFileSync(htmlFilePath, html); - console.log('Performance test report file generated') - } - }) + fs.writeFileSync(htmlFilePath, html); + console.log('Performance test report file generated'); + } + }) .run({async: true}); } -}); \ No newline at end of file +}); diff --git a/test/performance/utils/index.ts b/test/performance/utils/index.ts index a1884f0..feb65e4 100644 --- a/test/performance/utils/index.ts +++ b/test/performance/utils/index.ts @@ -1,2 +1,3 @@ export * from './json2html'; -export * from './number'; \ No newline at end of file +export * from './number'; +export * from './is'; diff --git a/test/performance/utils/is.ts b/test/performance/utils/is.ts new file mode 100644 index 0000000..2975299 --- /dev/null +++ b/test/performance/utils/is.ts @@ -0,0 +1,56 @@ +export const isNumber = (value: any) => { + return typeof value === 'number'; +}; +export const isString = (value: any) => { + return typeof value === 'string'; +}; +export const isBoolean = (value: any) => { + return typeof value === 'boolean'; +}; +export const isDate = (value: any) => { + return value instanceof Date; +}; +export const isNull = (value: any) => { + return value === null; +}; +export const isUndefined = (value: any) => { + return typeof value === 'undefined'; +}; +export const isFunction = (value: any) => { + return typeof value === 'function'; +}; +export const isObject = (value: any) => { + return typeof value === 'object'; +}; +export const isArray = (value: any) => { + return Array.isArray(value); +}; + +export const isEqual = (objA: any, objB: any): boolean => { + if (objA === objB) { + return true; + } + + if (typeof objA !== 'object' || typeof objB !== 'object' || objA === null || objB === null) { + return false; + } + + const keysA = Object.keys(objA); + const keysB = Object.keys(objB); + + if (keysA.length !== keysB.length) { + return false; + } + + for (const key of keysA) { + if (!keysB.includes(key)) { + return false; + } + + if (!isEqual(objA[key], objB[key])) { + return false; + } + } + + return true; +}; diff --git a/test/performance/utils/json2html.ts b/test/performance/utils/json2html.ts index e7d8bce..7648fe2 100644 --- a/test/performance/utils/json2html.ts +++ b/test/performance/utils/json2html.ts @@ -1,43 +1,38 @@ -import * as _ from "underscore"; +import * as _ from './is'; -function toggleJS(options?: { plainHtml?: boolean }): string { +function toggleJS(options?: {plainHtml?: boolean}): string { if (options?.plainHtml) { - return ""; + return ''; } else { - return "onclick=\"j2h.toggleVisibility(this);return false\""; + return 'onclick="json-to-html.toggleVisibility(this);return false"'; } } -function makeLabelDiv( - options: any, - level: number, - keyname: string | number, - datatype?: string -): string { - if (typeof keyname === "number") { - return `
${keyname} 
`; - } else if (typeof keyname === "string") { - if (datatype === "array") { +function makeLabelDiv(options: any, level: number, keyname: string | number, datatype?: string): string { + if (typeof keyname === 'number') { + return `
${keyname} 
`; + } else if (typeof keyname === 'string') { + if (datatype === 'array') { return `
${keyname}
`; - } else if (datatype === "object") { + )}>${keyname}`; + } else if (datatype === 'object') { return `
${keyname}:
`; + )}>${keyname}:`; } else { - return `
${keyname}:
`; + return `
${keyname}:
`; } } else { - return ""; + return ''; } } function getContentClass(keyname: string | number): string { - if (typeof keyname === "string") { - return "content"; + if (typeof keyname === 'string') { + return 'content'; } else { - return ""; + return ''; } } @@ -63,7 +58,7 @@ function isLeafValue(val: any): boolean { _.isDate(val) || _.isNull(val) || _.isUndefined(val) || - _.isNaN(val) || + isNaN(val) || _.isFunction(val) || !isPlainObject(val) ); @@ -89,12 +84,12 @@ function isTable(arr: any[]): boolean { if (arr.length === 0 || !_.isObject(arr[0])) { return false; } else { - let nonCompliant = _.detect(arr, (row) => !isLeafObject(row)); + let nonCompliant = arr.find(row => !isLeafObject(row)); if (nonCompliant) { return false; } else { - const cols = _.keys(arr[0]); - nonCompliant = _.detect(arr, (row: object) => !_.isEqual(cols, _.keys(row))); + const cols = Object.keys(arr[0]); + nonCompliant = arr.find((row: object) => !_.isEqual(cols, Object.keys(row))); if (nonCompliant) { return false; } else { @@ -106,65 +101,61 @@ function isTable(arr: any[]): boolean { function drawTable(arr: any[]): string { function drawRow(headers: string[], rowObj: any): string { - return ( - "" + - headers.map((header) => rowObj[header]).join("") + - "" - ); + return '' + headers.map(header => rowObj[header]).join('') + ''; } - const cols = _.keys(arr[0]); - const content = arr.map((rowObj) => drawRow(cols, rowObj)); - const headingHtml = "" + cols.join("") + ""; - const contentHtml = "" + content.join("") + ""; - return "" + headingHtml + contentHtml + "
"; + const cols = Object.keys(arr[0]); + const content = arr.map(rowObj => drawRow(cols, rowObj)); + const headingHtml = '' + cols.join('') + ''; + const contentHtml = '' + content.join('') + ''; + return '' + headingHtml + contentHtml + '
'; } -function _render( - name: string, - data: any, - options: any, - level: number, - altrow: number -): string { +function _render(name: string, data: any, options: any, level: number, altrow: number): string { const contentClass = getContentClass(name); if (_.isArray(data)) { - const title = makeLabelDiv(options, level, `${name} (${data.length})`, "array"); + const title = makeLabelDiv(options, level, `${name} (${data.length})`, 'array'); let subs: string; if (isTable(data)) { subs = drawTable(data); } else { - subs = "
" + data - .map((val: any, idx: number) => _render(idx.toString(), val, options, level + 1, idx % 2)) - .join("
") + "
"; + subs = + "
" + + data + .map((val: any, idx: number) => _render(idx.toString(), val, options, level + 1, idx % 2)) + .join("
") + + '
'; } - return `
+ return `
${title}
${subs}
`; } else if (isLeafValue(data)) { const title = makeLabelDiv(options, level, name); if (_.isFunction(data)) { - return `${title}  -function() can't _render-`; + return `${title}  -function() can't _render-`; } else if (!isPlainObject(data)) { if (_.isFunction(data.toString)) { - return `${title}  ${data.toString()}`; + return `${title}  ${data.toString()}`; } else { - return `${title}  -instance object, can't render-`; + return `${title}  -instance object, can't render-`; } } else { - return `${title}  ${data}`; + return `${title}  ${data}`; } } else { - const title = makeLabelDiv(options, level, name, "object"); + const title = makeLabelDiv(options, level, name, 'object'); let count = 0; - const subs = "
" + Object.entries(data) - .map(([key, val]) => _render(key, val, options, level + 1, count++ % 2)) - .join("
") + "
"; - const inner = `
+ const subs = + '
' + + Object.entries(data) + .map(([key, val]) => _render(key, val, options, level + 1, count++ % 2)) + .join('
') + + '
'; + const inner = `
${title}
${subs}
`; - return `${level === 0 ? '
' : ''} + return `${level === 0 ? "
" : ''} ${inner} ${level === 0 ? '
' : ''}`; } @@ -175,155 +166,155 @@ export function render(json: any, options: any): string { return `${_render('', json, options, 0, 0)}`; } -const head = ` -`; +// const head = ` +// `; diff --git a/test/performance/utils/number.ts b/test/performance/utils/number.ts index f1c3dd4..de6eef4 100644 --- a/test/performance/utils/number.ts +++ b/test/performance/utils/number.ts @@ -1,5 +1,4 @@ export function numberFix(number: number, decimalPlaces: number): string { - if (number > 10000 || number < 0.001) { const [mantissa, exponent] = number.toExponential().split('e'); const formattedMantissa = Number(mantissa).toFixed(decimalPlaces); @@ -7,4 +6,4 @@ export function numberFix(number: number, decimalPlaces: number): string { } else { return number.toFixed(decimalPlaces); } -} \ No newline at end of file +}