Skip to content

Commit

Permalink
Start removing wildcard combined with others
Browse files Browse the repository at this point in the history
  • Loading branch information
ehmicky committed Mar 6, 2022
1 parent be2e369 commit a072b87
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 62 deletions.
24 changes: 3 additions & 21 deletions src/config/normalize/lib/star_dot_path/parsing/normalize.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,8 @@
import { ANY_TOKEN } from './special.js'

// Normalize a path of tokens
export const normalizePath = function (path) {
return path.map(normalizeNode)
}

// Nodes can be both arrays and not arrays (if they have a single element) but
// we encourage the latter since it is simpler
const normalizeNode = function (node) {
const nodeA = node.length === 1 ? node[0] : node
validateComplexNode(nodeA)
return nodeA
}

const validateComplexNode = function (node) {
if (Array.isArray(node)) {
node.forEach(validateComplexToken)
}
return path.map(normalizeToken)
}

const validateComplexToken = function (token) {
if (typeof token === 'symbol' && token !== ANY_TOKEN) {
throw new TypeError(`${String(token)} must not be in a nested array.`)
}
const normalizeToken = function (token) {
return token
}
83 changes: 42 additions & 41 deletions src/config/normalize/lib/star_dot_path/parsing/parse.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { normalizePath } from './normalize.js'
import { convertIndexInteger } from './path.js'
import { ESCAPE, SEPARATOR, ANY, ANY_TOKEN } from './special.js'
import { ESCAPE, SEPARATOR, ANY, SPECIAL_CHARS, ANY_TOKEN } from './special.js'

// Parse a query string into an array of nodes.
// Parse a query string into an array of tokens.
// This is inspired by JSON paths and JSON pointers.
// Syntax:
// - Dots are used for object properties, e.g. `one.two`
Expand Down Expand Up @@ -42,66 +42,67 @@ export const parse = function (query) {

// Use imperative logic for performance
/* eslint-disable complexity, max-depth, max-statements, fp/no-loops,
fp/no-mutation, fp/no-let, no-continue, fp/no-mutating-methods */
fp/no-mutation, fp/no-mutating-methods, fp/no-let */
const parseQuery = function (query) {
if (query === '') {
return []
}

const path = []
let node = []
let token = ''
let chars = ''
let hasAny = false
let index = query[0] === SEPARATOR ? 1 : 0

for (; index <= query.length; index += 1) {
const character = query[index]
const char = query[index]

if (character === ESCAPE) {
if (char === ESCAPE) {
chars += getEscapedChar(query, index)
index += 1
const escapedCharacter = query[index]
validateEscape(escapedCharacter, query, character, index)
token += escapedCharacter
continue
} else if (char === SEPARATOR || index === query.length) {
path.push(getToken(chars, query, hasAny))
chars = ''
hasAny = false
} else {
hasAny = hasAny || char === ANY
chars += char
}
}

if (character === SEPARATOR || index === query.length) {
if (token !== '' || node.length === 0) {
node.push(convertIndexInteger(token))
token = ''
}

path.push(node)
node = []
continue
}
return path
}
/* eslint-enable complexity, max-depth, max-statements, fp/no-loops,
fp/no-mutation, fp/no-mutating-methods, fp/no-let */

if (character === ANY) {
if (token !== '') {
node.push(token)
token = ''
}
const getEscapedChar = function (query, index) {
const escapedChar = query[index + 1]
validateEscape(escapedChar, query, index)
return escapedChar
}

node.push(ANY_TOKEN)
continue
}
const validateEscape = function (escapedChar, query, index) {
if (!SPECIAL_CHARS.has(escapedChar)) {
throw new Error(
`Invalid query "${query}": character ${ESCAPE} at index ${index} must be followed by ${SEPARATOR} ${ANY} or ${ESCAPE}`,
)
}
}

token += character
const getToken = function (chars, query, hasAny) {
if (hasAny) {
return getAnyToken(chars, query)
}

return path
return convertIndexInteger(chars)
}
/* eslint-enable complexity, max-depth, max-statements, fp/no-loops,
fp/no-mutation, fp/no-let, no-continue, fp/no-mutating-methods */

// eslint-disable-next-line max-params
const validateEscape = function (escapedCharacter, query, character, index) {
if (
escapedCharacter !== ESCAPE &&
escapedCharacter !== SEPARATOR &&
escapedCharacter !== ANY
) {
const getAnyToken = function (chars, query) {
if (chars !== ANY) {
throw new Error(
`Invalid query "${query}": character ${character} at index ${index} must be followed by ${SEPARATOR}, ${ANY} or ${ESCAPE}`,
`Invalid query "${query}": character ${ANY} must not be preceded or followed by other characters except "${SEPARATOR}"
Regular expressions can be used instead.`,
)
}

return ANY_TOKEN
}
1 change: 1 addition & 0 deletions src/config/normalize/lib/star_dot_path/parsing/special.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
export const ESCAPE = '\\'
export const SEPARATOR = '.'
export const ANY = '*'
export const SPECIAL_CHARS = new Set([ESCAPE, SEPARATOR, ANY])
// Tokens for special characters
export const ANY_TOKEN = Symbol.for('*')
// Matches any special characters
Expand Down

0 comments on commit a072b87

Please sign in to comment.