A few more files refactored to ES modules

This commit is contained in:
jos 2019-08-31 11:21:29 +02:00
parent f321eb54ee
commit b79885471e
15 changed files with 356 additions and 323 deletions

View File

@ -4,8 +4,8 @@ https://github.com/josdejong/jsoneditor
## not yet published, version 7.0.0 ## not yet published, version 7.0.0
- Converted a large part of the code to ES6, put Babel transpiler in place.
- Dropped support for bower, removed the `dist` folder from the git repository. - Dropped support for bower, removed the `dist` folder from the git repository.
- Converted the code into ES6, put Babel transpiler in place.
- Fixed #586: caret position lost when switching browser tabs. - Fixed #586: caret position lost when switching browser tabs.

View File

@ -1,40 +1,40 @@
var fs = require('fs') const fs = require('fs')
var path = require('path') const path = require('path')
var gulp = require('gulp') const gulp = require('gulp')
var log = require('fancy-log') const log = require('fancy-log')
var format = require('date-format') const format = require('date-format')
var concatCss = require('gulp-concat-css') const concatCss = require('gulp-concat-css')
var minifyCSS = require('gulp-clean-css') const minifyCSS = require('gulp-clean-css')
var sass = require('gulp-sass') const sass = require('gulp-sass')
var mkdirp = require('mkdirp') const mkdirp = require('mkdirp')
var webpack = require('webpack') const webpack = require('webpack')
var uglify = require('uglify-js') const uglify = require('uglify-js')
var NAME = 'jsoneditor' const NAME = 'jsoneditor'
var NAME_MINIMALIST = 'jsoneditor-minimalist' const NAME_MINIMALIST = 'jsoneditor-minimalist'
var ENTRY = './src/js/JSONEditor.js' const ENTRY = './src/js/JSONEditor.js'
var HEADER = './src/js/header.js' const HEADER = './src/js/header.js'
var IMAGE = './src/scss/img/jsoneditor-icons.svg' const IMAGE = './src/scss/img/jsoneditor-icons.svg'
var DOCS = './src/docs/*' const DOCS = './src/docs/*'
var DIST = path.join(__dirname, 'dist') const DIST = path.join(__dirname, 'dist')
// generate banner with today's date and correct version // generate banner with today's date and correct version
function createBanner () { function createBanner () {
var today = format.asString('yyyy-MM-dd', new Date()) // today, formatted as yyyy-MM-dd const today = format.asString('yyyy-MM-dd', new Date()) // today, formatted as yyyy-MM-dd
var version = require('./package.json').version // math.js version const version = require('./package.json').version // math.js version
return String(fs.readFileSync(HEADER)) return String(fs.readFileSync(HEADER))
.replace('@@date', today) .replace('@@date', today)
.replace('@@version', version) .replace('@@version', version)
} }
var bannerPlugin = new webpack.BannerPlugin({ const bannerPlugin = new webpack.BannerPlugin({
banner: createBanner(), banner: createBanner(),
entryOnly: true, entryOnly: true,
raw: true raw: true
}) })
var webpackConfigModule = { const webpackConfigModule = {
rules: [ rules: [
{ {
test: /\.m?js$/, test: /\.m?js$/,
@ -47,7 +47,7 @@ var webpackConfigModule = {
} }
// create a single instance of the compiler to allow caching // create a single instance of the compiler to allow caching
var compiler = webpack({ const compiler = webpack({
entry: ENTRY, entry: ENTRY,
output: { output: {
library: 'JSONEditor', library: 'JSONEditor',
@ -69,7 +69,7 @@ var compiler = webpack({
}) })
// create a single instance of the compiler to allow caching // create a single instance of the compiler to allow caching
var compilerMinimalist = webpack({ const compilerMinimalist = webpack({
entry: ENTRY, entry: ENTRY,
output: { output: {
library: 'JSONEditor', library: 'JSONEditor',
@ -92,8 +92,8 @@ var compilerMinimalist = webpack({
}) })
function minify (name) { function minify (name) {
var code = String(fs.readFileSync(DIST + '/' + name + '.js')) const code = String(fs.readFileSync(DIST + '/' + name + '.js'))
var result = uglify.minify(code, { const result = uglify.minify(code, {
sourceMap: { sourceMap: {
url: name + '.map' url: name + '.map'
}, },
@ -107,8 +107,8 @@ function minify (name) {
throw result.error throw result.error
} }
var fileMin = DIST + '/' + name + '.min.js' const fileMin = DIST + '/' + name + '.min.js'
var fileMap = DIST + '/' + name + '.map' const fileMap = DIST + '/' + name + '.map'
fs.writeFileSync(fileMin, result.code) fs.writeFileSync(fileMin, result.code)
fs.writeFileSync(fileMap, result.map) fs.writeFileSync(fileMap, result.map)

View File

@ -1 +1 @@
module.exports = require('./src/js/JSONEditor').default module.exports = require('./src/js/JSONEditor')

View File

@ -2,11 +2,10 @@
const ace = require('./ace') // may be undefined in case of minimalist bundle const ace = require('./ace') // may be undefined in case of minimalist bundle
const VanillaPicker = require('./vanilla-picker') // may be undefined in case of minimalist bundle const VanillaPicker = require('./vanilla-picker') // may be undefined in case of minimalist bundle
const { treeModeMixins } = require('./treemode')
const treeModeMixins = require('./treemode').treeModeMixins const { textModeMixins } = require('./textmode')
const textModeMixins = require('./textmode').textModeMixins const { previewModeMixins } = require('./previewmode')
const previewModeMixins = require('./previewmode').previewModeMixins const { clear, extend, getInternetExplorerVersion, parse } = require('./util')
const util = require('./util')
const { tryRequireAjv } = require('./tryRequireAjv') const { tryRequireAjv } = require('./tryRequireAjv')
const Ajv = tryRequireAjv() const Ajv = tryRequireAjv()
@ -97,7 +96,7 @@ function JSONEditor (container, options, json) {
} }
// check for unsupported browser (IE8 and older) // check for unsupported browser (IE8 and older)
const ieVersion = util.getInternetExplorerVersion() const ieVersion = getInternetExplorerVersion()
if (ieVersion !== -1 && ieVersion < 9) { if (ieVersion !== -1 && ieVersion < 9) {
throw new Error('Unsupported browser, IE9 or newer required. ' + throw new Error('Unsupported browser, IE9 or newer required. ' +
'Please install the newest version of your browser.') 'Please install the newest version of your browser.')
@ -220,7 +219,7 @@ JSONEditor.prototype.get = function () {
* @param {String | undefined} jsonText * @param {String | undefined} jsonText
*/ */
JSONEditor.prototype.setText = function (jsonText) { JSONEditor.prototype.setText = function (jsonText) {
this.json = util.parse(jsonText) this.json = parse(jsonText)
} }
/** /**
@ -263,7 +262,7 @@ JSONEditor.prototype.setMode = function (mode) {
} }
const container = this.container const container = this.container
const options = util.extend({}, this.options) const options = extend({}, this.options)
const oldMode = options.mode const oldMode = options.mode
let data let data
let name let name
@ -277,8 +276,8 @@ JSONEditor.prototype.setMode = function (mode) {
data = this[asText ? 'getText' : 'get']() // get text or json data = this[asText ? 'getText' : 'get']() // get text or json
this.destroy() this.destroy()
util.clear(this) clear(this)
util.extend(this, config.mixin) extend(this, config.mixin)
this.create(container, options) this.create(container, options)
this.setName(name) this.setName(name)
@ -428,7 +427,7 @@ JSONEditor.prototype.refresh = () => {
JSONEditor.registerMode = mode => { JSONEditor.registerMode = mode => {
let i, prop let i, prop
if (util.isArray(mode)) { if (Array.isArray(mode)) {
// multiple modes // multiple modes
for (i = 0; i < mode.length; i++) { for (i = 0; i < mode.length; i++) {
JSONEditor.registerMode(mode[i]) JSONEditor.registerMode(mode[i])

View File

@ -1,7 +1,7 @@
'use strict' 'use strict'
const ContextMenu = require('./ContextMenu').ContextMenu import { ContextMenu } from './ContextMenu'
const translate = require('./i18n').translate import { translate } from './i18n'
/** /**
* Create a select box to be used in the editor menu's, which allows to switch mode * Create a select box to be used in the editor menu's, which allows to switch mode
@ -11,7 +11,7 @@ const translate = require('./i18n').translate
* @param {function(mode: string)} onSwitch Callback invoked on switch * @param {function(mode: string)} onSwitch Callback invoked on switch
* @constructor * @constructor
*/ */
function ModeSwitcher (container, modes, current, onSwitch) { export function ModeSwitcher (container, modes, current, onSwitch) {
// available modes // available modes
const availableModes = { const availableModes = {
code: { code: {
@ -119,5 +119,3 @@ ModeSwitcher.prototype.destroy = function () {
} }
this.dom = null this.dom = null
} }
module.exports = ModeSwitcher

View File

@ -1,16 +1,39 @@
'use strict' 'use strict'
const jmespath = require('jmespath') import jmespath from 'jmespath'
const naturalSort = require('javascript-natural-sort') import naturalSort from 'javascript-natural-sort'
const createAbsoluteAnchor = require('./createAbsoluteAnchor').createAbsoluteAnchor import { createAbsoluteAnchor } from './createAbsoluteAnchor'
const ContextMenu = require('./ContextMenu').ContextMenu import { ContextMenu } from './ContextMenu'
const appendNodeFactory = require('./appendNodeFactory') import { appendNodeFactory } from './appendNodeFactory'
const showMoreNodeFactory = require('./showMoreNodeFactory').showMoreNodeFactory import { showMoreNodeFactory } from './showMoreNodeFactory'
const showSortModal = require('./showSortModal').showSortModal import { showSortModal } from './showSortModal'
const showTransformModal = require('./showTransformModal').showTransformModal import { showTransformModal } from './showTransformModal'
const util = require('./util') import {
const translate = require('./i18n').translate addClassName,
const DEFAULT_MODAL_ANCHOR = require('./constants').DEFAULT_MODAL_ANCHOR addEventListener,
debounce,
escapeUnicodeChars,
findUniqueName,
getAbsoluteLeft,
getAbsoluteTop,
getInnerText,
getType,
insideRect,
isUrl,
isValidColor,
makeFieldTooltip,
parse,
parsePath,
parseString, removeAllClassNames,
removeClassName,
removeEventListener,
selectContentEditable,
setEndOfContentEditable,
stripFormatting,
textDiff
} from './util'
import { translate } from './i18n'
import { DEFAULT_MODAL_ANCHOR } from './constants'
const YEAR_2000 = 946684800000 const YEAR_2000 = 946684800000
@ -44,8 +67,8 @@ function Node (editor, params) {
this.setValue(null) this.setValue(null)
} }
this._debouncedOnChangeValue = util.debounce(this._onChangeValue.bind(this), Node.prototype.DEBOUNCE_INTERVAL) this._debouncedOnChangeValue = debounce(this._onChangeValue.bind(this), Node.prototype.DEBOUNCE_INTERVAL)
this._debouncedOnChangeField = util.debounce(this._onChangeField.bind(this), Node.prototype.DEBOUNCE_INTERVAL) this._debouncedOnChangeField = debounce(this._onChangeField.bind(this), Node.prototype.DEBOUNCE_INTERVAL)
// starting value for visible children // starting value for visible children
this.visibleChilds = this.getMaxVisibleChilds() this.visibleChilds = this.getMaxVisibleChilds()
@ -206,7 +229,7 @@ Node.prototype.serialize = function () {
* @return {Node | null} Returns the Node when found, returns null if not found * @return {Node | null} Returns the Node when found, returns null if not found
*/ */
Node.prototype.findNode = function (jsonPath) { Node.prototype.findNode = function (jsonPath) {
const path = util.parsePath(jsonPath) const path = parsePath(jsonPath)
let node = this let node = this
while (node && path.length > 0) { while (node && path.length > 0) {
const prop = path.shift() const prop = path.shift()
@ -265,7 +288,7 @@ Node.prototype.updateError = function () {
const error = this.fieldError || this.valueError || this.error const error = this.fieldError || this.valueError || this.error
let tdError = this.dom.tdError let tdError = this.dom.tdError
if (error && this.dom && this.dom.tr) { if (error && this.dom && this.dom.tr) {
util.addClassName(this.dom.tr, 'jsoneditor-validation-error') addClassName(this.dom.tr, 'jsoneditor-validation-error')
if (!tdError) { if (!tdError) {
tdError = document.createElement('td') tdError = document.createElement('td')
@ -292,7 +315,7 @@ Node.prototype.updateError = function () {
const contentRect = this.editor.content.getBoundingClientRect() const contentRect = this.editor.content.getBoundingClientRect()
const popoverRect = popover.getBoundingClientRect() const popoverRect = popover.getBoundingClientRect()
const margin = 20 // account for a scroll bar const margin = 20 // account for a scroll bar
const fit = util.insideRect(contentRect, popoverRect, margin) const fit = insideRect(contentRect, popoverRect, margin)
if (fit) { if (fit) {
break break
@ -322,7 +345,7 @@ Node.prototype.updateError = function () {
tdError.appendChild(button) tdError.appendChild(button)
} else { } else {
if (this.dom.tr) { if (this.dom.tr) {
util.removeClassName(this.dom.tr, 'jsoneditor-validation-error') removeClassName(this.dom.tr, 'jsoneditor-validation-error')
} }
if (tdError) { if (tdError) {
@ -894,9 +917,9 @@ Node.prototype._updateCssClassName = function () {
this.editor.options && this.editor.options &&
typeof this.editor.options.onClassName === 'function' && typeof this.editor.options.onClassName === 'function' &&
this.dom.tree) { this.dom.tree) {
util.removeAllClassNames(this.dom.tree) removeAllClassNames(this.dom.tree)
const addClasses = this.editor.options.onClassName({ path: this.getPath(), field: this.field, value: this.value }) || '' const addClasses = this.editor.options.onClassName({ path: this.getPath(), field: this.field, value: this.value }) || ''
util.addClassName(this.dom.tree, 'jsoneditor-values ' + addClasses) addClassName(this.dom.tree, 'jsoneditor-values ' + addClasses)
} }
} }
@ -1209,10 +1232,10 @@ Node.prototype.focus = function (elementName) {
dom.expand.focus() dom.expand.focus()
} else if (dom.field && this.fieldEditable) { } else if (dom.field && this.fieldEditable) {
dom.field.focus() dom.field.focus()
util.selectContentEditable(dom.field) selectContentEditable(dom.field)
} else if (dom.value && !this._hasChilds()) { } else if (dom.value && !this._hasChilds()) {
dom.value.focus() dom.value.focus()
util.selectContentEditable(dom.value) selectContentEditable(dom.value)
} else { } else {
dom.menu.focus() dom.menu.focus()
} }
@ -1221,10 +1244,10 @@ Node.prototype.focus = function (elementName) {
case 'field': case 'field':
if (dom.field && this.fieldEditable) { if (dom.field && this.fieldEditable) {
dom.field.focus() dom.field.focus()
util.selectContentEditable(dom.field) selectContentEditable(dom.field)
} else if (dom.value && !this._hasChilds()) { } else if (dom.value && !this._hasChilds()) {
dom.value.focus() dom.value.focus()
util.selectContentEditable(dom.value) selectContentEditable(dom.value)
} else if (this._hasChilds()) { } else if (this._hasChilds()) {
dom.expand.focus() dom.expand.focus()
} else { } else {
@ -1239,10 +1262,10 @@ Node.prototype.focus = function (elementName) {
dom.select.focus() dom.select.focus()
} else if (dom.value && !this._hasChilds()) { } else if (dom.value && !this._hasChilds()) {
dom.value.focus() dom.value.focus()
util.selectContentEditable(dom.value) selectContentEditable(dom.value)
} else if (dom.field && this.fieldEditable) { } else if (dom.field && this.fieldEditable) {
dom.field.focus() dom.field.focus()
util.selectContentEditable(dom.field) selectContentEditable(dom.field)
} else if (this._hasChilds()) { } else if (this._hasChilds()) {
dom.expand.focus() dom.expand.focus()
} else { } else {
@ -1259,7 +1282,7 @@ Node.prototype.focus = function (elementName) {
*/ */
Node.select = editableDiv => { Node.select = editableDiv => {
setTimeout(() => { setTimeout(() => {
util.selectContentEditable(editableDiv) selectContentEditable(editableDiv)
}, 0) }, 0)
} }
@ -1406,7 +1429,7 @@ Node.prototype.changeType = function (newType) {
if (newType === 'string') { if (newType === 'string') {
this.value = String(this.value) this.value = String(this.value)
} else { } else {
this.value = util.parseString(String(this.value)) this.value = parseString(String(this.value))
} }
this.focus() this.focus()
@ -1483,7 +1506,7 @@ Node.prototype._getDomValue = function () {
this._clearValueError() this._clearValueError()
if (this.dom.value && this.type !== 'array' && this.type !== 'object') { if (this.dom.value && this.type !== 'array' && this.type !== 'object') {
this.valueInnerText = util.getInnerText(this.dom.value) this.valueInnerText = getInnerText(this.dom.value)
} }
if (this.valueInnerText !== undefined) { if (this.valueInnerText !== undefined) {
@ -1494,7 +1517,7 @@ Node.prototype._getDomValue = function () {
value = this._unescapeHTML(this.valueInnerText) value = this._unescapeHTML(this.valueInnerText)
} else { } else {
const str = this._unescapeHTML(this.valueInnerText) const str = this._unescapeHTML(this.valueInnerText)
value = util.parseString(str) value = parseString(str)
} }
if (value !== this.value) { if (value !== this.value) {
this.value = value this.value = value
@ -1554,13 +1577,13 @@ Node.prototype._onChangeValue = function () {
// the added/removed text on undo/redo // the added/removed text on undo/redo
const oldSelection = this.editor.getDomSelection() const oldSelection = this.editor.getDomSelection()
if (oldSelection.range) { if (oldSelection.range) {
const undoDiff = util.textDiff(String(this.value), String(this.previousValue)) const undoDiff = textDiff(String(this.value), String(this.previousValue))
oldSelection.range.startOffset = undoDiff.start oldSelection.range.startOffset = undoDiff.start
oldSelection.range.endOffset = undoDiff.end oldSelection.range.endOffset = undoDiff.end
} }
const newSelection = this.editor.getDomSelection() const newSelection = this.editor.getDomSelection()
if (newSelection.range) { if (newSelection.range) {
const redoDiff = util.textDiff(String(this.previousValue), String(this.value)) const redoDiff = textDiff(String(this.previousValue), String(this.value))
newSelection.range.startOffset = redoDiff.start newSelection.range.startOffset = redoDiff.start
newSelection.range.endOffset = redoDiff.end newSelection.range.endOffset = redoDiff.end
} }
@ -1586,13 +1609,13 @@ Node.prototype._onChangeField = function () {
const oldSelection = this.editor.getDomSelection() const oldSelection = this.editor.getDomSelection()
const previous = this.previousField || '' const previous = this.previousField || ''
if (oldSelection.range) { if (oldSelection.range) {
const undoDiff = util.textDiff(this.field, previous) const undoDiff = textDiff(this.field, previous)
oldSelection.range.startOffset = undoDiff.start oldSelection.range.startOffset = undoDiff.start
oldSelection.range.endOffset = undoDiff.end oldSelection.range.endOffset = undoDiff.end
} }
const newSelection = this.editor.getDomSelection() const newSelection = this.editor.getDomSelection()
if (newSelection.range) { if (newSelection.range) {
const redoDiff = util.textDiff(previous, this.field) const redoDiff = textDiff(previous, this.field)
newSelection.range.startOffset = redoDiff.start newSelection.range.startOffset = redoDiff.start
newSelection.range.endOffset = redoDiff.end newSelection.range.endOffset = redoDiff.end
} }
@ -1623,10 +1646,10 @@ Node.prototype._updateDomValue = function () {
// set text color depending on value type // set text color depending on value type
const value = this.value const value = this.value
const type = (this.type === 'auto') ? util.type(value) : this.type const valueType = (this.type === 'auto') ? getType(value) : this.type
const isUrl = type === 'string' && util.isUrl(value) const valueIsUrl = valueType === 'string' && isUrl(value)
classNames.push('jsoneditor-' + type) classNames.push('jsoneditor-' + valueType)
if (isUrl) { if (valueIsUrl) {
classNames.push('jsoneditor-url') classNames.push('jsoneditor-url')
} }
@ -1647,17 +1670,17 @@ Node.prototype._updateDomValue = function () {
domValue.className = classNames.join(' ') domValue.className = classNames.join(' ')
// update title // update title
if (type === 'array' || type === 'object') { if (valueType === 'array' || valueType === 'object') {
const count = this.childs ? this.childs.length : 0 const count = this.childs ? this.childs.length : 0
domValue.title = this.type + ' containing ' + count + ' items' domValue.title = this.type + ' containing ' + count + ' items'
} else if (isUrl && this.editable.value) { } else if (valueIsUrl && this.editable.value) {
domValue.title = translate('openUrl') domValue.title = translate('openUrl')
} else { } else {
domValue.title = '' domValue.title = ''
} }
// show checkbox when the value is a boolean // show checkbox when the value is a boolean
if (type === 'boolean' && this.editable.value) { if (valueType === 'boolean' && this.editable.value) {
if (!this.dom.checkbox) { if (!this.dom.checkbox) {
this.dom.checkbox = document.createElement('input') this.dom.checkbox = document.createElement('input')
this.dom.checkbox.type = 'checkbox' this.dom.checkbox.type = 'checkbox'
@ -1738,7 +1761,7 @@ Node.prototype._updateDomValue = function () {
if (this.editable.value && if (this.editable.value &&
this.editor.options.colorPicker && this.editor.options.colorPicker &&
typeof value === 'string' && typeof value === 'string' &&
util.isValidColor(value)) { isValidColor(value)) {
if (!this.dom.color) { if (!this.dom.color) {
this.dom.color = document.createElement('div') this.dom.color = document.createElement('div')
this.dom.color.className = 'jsoneditor-color' this.dom.color.className = 'jsoneditor-color'
@ -1782,7 +1805,7 @@ Node.prototype._updateDomValue = function () {
} }
// strip formatting from the contents of the editable div // strip formatting from the contents of the editable div
util.stripFormatting(domValue) stripFormatting(domValue)
this._updateDomDefault() this._updateDomDefault()
} }
@ -1808,7 +1831,7 @@ Node.prototype._deleteDomColor = function () {
Node.prototype._updateDomField = function () { Node.prototype._updateDomField = function () {
const domField = this.dom.field const domField = this.dom.field
if (domField) { if (domField) {
const tooltip = util.makeFieldTooltip(this.schema, this.editor.options.language) const tooltip = makeFieldTooltip(this.schema, this.editor.options.language)
if (tooltip) { if (tooltip) {
domField.title = tooltip domField.title = tooltip
} }
@ -1816,25 +1839,25 @@ Node.prototype._updateDomField = function () {
// make backgound color lightgray when empty // make backgound color lightgray when empty
const isEmpty = (String(this.field) === '' && this.parent.type !== 'array') const isEmpty = (String(this.field) === '' && this.parent.type !== 'array')
if (isEmpty) { if (isEmpty) {
util.addClassName(domField, 'jsoneditor-empty') addClassName(domField, 'jsoneditor-empty')
} else { } else {
util.removeClassName(domField, 'jsoneditor-empty') removeClassName(domField, 'jsoneditor-empty')
} }
// highlight when there is a search result // highlight when there is a search result
if (this.searchFieldActive) { if (this.searchFieldActive) {
util.addClassName(domField, 'jsoneditor-highlight-active') addClassName(domField, 'jsoneditor-highlight-active')
} else { } else {
util.removeClassName(domField, 'jsoneditor-highlight-active') removeClassName(domField, 'jsoneditor-highlight-active')
} }
if (this.searchField) { if (this.searchField) {
util.addClassName(domField, 'jsoneditor-highlight') addClassName(domField, 'jsoneditor-highlight')
} else { } else {
util.removeClassName(domField, 'jsoneditor-highlight') removeClassName(domField, 'jsoneditor-highlight')
} }
// strip formatting from the contents of the editable div // strip formatting from the contents of the editable div
util.stripFormatting(domField) stripFormatting(domField)
} }
} }
@ -1848,7 +1871,7 @@ Node.prototype._getDomField = function (forceUnique) {
this._clearFieldError() this._clearFieldError()
if (this.dom.field && this.fieldEditable) { if (this.dom.field && this.fieldEditable) {
this.fieldInnerText = util.getInnerText(this.dom.field) this.fieldInnerText = getInnerText(this.dom.field)
} }
if (this.fieldInnerText !== undefined) { if (this.fieldInnerText !== undefined) {
@ -1866,7 +1889,7 @@ Node.prototype._getDomField = function (forceUnique) {
} else { } else {
if (forceUnique) { if (forceUnique) {
// fix duplicate field: change it into a unique name // fix duplicate field: change it into a unique name
field = util.findUniqueName(field, existingFieldNames) field = findUniqueName(field, existingFieldNames)
if (field !== this.field) { if (field !== this.field) {
this.field = field this.field = field
@ -1906,12 +1929,12 @@ Node.prototype._updateDomDefault = function () {
if (this.value === this.schema.default) { if (this.value === this.schema.default) {
inputElement.title = translate('default') inputElement.title = translate('default')
util.addClassName(inputElement, 'jsoneditor-is-default') addClassName(inputElement, 'jsoneditor-is-default')
util.removeClassName(inputElement, 'jsoneditor-is-not-default') removeClassName(inputElement, 'jsoneditor-is-not-default')
} else { } else {
inputElement.removeAttribute('title') inputElement.removeAttribute('title')
util.removeClassName(inputElement, 'jsoneditor-is-default') removeClassName(inputElement, 'jsoneditor-is-default')
util.addClassName(inputElement, 'jsoneditor-is-not-default') addClassName(inputElement, 'jsoneditor-is-not-default')
} }
} }
@ -2009,16 +2032,16 @@ Node.onDragStart = (nodes, event) => {
// in case of multiple selected nodes, offsetY prevents the selection from // in case of multiple selected nodes, offsetY prevents the selection from
// jumping when you start dragging one of the lower down nodes in the selection // jumping when you start dragging one of the lower down nodes in the selection
const offsetY = util.getAbsoluteTop(draggedNode.dom.tr) - util.getAbsoluteTop(firstNode.dom.tr) const offsetY = getAbsoluteTop(draggedNode.dom.tr) - getAbsoluteTop(firstNode.dom.tr)
if (!editor.mousemove) { if (!editor.mousemove) {
editor.mousemove = util.addEventListener(window, 'mousemove', event => { editor.mousemove = addEventListener(window, 'mousemove', event => {
Node.onDrag(nodes, event) Node.onDrag(nodes, event)
}) })
} }
if (!editor.mouseup) { if (!editor.mouseup) {
editor.mouseup = util.addEventListener(window, 'mouseup', event => { editor.mouseup = addEventListener(window, 'mouseup', event => {
Node.onDragEnd(nodes, event) Node.onDragEnd(nodes, event)
}) })
} }
@ -2068,7 +2091,7 @@ Node.onDrag = (nodes, event) => {
// move up/down // move up/down
const firstNode = nodes[0] const firstNode = nodes[0]
const trThis = firstNode.dom.tr const trThis = firstNode.dom.tr
let topThis = util.getAbsoluteTop(trThis) let topThis = getAbsoluteTop(trThis)
const heightThis = trThis.offsetHeight const heightThis = trThis.offsetHeight
if (mouseY < topThis) { if (mouseY < topThis) {
// move up // move up
@ -2076,7 +2099,7 @@ Node.onDrag = (nodes, event) => {
do { do {
trPrev = trPrev.previousSibling trPrev = trPrev.previousSibling
nodePrev = Node.getNodeFromTarget(trPrev) nodePrev = Node.getNodeFromTarget(trPrev)
topPrev = trPrev ? util.getAbsoluteTop(trPrev) : 0 topPrev = trPrev ? getAbsoluteTop(trPrev) : 0
} }
while (trPrev && mouseY < topPrev) while (trPrev && mouseY < topPrev)
@ -2097,7 +2120,7 @@ Node.onDrag = (nodes, event) => {
if (nodePrev && nodePrev.isVisible()) { if (nodePrev && nodePrev.isVisible()) {
// check if mouseY is really inside the found node // check if mouseY is really inside the found node
trPrev = nodePrev.dom.tr trPrev = nodePrev.dom.tr
topPrev = trPrev ? util.getAbsoluteTop(trPrev) : 0 topPrev = trPrev ? getAbsoluteTop(trPrev) : 0
if (mouseY > topPrev + heightThis) { if (mouseY > topPrev + heightThis) {
nodePrev = undefined nodePrev = undefined
} }
@ -2115,13 +2138,13 @@ Node.onDrag = (nodes, event) => {
trLast = (lastNode.expanded && lastNode.append) ? lastNode.append.getDom() : lastNode.dom.tr trLast = (lastNode.expanded && lastNode.append) ? lastNode.append.getDom() : lastNode.dom.tr
trFirst = trLast ? trLast.nextSibling : undefined trFirst = trLast ? trLast.nextSibling : undefined
if (trFirst) { if (trFirst) {
topFirst = util.getAbsoluteTop(trFirst) topFirst = getAbsoluteTop(trFirst)
trNext = trFirst trNext = trFirst
do { do {
nodeNext = Node.getNodeFromTarget(trNext) nodeNext = Node.getNodeFromTarget(trNext)
if (trNext) { if (trNext) {
bottomNext = trNext.nextSibling bottomNext = trNext.nextSibling
? util.getAbsoluteTop(trNext.nextSibling) : 0 ? getAbsoluteTop(trNext.nextSibling) : 0
heightNext = trNext ? (bottomNext - topFirst) : 0 heightNext = trNext ? (bottomNext - topFirst) : 0
if (nodeNext && if (nodeNext &&
@ -2267,11 +2290,11 @@ Node.onDragEnd = (nodes, event) => {
delete editor.drag delete editor.drag
if (editor.mousemove) { if (editor.mousemove) {
util.removeEventListener(window, 'mousemove', editor.mousemove) removeEventListener(window, 'mousemove', editor.mousemove)
delete editor.mousemove delete editor.mousemove
} }
if (editor.mouseup) { if (editor.mouseup) {
util.removeEventListener(window, 'mouseup', editor.mouseup) removeEventListener(window, 'mouseup', editor.mouseup)
delete editor.mouseup delete editor.mouseup
} }
@ -2314,9 +2337,9 @@ Node.prototype._createDomField = () => document.createElement('div')
Node.prototype.setHighlight = function (highlight) { Node.prototype.setHighlight = function (highlight) {
if (this.dom.tr) { if (this.dom.tr) {
if (highlight) { if (highlight) {
util.addClassName(this.dom.tr, 'jsoneditor-highlight') addClassName(this.dom.tr, 'jsoneditor-highlight')
} else { } else {
util.removeClassName(this.dom.tr, 'jsoneditor-highlight') removeClassName(this.dom.tr, 'jsoneditor-highlight')
} }
if (this.append) { if (this.append) {
@ -2341,15 +2364,15 @@ Node.prototype.setSelected = function (selected, isFirst) {
if (this.dom.tr) { if (this.dom.tr) {
if (selected) { if (selected) {
util.addClassName(this.dom.tr, 'jsoneditor-selected') addClassName(this.dom.tr, 'jsoneditor-selected')
} else { } else {
util.removeClassName(this.dom.tr, 'jsoneditor-selected') removeClassName(this.dom.tr, 'jsoneditor-selected')
} }
if (isFirst) { if (isFirst) {
util.addClassName(this.dom.tr, 'jsoneditor-first') addClassName(this.dom.tr, 'jsoneditor-first')
} else { } else {
util.removeClassName(this.dom.tr, 'jsoneditor-first') removeClassName(this.dom.tr, 'jsoneditor-first')
} }
if (this.append) { if (this.append) {
@ -2450,13 +2473,13 @@ Node.prototype.updateDom = function (options) {
if (domValue) { if (domValue) {
if (this.type === 'array') { if (this.type === 'array') {
this.updateNodeName() this.updateNodeName()
util.addClassName(this.dom.tr, 'jsoneditor-expandable') addClassName(this.dom.tr, 'jsoneditor-expandable')
} else if (this.type === 'object') { } else if (this.type === 'object') {
this.updateNodeName() this.updateNodeName()
util.addClassName(this.dom.tr, 'jsoneditor-expandable') addClassName(this.dom.tr, 'jsoneditor-expandable')
} else { } else {
domValue.innerHTML = this._escapeHTML(this.value) domValue.innerHTML = this._escapeHTML(this.value)
util.removeClassName(this.dom.tr, 'jsoneditor-expandable') removeClassName(this.dom.tr, 'jsoneditor-expandable')
} }
} }
@ -2649,7 +2672,7 @@ Node.prototype._createDomValue = function () {
domValue = document.createElement('div') domValue = document.createElement('div')
domValue.innerHTML = '{...}' domValue.innerHTML = '{...}'
} else { } else {
if (!this.editable.value && util.isUrl(this.value)) { if (!this.editable.value && isUrl(this.value)) {
// create a link in case of read-only editor and value containing an url // create a link in case of read-only editor and value containing an url
domValue = document.createElement('a') domValue = document.createElement('a')
domValue.href = this.value domValue.href = this.value
@ -2770,9 +2793,9 @@ Node.prototype.onEvent = function (event) {
const highlighter = node.editor.highlighter const highlighter = node.editor.highlighter
highlighter.highlight(node) highlighter.highlight(node)
highlighter.lock() highlighter.lock()
util.addClassName(dom.menu, 'jsoneditor-selected') addClassName(dom.menu, 'jsoneditor-selected')
this.showContextMenu(dom.menu, () => { this.showContextMenu(dom.menu, () => {
util.removeClassName(dom.menu, 'jsoneditor-selected') removeClassName(dom.menu, 'jsoneditor-selected')
highlighter.unlock() highlighter.unlock()
highlighter.unhighlight() highlighter.unhighlight()
}) })
@ -2840,7 +2863,7 @@ Node.prototype.onEvent = function (event) {
case 'click': case 'click':
if (event.ctrlKey && this.editable.value) { if (event.ctrlKey && this.editable.value) {
// if read-only, we use the regular click behavior of an anchor // if read-only, we use the regular click behavior of an anchor
if (util.isUrl(this.value)) { if (isUrl(this.value)) {
event.preventDefault() event.preventDefault()
window.open(this.value, '_blank') window.open(this.value, '_blank')
} }
@ -2911,16 +2934,16 @@ Node.prototype.onEvent = function (event) {
if (domTree && target === domTree.parentNode && type === 'click' && !event.hasMoved) { if (domTree && target === domTree.parentNode && type === 'click' && !event.hasMoved) {
const left = (event.offsetX !== undefined) const left = (event.offsetX !== undefined)
? (event.offsetX < (this.getLevel() + 1) * 24) ? (event.offsetX < (this.getLevel() + 1) * 24)
: (event.pageX < util.getAbsoluteLeft(dom.tdSeparator))// for FF : (event.pageX < getAbsoluteLeft(dom.tdSeparator))// for FF
if (left || expandable) { if (left || expandable) {
// node is expandable when it is an object or array // node is expandable when it is an object or array
if (domField) { if (domField) {
util.setEndOfContentEditable(domField) setEndOfContentEditable(domField)
domField.focus() domField.focus()
} }
} else { } else {
if (domValue && !this.enum) { if (domValue && !this.enum) {
util.setEndOfContentEditable(domValue) setEndOfContentEditable(domValue)
domValue.focus() domValue.focus()
} }
} }
@ -2928,7 +2951,7 @@ Node.prototype.onEvent = function (event) {
if (((target === dom.tdExpand && !expandable) || target === dom.tdField || target === dom.tdSeparator) && if (((target === dom.tdExpand && !expandable) || target === dom.tdField || target === dom.tdSeparator) &&
(type === 'click' && !event.hasMoved)) { (type === 'click' && !event.hasMoved)) {
if (domField) { if (domField) {
util.setEndOfContentEditable(domField) setEndOfContentEditable(domField)
domField.focus() domField.focus()
} }
} }
@ -2994,7 +3017,7 @@ Node.prototype.onKeyDown = function (event) {
if (keynum === 13) { // Enter if (keynum === 13) { // Enter
if (target === this.dom.value) { if (target === this.dom.value) {
if (!this.editable.value || event.ctrlKey) { if (!this.editable.value || event.ctrlKey) {
if (util.isUrl(this.value)) { if (isUrl(this.value)) {
window.open(this.value, '_blank') window.open(this.value, '_blank')
handled = true handled = true
} }
@ -3430,7 +3453,7 @@ Node.onDuplicate = nodes => {
const clone = node.clone() const clone = node.clone()
if (node.parent.type === 'object') { if (node.parent.type === 'object') {
const existingFieldNames = node.parent.getFieldNames() const existingFieldNames = node.parent.getFieldNames()
clone.field = util.findUniqueName(node.field, existingFieldNames) clone.field = findUniqueName(node.field, existingFieldNames)
} }
parent.insertAfter(clone, afterNode) parent.insertAfter(clone, afterNode)
afterNode = clone afterNode = clone
@ -3589,7 +3612,7 @@ Node.prototype._onChangeType = function (newType) {
*/ */
Node.prototype.sort = function (path, direction) { Node.prototype.sort = function (path, direction) {
if (typeof path === 'string') { if (typeof path === 'string') {
path = util.parsePath(path) path = parsePath(path)
} }
if (!this._hasChilds()) { if (!this._hasChilds()) {
@ -4330,7 +4353,7 @@ Node.prototype.showSortModal = function () {
function onSort (sortedBy) { function onSort (sortedBy) {
const path = sortedBy.path const path = sortedBy.path
const pathArray = util.parsePath(path) const pathArray = parsePath(path)
node.sortedBy = sortedBy node.sortedBy = sortedBy
node.sort(pathArray, sortedBy.direction) node.sort(pathArray, sortedBy.direction)
@ -4365,7 +4388,7 @@ Node.prototype._getType = value => {
if (value instanceof Object) { if (value instanceof Object) {
return 'object' return 'object'
} }
if (typeof (value) === 'string' && typeof (util.parseString(value)) !== 'string') { if (typeof (value) === 'string' && typeof (parseString(value)) !== 'string') {
return 'string' return 'string'
} }
@ -4393,7 +4416,7 @@ Node.prototype._escapeHTML = function (text) {
const json = JSON.stringify(htmlEscaped) const json = JSON.stringify(htmlEscaped)
let html = json.substring(1, json.length - 1) let html = json.substring(1, json.length - 1)
if (this.editor.options.escapeUnicode === true) { if (this.editor.options.escapeUnicode === true) {
html = util.escapeUnicodeChars(html) html = escapeUnicodeChars(html)
} }
return html return html
} }
@ -4407,7 +4430,7 @@ Node.prototype._escapeHTML = function (text) {
*/ */
Node.prototype._unescapeHTML = function (escapedText) { Node.prototype._unescapeHTML = function (escapedText) {
const json = '"' + this._escapeJSON(escapedText) + '"' const json = '"' + this._escapeJSON(escapedText) + '"'
const htmlEscaped = util.parse(json) const htmlEscaped = parse(json)
return htmlEscaped return htmlEscaped
.replace(/&lt;/g, '<') .replace(/&lt;/g, '<')
@ -4514,4 +4537,4 @@ function hasOwnProperty (object, key) {
var AppendNode = appendNodeFactory(Node) var AppendNode = appendNodeFactory(Node)
var ShowMoreNode = showMoreNodeFactory(Node) var ShowMoreNode = showMoreNodeFactory(Node)
module.exports = Node export default Node

View File

@ -1,14 +1,14 @@
'use strict' 'use strict'
const util = require('./util') import { ContextMenu } from './ContextMenu'
const ContextMenu = require('./ContextMenu').ContextMenu import { translate } from './i18n'
const translate = require('./i18n').translate import { addClassName, removeClassName } from './util'
/** /**
* A factory function to create an AppendNode, which depends on a Node * A factory function to create an AppendNode, which depends on a Node
* @param {Node} Node * @param {Node} Node
*/ */
function appendNodeFactory (Node) { export function appendNodeFactory (Node) {
/** /**
* @constructor AppendNode * @constructor AppendNode
* @extends Node * @extends Node
@ -234,9 +234,9 @@ function appendNodeFactory (Node) {
const highlighter = this.editor.highlighter const highlighter = this.editor.highlighter
highlighter.highlight(this.parent) highlighter.highlight(this.parent)
highlighter.lock() highlighter.lock()
util.addClassName(dom.menu, 'jsoneditor-selected') addClassName(dom.menu, 'jsoneditor-selected')
this.showContextMenu(dom.menu, () => { this.showContextMenu(dom.menu, () => {
util.removeClassName(dom.menu, 'jsoneditor-selected') removeClassName(dom.menu, 'jsoneditor-selected')
highlighter.unlock() highlighter.unlock()
highlighter.unhighlight() highlighter.unhighlight()
}) })
@ -249,5 +249,3 @@ function appendNodeFactory (Node) {
return AppendNode return AppendNode
} }
module.exports = appendNodeFactory

View File

@ -2,7 +2,7 @@
import jmespath from 'jmespath' import jmespath from 'jmespath'
import { translate } from './i18n' import { translate } from './i18n'
import ModeSwitcher from './ModeSwitcher' import { ModeSwitcher } from './ModeSwitcher'
import { ErrorTable } from './ErrorTable' import { ErrorTable } from './ErrorTable'
import { showSortModal } from './showSortModal' import { showSortModal } from './showSortModal'
import { showTransformModal } from './showTransformModal' import { showTransformModal } from './showTransformModal'

View File

@ -3,7 +3,7 @@
import ace from './ace' import ace from './ace'
import jmespath from 'jmespath' import jmespath from 'jmespath'
import { translate } from './i18n' import { translate } from './i18n'
import ModeSwitcher from './ModeSwitcher' import { ModeSwitcher } from './ModeSwitcher'
import { ErrorTable } from './ErrorTable' import { ErrorTable } from './ErrorTable'
import { validateCustom } from './validationUtils' import { validateCustom } from './validationUtils'
import { showSortModal } from './showSortModal' import { showSortModal } from './showSortModal'

View File

@ -7,7 +7,7 @@ import { SearchBox } from './SearchBox'
import { ContextMenu } from './ContextMenu' import { ContextMenu } from './ContextMenu'
import { TreePath } from './TreePath' import { TreePath } from './TreePath'
import Node from './Node' import Node from './Node'
import ModeSwitcher from './ModeSwitcher' import { ModeSwitcher } from './ModeSwitcher'
import { import {
addClassName, addClassName,
addEventListener, addEventListener,

View File

@ -341,7 +341,7 @@ export function clear (a) {
* @param {*} object * @param {*} object
* @return {String} type * @return {String} type
*/ */
export function type (object) { export function getType (object) {
if (object === null) { if (object === null) {
return 'null' return 'null'
} }

View File

@ -1,8 +1,6 @@
const assert = require('assert') import assert from 'assert'
const setUpTestEnvironment = require('./setup') import './setup'
setUpTestEnvironment() import Node from '../src/js/Node'
const Node = require('../src/js/Node')
describe('Node', () => { describe('Node', () => {
describe('_findSchema', () => { describe('_findSchema', () => {

View File

@ -1,6 +1,5 @@
const assert = require('assert') import assert from 'assert'
const stringifyPartial = require('../src/js/jsonUtils').stringifyPartial import { stringifyPartial, containsArray } from '../src/js/jsonUtils'
const containsArray = require('../src/js/jsonUtils').containsArray
describe('jsonUtils', () => { describe('jsonUtils', () => {
it('should stringify a small object', () => { it('should stringify a small object', () => {

View File

@ -1,11 +1,11 @@
const JSDOM = require('jsdom').JSDOM import { JSDOM } from 'jsdom'
/** /**
* Set up the test environment by simulating browser globals. * Set up the test environment by simulating browser globals.
* @param {string} [locale=en] A locale to set in navigator.language * @param {string} [locale=en] A locale to set in navigator.language
* @return {void} * @return {void}
*/ */
module.exports = function setUpTestEnvironment (locale) { function setUpTestEnvironment (locale) {
if (!locale) { if (!locale) {
locale = 'en' locale = 'en'
} }
@ -17,4 +17,6 @@ module.exports = function setUpTestEnvironment (locale) {
// JSDom has no setter defined for navigator.language, so defineProperty is necessary in order to override it // JSDom has no setter defined for navigator.language, so defineProperty is necessary in order to override it
Object.defineProperty(navigator, 'language', { value: locale }) Object.defineProperty(navigator, 'language', { value: locale })
} };
setUpTestEnvironment()

View File

@ -1,93 +1,109 @@
const assert = require('assert') import assert from 'assert'
const util = require('../src/js/util') import {
compileJSONPointer,
findUniqueName,
formatSize,
get,
getChildPaths,
getIndexForPosition,
isObject,
limitCharacters,
makeFieldTooltip,
parsePath,
parseString,
repair,
sort,
sortObjectKeys,
stringifyPath
} from '../src/js/util'
describe('util', () => { describe('util', () => {
describe('repair', () => { describe('repair', () => {
it('should leave valid JSON as is', () => { it('should leave valid JSON as is', () => {
assert.strictEqual(util.repair('{"a":2}'), '{"a":2}') assert.strictEqual(repair('{"a":2}'), '{"a":2}')
}) })
it('should replace JavaScript with JSON', () => { it('should replace JavaScript with JSON', () => {
assert.strictEqual(util.repair('{a:2}'), '{"a":2}') assert.strictEqual(repair('{a:2}'), '{"a":2}')
assert.strictEqual(util.repair('{a: 2}'), '{"a": 2}') assert.strictEqual(repair('{a: 2}'), '{"a": 2}')
assert.strictEqual(util.repair('{\n a: 2\n}'), '{\n "a": 2\n}') assert.strictEqual(repair('{\n a: 2\n}'), '{\n "a": 2\n}')
assert.strictEqual(util.repair('{\'a\':2}'), '{"a":2}') assert.strictEqual(repair('{\'a\':2}'), '{"a":2}')
assert.strictEqual(util.repair('{a:\'foo\'}'), '{"a":"foo"}') assert.strictEqual(repair('{a:\'foo\'}'), '{"a":"foo"}')
assert.strictEqual(util.repair('{a:\'foo\',b:\'bar\'}'), '{"a":"foo","b":"bar"}') assert.strictEqual(repair('{a:\'foo\',b:\'bar\'}'), '{"a":"foo","b":"bar"}')
// should leave string content untouched // should leave string content untouched
assert.strictEqual(util.repair('"{a:b}"'), '"{a:b}"') assert.strictEqual(repair('"{a:b}"'), '"{a:b}"')
}) })
it('should add/remove escape characters', () => { it('should add/remove escape characters', () => {
assert.strictEqual(util.repair('"foo\'bar"'), '"foo\'bar"') assert.strictEqual(repair('"foo\'bar"'), '"foo\'bar"')
assert.strictEqual(util.repair('"foo\\"bar"'), '"foo\\"bar"') assert.strictEqual(repair('"foo\\"bar"'), '"foo\\"bar"')
assert.strictEqual(util.repair('\'foo"bar\''), '"foo\\"bar"') assert.strictEqual(repair('\'foo"bar\''), '"foo\\"bar"')
assert.strictEqual(util.repair('\'foo\\\'bar\''), '"foo\'bar"') assert.strictEqual(repair('\'foo\\\'bar\''), '"foo\'bar"')
assert.strictEqual(util.repair('"foo\\\'bar"'), '"foo\'bar"') assert.strictEqual(repair('"foo\\\'bar"'), '"foo\'bar"')
}) })
it('should replace special white characters', () => { it('should replace special white characters', () => {
assert.strictEqual(util.repair('{"a":\u00a0"foo\u00a0bar"}'), '{"a": "foo\u00a0bar"}') assert.strictEqual(repair('{"a":\u00a0"foo\u00a0bar"}'), '{"a": "foo\u00a0bar"}')
assert.strictEqual(util.repair('{"a":\u2009"foo"}'), '{"a": "foo"}') assert.strictEqual(repair('{"a":\u2009"foo"}'), '{"a": "foo"}')
}) })
it('should escape unescaped control characters', () => { it('should escape unescaped control characters', () => {
assert.strictEqual(util.repair('"hello\bworld"'), '"hello\\bworld"') assert.strictEqual(repair('"hello\bworld"'), '"hello\\bworld"')
assert.strictEqual(util.repair('"hello\fworld"'), '"hello\\fworld"') assert.strictEqual(repair('"hello\fworld"'), '"hello\\fworld"')
assert.strictEqual(util.repair('"hello\nworld"'), '"hello\\nworld"') assert.strictEqual(repair('"hello\nworld"'), '"hello\\nworld"')
assert.strictEqual(util.repair('"hello\rworld"'), '"hello\\rworld"') assert.strictEqual(repair('"hello\rworld"'), '"hello\\rworld"')
assert.strictEqual(util.repair('"hello\tworld"'), '"hello\\tworld"') assert.strictEqual(repair('"hello\tworld"'), '"hello\\tworld"')
assert.strictEqual(util.repair('{"value\n": "dc=hcm,dc=com"}'), '{"value\\n": "dc=hcm,dc=com"}') assert.strictEqual(repair('{"value\n": "dc=hcm,dc=com"}'), '{"value\\n": "dc=hcm,dc=com"}')
}) })
it('should replace left/right quotes', () => { it('should replace left/right quotes', () => {
assert.strictEqual(util.repair('\u2018foo\u2019'), '"foo"') assert.strictEqual(repair('\u2018foo\u2019'), '"foo"')
assert.strictEqual(util.repair('\u201Cfoo\u201D'), '"foo"') assert.strictEqual(repair('\u201Cfoo\u201D'), '"foo"')
assert.strictEqual(util.repair('\u0060foo\u00B4'), '"foo"') assert.strictEqual(repair('\u0060foo\u00B4'), '"foo"')
}) })
it('remove comments', () => { it('remove comments', () => {
assert.strictEqual(util.repair('/* foo */ {}'), ' {}') assert.strictEqual(repair('/* foo */ {}'), ' {}')
assert.strictEqual(util.repair('/* foo */ {}'), ' {}') assert.strictEqual(repair('/* foo */ {}'), ' {}')
assert.strictEqual(util.repair('{a:\'foo\',/*hello*/b:\'bar\'}'), '{"a":"foo","b":"bar"}') assert.strictEqual(repair('{a:\'foo\',/*hello*/b:\'bar\'}'), '{"a":"foo","b":"bar"}')
assert.strictEqual(util.repair('{\na:\'foo\',//hello\nb:\'bar\'\n}'), '{\n"a":"foo",\n"b":"bar"\n}') assert.strictEqual(repair('{\na:\'foo\',//hello\nb:\'bar\'\n}'), '{\n"a":"foo",\n"b":"bar"\n}')
// should not remove comments in string // should not remove comments in string
assert.strictEqual(util.repair('{"str":"/* foo */"}'), '{"str":"/* foo */"}') assert.strictEqual(repair('{"str":"/* foo */"}'), '{"str":"/* foo */"}')
}) })
it('should strip JSONP notation', () => { it('should strip JSONP notation', () => {
// matching // matching
assert.strictEqual(util.repair('callback_123({});'), '{}') assert.strictEqual(repair('callback_123({});'), '{}')
assert.strictEqual(util.repair('callback_123([]);'), '[]') assert.strictEqual(repair('callback_123([]);'), '[]')
assert.strictEqual(util.repair('callback_123(2);'), '2') assert.strictEqual(repair('callback_123(2);'), '2')
assert.strictEqual(util.repair('callback_123("foo");'), '"foo"') assert.strictEqual(repair('callback_123("foo");'), '"foo"')
assert.strictEqual(util.repair('callback_123(null);'), 'null') assert.strictEqual(repair('callback_123(null);'), 'null')
assert.strictEqual(util.repair('callback_123(true);'), 'true') assert.strictEqual(repair('callback_123(true);'), 'true')
assert.strictEqual(util.repair('callback_123(false);'), 'false') assert.strictEqual(repair('callback_123(false);'), 'false')
assert.strictEqual(util.repair('/* foo bar */ callback_123 ({})'), '{}') assert.strictEqual(repair('/* foo bar */ callback_123 ({})'), '{}')
assert.strictEqual(util.repair('/* foo bar */ callback_123 ({})'), '{}') assert.strictEqual(repair('/* foo bar */ callback_123 ({})'), '{}')
assert.strictEqual(util.repair('/* foo bar */\ncallback_123({})'), '{}') assert.strictEqual(repair('/* foo bar */\ncallback_123({})'), '{}')
assert.strictEqual(util.repair('/* foo bar */ callback_123 ( {} )'), ' {} ') assert.strictEqual(repair('/* foo bar */ callback_123 ( {} )'), ' {} ')
assert.strictEqual(util.repair(' /* foo bar */ callback_123 ({}); '), '{}') assert.strictEqual(repair(' /* foo bar */ callback_123 ({}); '), '{}')
assert.strictEqual(util.repair('\n/* foo\nbar */\ncallback_123 ({});\n\n'), '{}') assert.strictEqual(repair('\n/* foo\nbar */\ncallback_123 ({});\n\n'), '{}')
// non-matching // non-matching
assert.strictEqual(util.repair('callback {}'), 'callback {}') assert.strictEqual(repair('callback {}'), 'callback {}')
assert.strictEqual(util.repair('callback({}'), 'callback({}') assert.strictEqual(repair('callback({}'), 'callback({}')
}) })
it('should strip trailing zeros', () => { it('should strip trailing zeros', () => {
// matching // matching
assert.strictEqual(util.repair('[1,2,3,]'), '[1,2,3]') assert.strictEqual(repair('[1,2,3,]'), '[1,2,3]')
assert.strictEqual(util.repair('[1,2,3,\n]'), '[1,2,3\n]') assert.strictEqual(repair('[1,2,3,\n]'), '[1,2,3\n]')
assert.strictEqual(util.repair('[1,2,3, \n ]'), '[1,2,3 \n ]') assert.strictEqual(repair('[1,2,3, \n ]'), '[1,2,3 \n ]')
assert.strictEqual(util.repair('{"a":2,}'), '{"a":2}') assert.strictEqual(repair('{"a":2,}'), '{"a":2}')
// not matching // not matching
assert.strictEqual(util.repair('"[1,2,3,]"'), '"[1,2,3,]"') assert.strictEqual(repair('"[1,2,3,]"'), '"[1,2,3,]"')
assert.strictEqual(util.repair('"{a:2,}"'), '"{a:2,}"') assert.strictEqual(repair('"{a:2,}"'), '"{a:2,}"')
}) })
it('should strip MongoDB data types', () => { it('should strip MongoDB data types', () => {
@ -115,45 +131,45 @@ describe('util', () => {
' "decimal2" : 4\n' + ' "decimal2" : 4\n' +
'}' '}'
assert.strictEqual(util.repair(mongoDocument), expectedJson) assert.strictEqual(repair(mongoDocument), expectedJson)
}) })
}) })
describe('jsonPath', () => { describe('jsonPath', () => {
it('should stringify an array of paths', () => { it('should stringify an array of paths', () => {
assert.deepStrictEqual(util.stringifyPath([]), '') assert.deepStrictEqual(stringifyPath([]), '')
assert.deepStrictEqual(util.stringifyPath(['foo']), '.foo') assert.deepStrictEqual(stringifyPath(['foo']), '.foo')
assert.deepStrictEqual(util.stringifyPath(['foo', 'bar']), '.foo.bar') assert.deepStrictEqual(stringifyPath(['foo', 'bar']), '.foo.bar')
assert.deepStrictEqual(util.stringifyPath(['foo', 2]), '.foo[2]') assert.deepStrictEqual(stringifyPath(['foo', 2]), '.foo[2]')
assert.deepStrictEqual(util.stringifyPath(['foo', 2, 'bar']), '.foo[2].bar') assert.deepStrictEqual(stringifyPath(['foo', 2, 'bar']), '.foo[2].bar')
assert.deepStrictEqual(util.stringifyPath(['foo', 2, 'bar_baz']), '.foo[2].bar_baz') assert.deepStrictEqual(stringifyPath(['foo', 2, 'bar_baz']), '.foo[2].bar_baz')
assert.deepStrictEqual(util.stringifyPath([2]), '[2]') assert.deepStrictEqual(stringifyPath([2]), '[2]')
assert.deepStrictEqual(util.stringifyPath(['foo', 'prop-with-hyphens']), '.foo["prop-with-hyphens"]') assert.deepStrictEqual(stringifyPath(['foo', 'prop-with-hyphens']), '.foo["prop-with-hyphens"]')
assert.deepStrictEqual(util.stringifyPath(['foo', 'prop with spaces']), '.foo["prop with spaces"]') assert.deepStrictEqual(stringifyPath(['foo', 'prop with spaces']), '.foo["prop with spaces"]')
}) })
it('should parse a json path', () => { it('should parse a json path', () => {
assert.deepStrictEqual(util.parsePath(''), []) assert.deepStrictEqual(parsePath(''), [])
assert.deepStrictEqual(util.parsePath('.foo'), ['foo']) assert.deepStrictEqual(parsePath('.foo'), ['foo'])
assert.deepStrictEqual(util.parsePath('.foo.bar'), ['foo', 'bar']) assert.deepStrictEqual(parsePath('.foo.bar'), ['foo', 'bar'])
assert.deepStrictEqual(util.parsePath('.foo[2]'), ['foo', 2]) assert.deepStrictEqual(parsePath('.foo[2]'), ['foo', 2])
assert.deepStrictEqual(util.parsePath('.foo[2].bar'), ['foo', 2, 'bar']) assert.deepStrictEqual(parsePath('.foo[2].bar'), ['foo', 2, 'bar'])
assert.deepStrictEqual(util.parsePath('.foo["prop with spaces"]'), ['foo', 'prop with spaces']) assert.deepStrictEqual(parsePath('.foo["prop with spaces"]'), ['foo', 'prop with spaces'])
assert.deepStrictEqual(util.parsePath('.foo[\'prop with single quotes as outputted by ajv library\']'), ['foo', 'prop with single quotes as outputted by ajv library']) assert.deepStrictEqual(parsePath('.foo[\'prop with single quotes as outputted by ajv library\']'), ['foo', 'prop with single quotes as outputted by ajv library'])
assert.deepStrictEqual(util.parsePath('.foo["prop with . dot"]'), ['foo', 'prop with . dot']) assert.deepStrictEqual(parsePath('.foo["prop with . dot"]'), ['foo', 'prop with . dot'])
assert.deepStrictEqual(util.parsePath('.foo["prop with ] character"]'), ['foo', 'prop with ] character']) assert.deepStrictEqual(parsePath('.foo["prop with ] character"]'), ['foo', 'prop with ] character'])
assert.deepStrictEqual(util.parsePath('.foo[*].bar'), ['foo', '*', 'bar']) assert.deepStrictEqual(parsePath('.foo[*].bar'), ['foo', '*', 'bar'])
assert.deepStrictEqual(util.parsePath('[2]'), [2]) assert.deepStrictEqual(parsePath('[2]'), [2])
}) })
it('should throw an exception in case of an invalid path', () => { it('should throw an exception in case of an invalid path', () => {
assert.throws(() => { util.parsePath('.') }, /Invalid JSON path: property name expected at index 1/) assert.throws(() => { parsePath('.') }, /Invalid JSON path: property name expected at index 1/)
assert.throws(() => { util.parsePath('[') }, /Invalid JSON path: unexpected end, character ] expected/) assert.throws(() => { parsePath('[') }, /Invalid JSON path: unexpected end, character ] expected/)
assert.throws(() => { util.parsePath('[]') }, /Invalid JSON path: array value expected at index 1/) assert.throws(() => { parsePath('[]') }, /Invalid JSON path: array value expected at index 1/)
assert.throws(() => { util.parsePath('.foo[ ]') }, /Invalid JSON path: array value expected at index 7/) assert.throws(() => { parsePath('.foo[ ]') }, /Invalid JSON path: array value expected at index 7/)
assert.throws(() => { util.parsePath('.[]') }, /Invalid JSON path: property name expected at index 1/) assert.throws(() => { parsePath('.[]') }, /Invalid JSON path: property name expected at index 1/)
assert.throws(() => { util.parsePath('["23]') }, /Invalid JSON path: unexpected end, character " expected/) assert.throws(() => { parsePath('["23]') }, /Invalid JSON path: unexpected end, character " expected/)
assert.throws(() => { util.parsePath('.foo bar') }, /Invalid JSON path: unexpected character " " at index 4/) assert.throws(() => { parsePath('.foo bar') }, /Invalid JSON path: unexpected character " " at index 4/)
}) })
}) })
@ -163,23 +179,23 @@ describe('util', () => {
} }
it('happy flows - row and column in range', () => { it('happy flows - row and column in range', () => {
assert.strictEqual(util.getIndexForPosition(el, 1, 1), 0) assert.strictEqual(getIndexForPosition(el, 1, 1), 0)
assert.strictEqual(util.getIndexForPosition(el, 2, 1), 124) assert.strictEqual(getIndexForPosition(el, 2, 1), 124)
assert.strictEqual(util.getIndexForPosition(el, 3, 8), 239) assert.strictEqual(getIndexForPosition(el, 3, 8), 239)
assert.strictEqual(util.getIndexForPosition(el, 4, 22), 356) assert.strictEqual(getIndexForPosition(el, 4, 22), 356)
}) })
it('if range exceeds it should be considered as if it is last row or column length', () => { it('if range exceeds it should be considered as if it is last row or column length', () => {
assert.strictEqual(util.getIndexForPosition(el, 1, 100000), 123) assert.strictEqual(getIndexForPosition(el, 1, 100000), 123)
assert.strictEqual(util.getIndexForPosition(el, 100000, 1), 335) assert.strictEqual(getIndexForPosition(el, 100000, 1), 335)
assert.strictEqual(util.getIndexForPosition(el, 100000, 100000), 445) assert.strictEqual(getIndexForPosition(el, 100000, 100000), 445)
}) })
it('missing or wrong input sould return -1', () => { it('missing or wrong input sould return -1', () => {
assert.strictEqual(util.getIndexForPosition(el), -1) assert.strictEqual(getIndexForPosition(el), -1)
assert.strictEqual(util.getIndexForPosition(el, undefined, 1), -1) assert.strictEqual(getIndexForPosition(el, undefined, 1), -1)
assert.strictEqual(util.getIndexForPosition(el, 1, undefined), -1) assert.strictEqual(getIndexForPosition(el, 1, undefined), -1)
assert.strictEqual(util.getIndexForPosition(el, -2, -2), -1) assert.strictEqual(getIndexForPosition(el, -2, -2), -1)
}) })
}) })
@ -194,80 +210,80 @@ describe('util', () => {
e: undefined e: undefined
} }
assert.strictEqual(util.get(obj, ['a', 'b']), 2) assert.strictEqual(get(obj, ['a', 'b']), 2)
assert.strictEqual(util.get(obj, ['c']), 3) assert.strictEqual(get(obj, ['c']), 3)
assert.deepStrictEqual(util.get(obj, ['a']), { b: 2 }) assert.deepStrictEqual(get(obj, ['a']), { b: 2 })
assert.strictEqual(util.get(obj, ['a', 'foo']), undefined) assert.strictEqual(get(obj, ['a', 'foo']), undefined)
assert.strictEqual(util.get(obj, ['a', 'foo', 'bar']), undefined) assert.strictEqual(get(obj, ['a', 'foo', 'bar']), undefined)
assert.strictEqual(util.get(obj, ['d']), null) assert.strictEqual(get(obj, ['d']), null)
assert.strictEqual(util.get(obj, ['d', 'foo', 'bar']), null) assert.strictEqual(get(obj, ['d', 'foo', 'bar']), null)
assert.strictEqual(util.get(obj, ['e']), undefined) assert.strictEqual(get(obj, ['e']), undefined)
}) })
}) })
describe('makeFieldTooltip', () => { describe('makeFieldTooltip', () => {
it('should return empty string when the schema is missing all relevant fields', () => { it('should return empty string when the schema is missing all relevant fields', () => {
assert.strictEqual(util.makeFieldTooltip({}), '') assert.strictEqual(makeFieldTooltip({}), '')
assert.strictEqual(util.makeFieldTooltip({ additionalProperties: false }), '') assert.strictEqual(makeFieldTooltip({ additionalProperties: false }), '')
assert.strictEqual(util.makeFieldTooltip(), '') assert.strictEqual(makeFieldTooltip(), '')
}) })
it('should make tooltips with only title', () => { it('should make tooltips with only title', () => {
assert.strictEqual(util.makeFieldTooltip({ title: 'foo' }), 'foo') assert.strictEqual(makeFieldTooltip({ title: 'foo' }), 'foo')
}) })
it('should make tooltips with only description', () => { it('should make tooltips with only description', () => {
assert.strictEqual(util.makeFieldTooltip({ description: 'foo' }), 'foo') assert.strictEqual(makeFieldTooltip({ description: 'foo' }), 'foo')
}) })
it('should make tooltips with only default', () => { it('should make tooltips with only default', () => {
assert.strictEqual(util.makeFieldTooltip({ default: 'foo' }), 'Default\n"foo"') assert.strictEqual(makeFieldTooltip({ default: 'foo' }), 'Default\n"foo"')
}) })
it('should make tooltips with only examples', () => { it('should make tooltips with only examples', () => {
assert.strictEqual(util.makeFieldTooltip({ examples: ['foo', 'bar'] }), 'Examples\n"foo"\n"bar"') assert.strictEqual(makeFieldTooltip({ examples: ['foo', 'bar'] }), 'Examples\n"foo"\n"bar"')
}) })
it('should make tooltips with title and description', () => { it('should make tooltips with title and description', () => {
assert.strictEqual(util.makeFieldTooltip({ title: 'foo', description: 'bar' }), 'foo\nbar') assert.strictEqual(makeFieldTooltip({ title: 'foo', description: 'bar' }), 'foo\nbar')
const longTitle = 'Lorem Ipsum Dolor' const longTitle = 'Lorem Ipsum Dolor'
const longDescription = 'Duis id elit non ante gravida vestibulum non nec est. ' + const longDescription = 'Duis id elit non ante gravida vestibulum non nec est. ' +
'Proin vitae ligula at elit dapibus tempor. ' + 'Proin vitae ligula at elit dapibus tempor. ' +
'Etiam lacinia augue vel condimentum interdum. ' 'Etiam lacinia augue vel condimentum interdum. '
assert.strictEqual( assert.strictEqual(
util.makeFieldTooltip({ title: longTitle, description: longDescription }), makeFieldTooltip({ title: longTitle, description: longDescription }),
longTitle + '\n' + longDescription longTitle + '\n' + longDescription
) )
}) })
it('should make tooltips with title, description, and examples', () => { it('should make tooltips with title, description, and examples', () => {
assert.strictEqual( assert.strictEqual(
util.makeFieldTooltip({ title: 'foo', description: 'bar', examples: ['baz'] }), makeFieldTooltip({ title: 'foo', description: 'bar', examples: ['baz'] }),
'foo\nbar\n\nExamples\n"baz"' 'foo\nbar\n\nExamples\n"baz"'
) )
}) })
it('should make tooltips with title, description, default, and examples', () => { it('should make tooltips with title, description, default, and examples', () => {
assert.strictEqual( assert.strictEqual(
util.makeFieldTooltip({ title: 'foo', description: 'bar', default: 'bat', examples: ['baz'] }), makeFieldTooltip({ title: 'foo', description: 'bar', default: 'bat', examples: ['baz'] }),
'foo\nbar\n\nDefault\n"bat"\n\nExamples\n"baz"' 'foo\nbar\n\nDefault\n"bat"\n\nExamples\n"baz"'
) )
}) })
it('should handle empty fields', () => { it('should handle empty fields', () => {
assert.strictEqual(util.makeFieldTooltip({ title: '', description: 'bar' }), 'bar') assert.strictEqual(makeFieldTooltip({ title: '', description: 'bar' }), 'bar')
assert.strictEqual(util.makeFieldTooltip({ title: 'foo', description: '' }), 'foo') assert.strictEqual(makeFieldTooltip({ title: 'foo', description: '' }), 'foo')
assert.strictEqual(util.makeFieldTooltip({ description: 'bar', examples: [] }), 'bar') assert.strictEqual(makeFieldTooltip({ description: 'bar', examples: [] }), 'bar')
assert.strictEqual(util.makeFieldTooltip({ description: 'bar', examples: [''] }), 'bar\n\nExamples\n""') assert.strictEqual(makeFieldTooltip({ description: 'bar', examples: [''] }), 'bar\n\nExamples\n""')
}) })
it('should internationalize "Defaults" correctly', () => { it('should internationalize "Defaults" correctly', () => {
assert.strictEqual(util.makeFieldTooltip({ default: 'foo' }, 'pt-BR'), 'Revelia\n"foo"') assert.strictEqual(makeFieldTooltip({ default: 'foo' }, 'pt-BR'), 'Revelia\n"foo"')
}) })
it('should internationalize "Examples" correctly', () => { it('should internationalize "Examples" correctly', () => {
assert.strictEqual(util.makeFieldTooltip({ examples: ['foo'] }, 'pt-BR'), 'Exemplos\n"foo"') assert.strictEqual(makeFieldTooltip({ examples: ['foo'] }, 'pt-BR'), 'Exemplos\n"foo"')
}) })
}) })
@ -279,7 +295,7 @@ describe('util', () => {
{ name: 'C', timestamp: 0 } { name: 'C', timestamp: 0 }
] ]
assert.deepStrictEqual(util.getChildPaths(json), [ assert.deepStrictEqual(getChildPaths(json), [
'.location.latitude', '.location.latitude',
'.location.longitude', '.location.longitude',
'.name', '.name',
@ -294,7 +310,7 @@ describe('util', () => {
{ name: 'C', timestamp: 0 } { name: 'C', timestamp: 0 }
] ]
assert.deepStrictEqual(util.getChildPaths(json, true), [ assert.deepStrictEqual(getChildPaths(json, true), [
'', '',
'.location', '.location',
'.location.latitude', '.location.latitude',
@ -307,33 +323,33 @@ describe('util', () => {
it('should extract all child paths of an array containing values', () => { it('should extract all child paths of an array containing values', () => {
const json = [1, 2, 3] const json = [1, 2, 3]
assert.deepStrictEqual(util.getChildPaths(json), [ assert.deepStrictEqual(getChildPaths(json), [
'' ''
]) ])
}) })
it('should extract all child paths of a non-array', () => { it('should extract all child paths of a non-array', () => {
assert.deepStrictEqual(util.getChildPaths({ a: 2, b: { c: 3 } }), ['']) assert.deepStrictEqual(getChildPaths({ a: 2, b: { c: 3 } }), [''])
assert.deepStrictEqual(util.getChildPaths('foo'), ['']) assert.deepStrictEqual(getChildPaths('foo'), [''])
assert.deepStrictEqual(util.getChildPaths(123), ['']) assert.deepStrictEqual(getChildPaths(123), [''])
}) })
}) })
it('should test whether something is an object', () => { it('should test whether something is an object', () => {
assert.strictEqual(util.isObject({}), true) assert.strictEqual(isObject({}), true)
assert.strictEqual(util.isObject(new Date()), true) assert.strictEqual(isObject(new Date()), true)
assert.strictEqual(util.isObject([]), false) assert.strictEqual(isObject([]), false)
assert.strictEqual(util.isObject(2), false) assert.strictEqual(isObject(2), false)
assert.strictEqual(util.isObject(null), false) assert.strictEqual(isObject(null), false)
assert.strictEqual(util.isObject(undefined), false) assert.strictEqual(isObject(undefined), false)
assert.strictEqual(util.isObject(), false) assert.strictEqual(isObject(), false)
}) })
describe('sort', () => { describe('sort', () => {
it('should sort an array', () => { it('should sort an array', () => {
const array = [4, 1, 10, 2] const array = [4, 1, 10, 2]
assert.deepStrictEqual(util.sort(array), [1, 2, 4, 10]) assert.deepStrictEqual(sort(array), [1, 2, 4, 10])
assert.deepStrictEqual(util.sort(array, '.', 'desc'), [10, 4, 2, 1]) assert.deepStrictEqual(sort(array, '.', 'desc'), [10, 4, 2, 1])
}) })
it('should sort an array containing objects', () => { it('should sort an array containing objects', () => {
@ -344,14 +360,14 @@ describe('util', () => {
{ value: 2 } { value: 2 }
] ]
assert.deepStrictEqual(util.sort(array, '.value'), [ assert.deepStrictEqual(sort(array, '.value'), [
{ value: 1 }, { value: 1 },
{ value: 2 }, { value: 2 },
{ value: 4 }, { value: 4 },
{ value: 10 } { value: 10 }
]) ])
assert.deepStrictEqual(util.sort(array, '.value', 'desc'), [ assert.deepStrictEqual(sort(array, '.value', 'desc'), [
{ value: 10 }, { value: 10 },
{ value: 4 }, { value: 4 },
{ value: 2 }, { value: 2 },
@ -368,42 +384,42 @@ describe('util', () => {
b: 'b' b: 'b'
} }
assert.strictEqual(JSON.stringify(object), '{"c":"c","a":"a","b":"b"}') assert.strictEqual(JSON.stringify(object), '{"c":"c","a":"a","b":"b"}')
assert.strictEqual(JSON.stringify(util.sortObjectKeys(object)), '{"a":"a","b":"b","c":"c"}') assert.strictEqual(JSON.stringify(sortObjectKeys(object)), '{"a":"a","b":"b","c":"c"}')
assert.strictEqual(JSON.stringify(util.sortObjectKeys(object, 'asc')), '{"a":"a","b":"b","c":"c"}') assert.strictEqual(JSON.stringify(sortObjectKeys(object, 'asc')), '{"a":"a","b":"b","c":"c"}')
assert.strictEqual(JSON.stringify(util.sortObjectKeys(object, 'desc')), '{"c":"c","b":"b","a":"a"}') assert.strictEqual(JSON.stringify(sortObjectKeys(object, 'desc')), '{"c":"c","b":"b","a":"a"}')
}) })
}) })
it('should parse a string', () => { it('should parse a string', () => {
assert.strictEqual(util.parseString('foo'), 'foo') assert.strictEqual(parseString('foo'), 'foo')
assert.strictEqual(util.parseString('234foo'), '234foo') assert.strictEqual(parseString('234foo'), '234foo')
assert.strictEqual(util.parseString('2.3'), 2.3) assert.strictEqual(parseString('2.3'), 2.3)
assert.strictEqual(util.parseString('null'), null) assert.strictEqual(parseString('null'), null)
assert.strictEqual(util.parseString('true'), true) assert.strictEqual(parseString('true'), true)
assert.strictEqual(util.parseString('false'), false) assert.strictEqual(parseString('false'), false)
}) })
it('should find a unique name', () => { it('should find a unique name', () => {
assert.strictEqual(util.findUniqueName('other', [ assert.strictEqual(findUniqueName('other', [
'a', 'a',
'b', 'b',
'c' 'c'
]), 'other') ]), 'other')
assert.strictEqual(util.findUniqueName('b', [ assert.strictEqual(findUniqueName('b', [
'a', 'a',
'b', 'b',
'c' 'c'
]), 'b (copy)') ]), 'b (copy)')
assert.strictEqual(util.findUniqueName('b', [ assert.strictEqual(findUniqueName('b', [
'a', 'a',
'b', 'b',
'c', 'c',
'b (copy)' 'b (copy)'
]), 'b (copy 2)') ]), 'b (copy 2)')
assert.strictEqual(util.findUniqueName('b', [ assert.strictEqual(findUniqueName('b', [
'a', 'a',
'b', 'b',
'c', 'c',
@ -411,7 +427,7 @@ describe('util', () => {
'b (copy 2)' 'b (copy 2)'
]), 'b (copy 3)') ]), 'b (copy 3)')
assert.strictEqual(util.findUniqueName('b (copy)', [ assert.strictEqual(findUniqueName('b (copy)', [
'a', 'a',
'b', 'b',
'b (copy)', 'b (copy)',
@ -419,7 +435,7 @@ describe('util', () => {
'c' 'c'
]), 'b (copy 3)') ]), 'b (copy 3)')
assert.strictEqual(util.findUniqueName('b (copy 2)', [ assert.strictEqual(findUniqueName('b (copy 2)', [
'a', 'a',
'b', 'b',
'b (copy)', 'b (copy)',
@ -429,27 +445,27 @@ describe('util', () => {
}) })
it('should format a document size in a human readable way', () => { it('should format a document size in a human readable way', () => {
assert.strictEqual(util.formatSize(500), '500 B') assert.strictEqual(formatSize(500), '500 B')
assert.strictEqual(util.formatSize(900), '0.9 KiB') assert.strictEqual(formatSize(900), '0.9 KiB')
assert.strictEqual(util.formatSize(77.89 * 1024), '77.9 KiB') assert.strictEqual(formatSize(77.89 * 1024), '77.9 KiB')
assert.strictEqual(util.formatSize(950 * 1024), '0.9 MiB') assert.strictEqual(formatSize(950 * 1024), '0.9 MiB')
assert.strictEqual(util.formatSize(7.22 * 1024 * 1024), '7.2 MiB') assert.strictEqual(formatSize(7.22 * 1024 * 1024), '7.2 MiB')
assert.strictEqual(util.formatSize(955.4 * 1024 * 1024), '0.9 GiB') assert.strictEqual(formatSize(955.4 * 1024 * 1024), '0.9 GiB')
assert.strictEqual(util.formatSize(22.37 * 1024 * 1024 * 1024), '22.4 GiB') assert.strictEqual(formatSize(22.37 * 1024 * 1024 * 1024), '22.4 GiB')
assert.strictEqual(util.formatSize(1024 * 1024 * 1024 * 1024), '1.0 TiB') assert.strictEqual(formatSize(1024 * 1024 * 1024 * 1024), '1.0 TiB')
}) })
it('should limit characters', () => { it('should limit characters', () => {
assert.strictEqual(util.limitCharacters('hello world', 11), 'hello world') assert.strictEqual(limitCharacters('hello world', 11), 'hello world')
assert.strictEqual(util.limitCharacters('hello world', 5), 'hello...') assert.strictEqual(limitCharacters('hello world', 5), 'hello...')
assert.strictEqual(util.limitCharacters('hello world', 100), 'hello world') assert.strictEqual(limitCharacters('hello world', 100), 'hello world')
}) })
it('should compile a JSON pointer', () => { it('should compile a JSON pointer', () => {
assert.strictEqual(util.compileJSONPointer(['foo', 'bar']), '/foo/bar') assert.strictEqual(compileJSONPointer(['foo', 'bar']), '/foo/bar')
assert.strictEqual(util.compileJSONPointer(['foo', '/~ ~/']), '/foo/~1~0 ~0~1') assert.strictEqual(compileJSONPointer(['foo', '/~ ~/']), '/foo/~1~0 ~0~1')
assert.strictEqual(util.compileJSONPointer(['']), '/') assert.strictEqual(compileJSONPointer(['']), '/')
assert.strictEqual(util.compileJSONPointer([]), '') assert.strictEqual(compileJSONPointer([]), '')
}) })
// TODO: thoroughly test all util methods // TODO: thoroughly test all util methods