Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: loupe@2 #14

Merged
merged 23 commits into from
Nov 15, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e11b077
feat: loupe@2
keithamus Apr 13, 2017
9c3c977
refactor(array): shorten filter condition for enumerable keys
lucasfcosta Jan 22, 2019
0865041
build: update travis.yml for latest node/npm
keithamus Jan 22, 2019
50deda1
build: update benchmark to use es6 import syntax
keithamus Jan 22, 2019
a219179
fix: WeakMap s/sepcial/special
keithamus Jan 22, 2019
223903b
refactor(error): use Set to filter error properties
keithamus Jan 22, 2019
81da557
build: rely on esm instead of pretest building
keithamus Jan 22, 2019
39cb9c0
chore: package-lock s/http/https
keithamus Jan 22, 2019
674c4a8
test: add tests for Objects from Object.create(null)
keithamus Jan 22, 2019
422eec6
style: ignore most complex functions
keithamus Jan 22, 2019
5982647
fix(array): broken filter function
keithamus Jan 22, 2019
1c85d29
style: eslint --fix
keithamus Jan 22, 2019
9b68b95
test: clean up benchmarking some more
keithamus Jan 23, 2019
0d94a2a
perf: drop all Object.assign calls
keithamus Jan 23, 2019
00322c4
perf(array): improve array performance around nonIndexProperties
keithamus Jan 23, 2019
fd4f089
feat: improve typedarray/buffer compatibility and performance
keithamus Jan 23, 2019
0d6b6fd
test: add all tests to index
keithamus Jan 23, 2019
6dd1f06
test(class): add basic class tests
keithamus Apr 30, 2019
9569a04
fix(errors): add case for non-string message property
keithamus Apr 30, 2019
01bbc62
feat(objects): add inspection of Symbol properties
keithamus Apr 30, 2019
f0a30ab
test(boolean): Add boolean object type tests
keithamus Apr 30, 2019
f1dbf19
feat(html): add HTML inspection
keithamus Apr 30, 2019
a851c2e
Merge branch 'master' into v2
keithamus Nov 12, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@
npm-debug.log
*.tmp.js
/tmp/
loupe.test.js
loupe.js
.nyc_output/
79 changes: 74 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,75 @@
sudo: false

dist: trusty

language: node_js
node_js:
- 0.8
- 0.10
script:
- make ci

cache:
directories:
- node_modules
- ~/.npm

node_js: 8

jobs:
include:
- stage: lint
script: npm run lint
- stage: test
addons:
chrome: stable
firefox: latest
before_script:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
- sleep 3 # give xvfb some time to start
script: npm run test:browser
env:
- QUICKLY_TEST_BROWSERS_AVAILABLE_IN_CI=1 # kept here for easier reading of build log
- stage: test
addons:
sauce_connect:
username: "chaijs-type-detect"
jwt:
secure: "GhkIK785QJbB1G5qwf51zpoJkHibS8wBhibID2jCL6TmQ8ZUHmihN2qnjuRvCI80uosHqkCBi3CeBYZIika5QFsg6LVVf5dnme7Qs0UkG+mw45yO6vcKycxbn1Bo5X8hqdtSjF/x+C91Wr4lelr5w/Sq2X7RokfE0fDVdklE5xQ="
script:
- npm run test:browser
env:
- TEST_BROWSERS_IN_SAUCELABS=1 # kept here for easier reading of build log
- SAUCE_USERNAME="chaijs-type-detect"
- SAUCE_CONNECT_READY_FILE=/tmp/sauce-connect-ready
- stage: test
node_js: 8 # to be removed 2019-12-01
script: npm run test:node
- stage: test
node_js: 7 # to be removed 2017-06-30
before_install: npm i -g npm@5
script: npm run test:node
- stage: test
node_js: 6 # to be removed 2019-04-01
before_install: npm i -g npm@5
script: npm run test:node
- stage: test
node_js: 4 # to be removed 2018-04-01
before_install: npm i -g npm@5
script: npm run test:node
- stage: test
node_js: lts/* # safety net; don't remove
script: npm run test:node
- stage: test
node_js: node # safety net; don't remove
script: npm run test:node
- stage: semantic-release
script:
- if [ "$TRAVIS_PULL_REQUEST" != "false" ] || [ "$TRAVIS_BRANCH" != "master" ]; then echo "the deploy job only runs for the master branch. This build will now exit"; exit 0; fi
- if [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_BRANCH" == "master" ]; then npm run semantic-release; fi
env:
- BUILD_LEADER_ID=10
# GH_TOKEN type-detect travis
- secure: "MPzfTVm7U1Q/eYhHT3DXwZki5Xn4ODNs/uXEM5PB2m+BxbytaAgU+3JSI0ZREv+JLk9CRnj2yWebaQkm+0ompkPRus0pEFuwEsMJ3HqV4ISj6zWGLPNjeJqy6kGa+m1WlkfHM+Spj7vrmk2yclZsmke4xpeQy9W8nnPDEHe6uoQ="
# NPM_TOKEN …7f80442b
- secure: "EM+nNOeL3X6Cz5u5aaBKZU6FqXrQVgKO543zy6CL3+Im/Esz2um9S2Ymgw9nzBH35SczhJh4Avfw7sujRdyHPL5XLbCWj2954TThsO8Ue62Xs/K3lQT6x8+iQc0jRZFtBkwX2sQjWFah04j381sKeTFFH94jifeW8dFOXXtWZfs="

env:
global:
- LOGS_DIR=/tmp/chai-build/logs
21 changes: 21 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: '{build}'

skip_tags: true
skip_branch_with_pr: true
clone_depth: 1
deploy: off
build: off

install:
- ps: Install-Product node '8'
- npm i -g npm@5
- npm install

test_script:
- node --version
- npm --version
- npm test

cache:
- node_modules -> package-lock.json
- '%APPDATA%\npm-cache'
17 changes: 17 additions & 0 deletions bench/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": [ "strict/test" ],
"env": {
"node": true,
"browser": true,
"es6": true
},
"rules": {
"no-new-wrappers": 0,
"no-array-constructor": 0,
"no-new-object": 0,
"no-empty-function": 0,
"no-undefined": 0,
"no-console": 0,
"id-length": 0
}
}
63 changes: 63 additions & 0 deletions bench/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const loupe = require('../')
const nodeInspect = require('util').inspect
const Benchmark = require('benchmark')
const benches = []
const mapObjRefA = {}
const mapObjRefB = {}
function getArguments() {
return arguments // eslint-disable-line prefer-rest-params
}
const fixtures = {
'string literal ': 'abc',
'array literal ': [1, 2, 3],
'boolean literal ': true,
'object literal ': { a: 1 },
'object from null ': Object.create(null),
'regex literal ': /^abc$/,
'number literal ': 1,
'null ': null,
'undefined ': undefined,
'buffer ': Buffer.from('hello world'),
'date ': new Date(123),
'map ': new Map().set('a', 1),
'map (complex) ': new Map().set(mapObjRefA, new Map().set(mapObjRefB, 1)),
'regex constructor ': new RegExp('abc'),
'set ': new Set().add(1),
'string constructor ': new String(),
'arguments ': getArguments(1, 2, 3),
}

function prepareBenchMark(test, name, inspect = loupe) {
benches.push(
new Benchmark(name, {
fn() {
inspect(test)
},
onCycle(event) {
process.stdout.clearLine()
process.stdout.cursorTo(0)
process.stdout.write(event.target.toString())
},
})
)
}

const filter = process.argv.slice(2).filter(arg => arg[0] !== '-')[0] || ''
const nodeinspect = process.argv.indexOf('--nodeinspect') !== -1
Object.keys(fixtures)
.filter(key => key.indexOf(filter) !== -1)
.forEach(testName => {
prepareBenchMark(fixtures[testName], `${testName} (loupe)`)
if (nodeinspect) {
prepareBenchMark(fixtures[testName], `${testName} (node)`, nodeInspect)
}
})
Benchmark.invoke(benches, {
name: 'run',
onCycle() {
console.log('')
},
onComplete() {
console.log('~Fin~')
keithamus marked this conversation as resolved.
Show resolved Hide resolved
},
})
14 changes: 0 additions & 14 deletions component.json

This file was deleted.

29 changes: 0 additions & 29 deletions hydro.conf.js

This file was deleted.

157 changes: 157 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/* !
* loupe
* Copyright(c) 2013 Jake Luer <jake@alogicalparadox.com>
* MIT Licensed
*/

import typeDetect from 'type-detect'

import inspectArray from './lib/array'
import inspectTypedArray from './lib/typedarray'
import inspectDate from './lib/date'
import inspectFunction from './lib/function'
import inspectMap from './lib/map'
import inspectNumber from './lib/number'
import inspectRegExp from './lib/regexp'
import inspectSet from './lib/set'
import inspectString from './lib/string'
import inspectSymbol from './lib/symbol'
import inspectPromise from './lib/promise'
import inspectClass from './lib/class'
import inspectObject from './lib/object'
import inspectArguments from './lib/arguments'
import inspectError from './lib/error'

import { normaliseOptions } from './lib/helpers'

const symbolsSupported = typeof Symbol === 'function' && typeof Symbol.for === 'function'
const chaiInspect = symbolsSupported ? Symbol.for('chai/inspect') : '@@chai/inspect'
let nodeInspect = false
try {
// eslint-disable-next-line global-require
nodeInspect = require('util').inspect.custom
} catch (noNodeInspect) {
nodeInspect = false
}

const constructorMap = new WeakMap()
const stringTagMap = {}
const baseTypesMap = {
undefined: (value, options) => options.stylize('undefined', 'undefined'),
null: (value, options) => options.stylize(null, 'null'),

boolean: (value, options) => options.stylize(value, 'boolean'),
Boolean: (value, options) => options.stylize(value, 'boolean'),

number: inspectNumber,
Number: inspectNumber,

string: inspectString,
String: inspectString,

function: inspectFunction,
Function: inspectFunction,

symbol: inspectSymbol,

Array: inspectArray,
Date: inspectDate,
Map: inspectMap,
Set: inspectSet,
RegExp: inspectRegExp,
Promise: inspectPromise,

// WeakSet, WeakMap are totally opaque to us
WeakSet: (value, options) => options.stylize('WeakSet{…}', 'special'),
WeakMap: (value, options) => options.stylize('WeakMap{…}', 'sepcial'),
keithamus marked this conversation as resolved.
Show resolved Hide resolved

Arguments: inspectArguments,
Int8Array: inspectTypedArray,
Uint8Array: inspectTypedArray,
Uint8ClampedArray: inspectTypedArray,
Int16Array: inspectTypedArray,
Uint16Array: inspectTypedArray,
Int32Array: inspectTypedArray,
Uint32Array: inspectTypedArray,
Float32Array: inspectTypedArray,
Float64Array: inspectTypedArray,

Generator: () => '',
DataView: () => '',
ArrayBuffer: () => '',

Error: inspectError,
}

const inspectCustom = (value, options, type) => {
if (chaiInspect in value && typeof value[chaiInspect] === 'function') {
return value[chaiInspect](options)
}

if (nodeInspect && nodeInspect in value && typeof value[nodeInspect] === 'function') {
return value[nodeInspect](options.depth, options)
}

if ('inspect' in value && typeof value.inspect === 'function') {
return value.inspect(options.depth, options)
}

if ('constructor' in value && constructorMap.has(value.constructor)) {
return constructorMap.get(value.constructor)(value, options)
}

if (stringTagMap[type]) {
return stringTagMap[type](value, options)
}

return ''
}

export default function inspect(value, options) {
options = normaliseOptions(options)
options.inspect = inspect
const { customInspect } = options
const type = typeDetect(value)

// If it is a base value that we already support, then use Loupe's inspector
if (baseTypesMap[type]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't someone set a custom inspect for those base values? IMO it's not an exotic use case and therefore the check for customInspectcould come first. Not sure I'm missing something here though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea here is to keep the base types protected. We don't want users to override base types to provide their own inspection; the custom inspection is really meant as a fallback for users who want to provide inspection for their own objects, not for builtins.

Essentially, I want to discourage the use of overriding for builtins because I don't think it will add value to this lib. Happy to hear otherwise though.

return baseTypesMap[type](value, options)
}

// If its a plain Object then use Loupe's inspector
keithamus marked this conversation as resolved.
Show resolved Hide resolved
if (value && Object.getPrototypeOf(value) === Object.prototype) {
return inspectObject(value, options)
}

// If `options.customInspect` is set to true then try to use the custom inspector
if (customInspect && value) {
const output = inspectCustom(value, options, type)
if (output) return output
}

// If it is a class, inspect it like an object but add the constructor name
if ('constructor' in value && value.constructor !== Object) {
return inspectClass(value, options)
}

// We have run out of options! Just stringify the value
return options.stylize(String(value), type)
}

export function registerConstructor(constructor, inspector) {
if (constructorMap.has(constructor)) {
return false
}
constructorMap.add(constructor, inspector)
return true
}

export function registerStringTag(stringTag, inspector) {
if (stringTag in stringTagMap) {
return false
}
stringTagMap[stringTag] = inspector
return true
}

export const custom = chaiInspect
Loading