configorama 0.6.11 → 0.6.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +196 -24
- package/cli.js +3 -3
- package/package.json +1 -1
- package/src/index.js +22 -32
- package/src/main.js +775 -857
- package/src/parsers/yaml.js +3 -47
- package/src/resolvers/valueFromCron.js +3 -1
- package/src/resolvers/valueFromEnv.js +1 -0
- package/src/resolvers/valueFromEval.js +1 -0
- package/src/resolvers/valueFromFile.js +394 -0
- package/src/resolvers/valueFromGit.js +3 -2
- package/src/resolvers/valueFromOptions.js +1 -0
- package/src/resolvers/valueFromString.js +2 -1
- package/src/sync.js +12 -5
- package/src/utils/parsing/arrayToJsonPath.test.js +56 -0
- package/src/utils/{enrichMetadata.js → parsing/enrichMetadata.js} +244 -94
- package/src/utils/{parse.js → parsing/parse.js} +13 -13
- package/src/utils/parsing/preProcess.js +165 -0
- package/src/utils/paths/filePathUtils.js +136 -0
- package/src/utils/paths/filePathUtils.test.js +214 -0
- package/src/utils/paths/findLineForKey.js +47 -0
- package/src/utils/paths/findLineForKey.test.js +126 -0
- package/src/utils/{getFullFilePath.js → paths/getFullFilePath.js} +22 -26
- package/src/utils/{resolveAlias.js → paths/resolveAlias.js} +1 -1
- package/src/utils/regex/index.js +23 -1
- package/src/utils/resolution/preResolveVariable.js +260 -0
- package/src/utils/resolution/preResolveVariable.test.js +98 -0
- package/src/utils/strings/bracketMatcher.js +86 -0
- package/src/utils/strings/bracketMatcher.test.js +135 -0
- package/src/utils/{formatFunctionArgs.js → strings/formatFunctionArgs.js} +3 -2
- package/src/utils/strings/formatFunctionArgs.test.js +77 -0
- package/src/utils/strings/quoteUtils.js +89 -0
- package/src/utils/strings/quoteUtils.test.js +217 -0
- package/src/utils/strings/replaceAll.test.js +82 -0
- package/src/utils/{splitByComma.js → strings/splitByComma.js} +1 -1
- package/src/utils/strings/splitCsv.js +38 -0
- package/src/utils/strings/splitCsv.test.js +96 -0
- package/src/utils/strings/textUtils.test.js +86 -0
- package/src/utils/{configWizard.js → ui/configWizard.js} +212 -60
- package/src/utils/{createEditorLink.js → ui/createEditorLink.js} +11 -2
- package/src/utils/{logs.js → ui/logs.js} +3 -3
- package/src/utils/validation/isValidValue.test.js +64 -0
- package/src/utils/validation/warnIfNotFound.js +52 -0
- package/src/utils/variables/appendDeepVariable.test.js +41 -0
- package/src/utils/{cleanVariable.js → variables/cleanVariable.js} +5 -26
- package/src/utils/{find-nested-variables.js → variables/findNestedVariables.js} +2 -2
- package/src/utils/{find-nested-variables.test.js → variables/findNestedVariables.test.js} +5 -5
- package/src/utils/variables/getVariableType.test.js +109 -0
- package/src/utils/variables/variableUtils.test.js +117 -0
- package/src/utils/isValidValue.js +0 -8
- package/src/utils/splitCsv.js +0 -29
- package/src/utils/trimSurroundingQuotes.js +0 -5
- /package/src/utils/{arrayToJsonPath.js → parsing/arrayToJsonPath.js} +0 -0
- /package/src/utils/{cloudformationSchema.js → parsing/cloudformationSchema.js} +0 -0
- /package/src/utils/{mergeByKeys.js → parsing/mergeByKeys.js} +0 -0
- /package/src/utils/{find-project-root.js → paths/findProjectRoot.js} +0 -0
- /package/src/utils/{resolveAlias.test.js → paths/resolveAlias.test.js} +0 -0
- /package/src/utils/{replaceAll.js → strings/replaceAll.js} +0 -0
- /package/src/utils/{splitByComma.test.js → strings/splitByComma.test.js} +0 -0
- /package/src/utils/{textUtils.js → strings/textUtils.js} +0 -0
- /package/src/utils/{chalk.js → ui/chalk.js} +0 -0
- /package/src/utils/{deep-log.js → ui/deep-log.js} +0 -0
- /package/src/utils/{appendDeepVariable.js → variables/appendDeepVariable.js} +0 -0
- /package/src/utils/{cleanVariable.test.js → variables/cleanVariable.test.js} +0 -0
- /package/src/utils/{getVariableType.js → variables/getVariableType.js} +0 -0
- /package/src/utils/{variableUtils.js → variables/variableUtils.js} +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
const { trim } = require('
|
|
1
|
+
const { trim } = require('../lodash')
|
|
2
|
+
const { trimSurroundingQuotes } = require('./quoteUtils')
|
|
2
3
|
|
|
3
4
|
function formatArg(arg) {
|
|
4
|
-
const cleanArg = trim(arg)
|
|
5
|
+
const cleanArg = trimSurroundingQuotes(trim(arg), false)
|
|
5
6
|
if (cleanArg.match(/^{([^}]+)}$/)) {
|
|
6
7
|
return JSON.parse(cleanArg)
|
|
7
8
|
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const { test } = require('uvu')
|
|
2
|
+
const assert = require('uvu/assert')
|
|
3
|
+
const formatFunctionArgs = require('./formatFunctionArgs')
|
|
4
|
+
|
|
5
|
+
test('formatFunctionArgs - should handle single string argument', () => {
|
|
6
|
+
const result = formatFunctionArgs('simpleString')
|
|
7
|
+
assert.equal(result, 'simpleString')
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
test('formatFunctionArgs - should trim and remove quotes from string', () => {
|
|
11
|
+
const result = formatFunctionArgs(' "quoted" ')
|
|
12
|
+
assert.equal(result, 'quoted')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test('formatFunctionArgs - should parse JSON object', () => {
|
|
16
|
+
const result = formatFunctionArgs('{"key":"value"}')
|
|
17
|
+
assert.is(typeof result, 'object')
|
|
18
|
+
assert.equal(result.key, 'value')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('formatFunctionArgs - should parse JSON array', () => {
|
|
22
|
+
const result = formatFunctionArgs('[1,2,3]')
|
|
23
|
+
assert.is(Array.isArray(result), true)
|
|
24
|
+
assert.equal(result, [1, 2, 3])
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('formatFunctionArgs - should handle array of arguments', () => {
|
|
28
|
+
const result = formatFunctionArgs(['arg1', '"arg2"', ' arg3 '])
|
|
29
|
+
assert.is(Array.isArray(result), true)
|
|
30
|
+
assert.equal(result, ['arg1', 'arg2', 'arg3'])
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('formatFunctionArgs - should parse JSON objects in array', () => {
|
|
34
|
+
const result = formatFunctionArgs(['{"x":1}', '{"y":2}'])
|
|
35
|
+
assert.is(Array.isArray(result), true)
|
|
36
|
+
assert.equal(result[0].x, 1)
|
|
37
|
+
assert.equal(result[1].y, 2)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('formatFunctionArgs - should parse JSON arrays in array', () => {
|
|
41
|
+
const result = formatFunctionArgs(['[1,2]', '[3,4]'])
|
|
42
|
+
assert.is(Array.isArray(result), true)
|
|
43
|
+
assert.equal(result[0], [1, 2])
|
|
44
|
+
assert.equal(result[1], [3, 4])
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('formatFunctionArgs - should handle mixed array', () => {
|
|
48
|
+
const result = formatFunctionArgs(['simple', '{"obj":"val"}', '[1,2]'])
|
|
49
|
+
assert.equal(result[0], 'simple')
|
|
50
|
+
assert.equal(result[1].obj, 'val')
|
|
51
|
+
assert.equal(result[2], [1, 2])
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('formatFunctionArgs - should handle single quotes', () => {
|
|
55
|
+
const result = formatFunctionArgs("'singleQuoted'")
|
|
56
|
+
assert.equal(result, 'singleQuoted')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('formatFunctionArgs - should handle empty object', () => {
|
|
60
|
+
const result = formatFunctionArgs('{}')
|
|
61
|
+
assert.is(typeof result, 'object')
|
|
62
|
+
assert.equal(Object.keys(result).length, 0)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('formatFunctionArgs - should handle empty array', () => {
|
|
66
|
+
const result = formatFunctionArgs('[]')
|
|
67
|
+
// Empty array regex pattern doesn't match /^\[([^}]+)\]$/ so returns the string as-is
|
|
68
|
+
assert.equal(result, '[]')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('formatFunctionArgs - should preserve unquoted strings', () => {
|
|
72
|
+
const result = formatFunctionArgs('unquoted')
|
|
73
|
+
assert.equal(result, 'unquoted')
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
// Run all tests
|
|
77
|
+
test.run()
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quote manipulation utilities for string handling
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Removes surrounding quotes (single, double, or backtick) from a string
|
|
7
|
+
* @param {string} str - The string to trim
|
|
8
|
+
* @param {boolean} includeBackticks - Whether to also trim backticks (default: true)
|
|
9
|
+
* @returns {string} The trimmed string
|
|
10
|
+
*/
|
|
11
|
+
function trimSurroundingQuotes(str = '', includeBackticks = true) {
|
|
12
|
+
let result = str
|
|
13
|
+
.replace(/^(")([^"\n]*?)(\1)$/, "$2")
|
|
14
|
+
.replace(/^(')([^'\n]*?)(\1)$/, "$2")
|
|
15
|
+
|
|
16
|
+
if (includeBackticks) {
|
|
17
|
+
result = result.replace(/^(`)([^`\n]*?)(\1)$/, "$2")
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return result
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Checks if a string starts with the given character
|
|
25
|
+
* @param {string} str - The string to check
|
|
26
|
+
* @param {string} char - The character to check for
|
|
27
|
+
* @returns {string} Empty string if starts with char, otherwise the char
|
|
28
|
+
*/
|
|
29
|
+
function startChar(str, char) {
|
|
30
|
+
return (str[0] === char) ? '' : char
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Checks if a string ends with the given character
|
|
35
|
+
* @param {string} str - The string to check
|
|
36
|
+
* @param {string} char - The character to check for
|
|
37
|
+
* @returns {string} Empty string if ends with char, otherwise the char
|
|
38
|
+
*/
|
|
39
|
+
function endChar(str, char) {
|
|
40
|
+
return (str[str.length - 1] === char) ? '' : char
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Ensures a value (string or array of strings) has quotes around it
|
|
45
|
+
* @param {string|string[]} value - The value to quote
|
|
46
|
+
* @param {string} open - Opening quote character (default: '"')
|
|
47
|
+
* @param {string} close - Closing quote character (default: same as open)
|
|
48
|
+
* @returns {string|string[]} The quoted value(s)
|
|
49
|
+
*/
|
|
50
|
+
function ensureQuote(value, open = '"', close) {
|
|
51
|
+
let i = -1
|
|
52
|
+
const result = []
|
|
53
|
+
const end = close || open
|
|
54
|
+
if (typeof value === 'string') {
|
|
55
|
+
return startChar(value, open) + value + endChar(value, end)
|
|
56
|
+
}
|
|
57
|
+
while (++i < value.length) {
|
|
58
|
+
result[i] = startChar(value[i], open) + value[i] + endChar(value[i], end)
|
|
59
|
+
}
|
|
60
|
+
return result
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Checks if a string is surrounded by matching quotes (single or double)
|
|
65
|
+
* @param {string} str - The string to check
|
|
66
|
+
* @returns {boolean} True if surrounded by matching quotes
|
|
67
|
+
*/
|
|
68
|
+
function isSurroundedByQuotes(str) {
|
|
69
|
+
if (!str || str.length < 2) return false
|
|
70
|
+
const firstChar = str[0]
|
|
71
|
+
const lastChar = str[str.length - 1]
|
|
72
|
+
return (firstChar === "'" && lastChar === "'") || (firstChar === '"' && lastChar === '"')
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Checks if a string starts with a quoted value followed by a pipe
|
|
77
|
+
* @param {string} str - The string to check
|
|
78
|
+
* @returns {boolean} True if matches pattern like 'xyz' | or "xyz" |
|
|
79
|
+
*/
|
|
80
|
+
function startsWithQuotedPipe(str) {
|
|
81
|
+
return /^(['"])(.*?)\1\s*\|/.test(str)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = {
|
|
85
|
+
trimSurroundingQuotes,
|
|
86
|
+
ensureQuote,
|
|
87
|
+
isSurroundedByQuotes,
|
|
88
|
+
startsWithQuotedPipe
|
|
89
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
const { test } = require('uvu')
|
|
2
|
+
const assert = require('uvu/assert')
|
|
3
|
+
const { trimSurroundingQuotes: trimQuotes, ensureQuote, isSurroundedByQuotes, startsWithQuotedPipe } = require('./quoteUtils')
|
|
4
|
+
|
|
5
|
+
// Tests for double quotes
|
|
6
|
+
test('trimQuotes - should remove surrounding double quotes', () => {
|
|
7
|
+
const result = trimQuotes('"hello"')
|
|
8
|
+
assert.equal(result, 'hello')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
test('trimQuotes - should not remove non-surrounding double quotes', () => {
|
|
12
|
+
const result = trimQuotes('say "hello" there')
|
|
13
|
+
assert.equal(result, 'say "hello" there')
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('trimQuotes - should preserve internal double quotes', () => {
|
|
17
|
+
const result = trimQuotes('"has "nested" quotes"')
|
|
18
|
+
assert.equal(result, '"has "nested" quotes"')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
// Tests for single quotes
|
|
22
|
+
test('trimQuotes - should remove surrounding single quotes', () => {
|
|
23
|
+
const result = trimQuotes("'hello'")
|
|
24
|
+
assert.equal(result, 'hello')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('trimQuotes - should not remove non-surrounding single quotes', () => {
|
|
28
|
+
const result = trimQuotes("say 'hello' there")
|
|
29
|
+
assert.equal(result, "say 'hello' there")
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('trimQuotes - should preserve internal single quotes', () => {
|
|
33
|
+
const result = trimQuotes("'has 'nested' quotes'")
|
|
34
|
+
assert.equal(result, "'has 'nested' quotes'")
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
// Tests for backticks
|
|
38
|
+
test('trimQuotes - should remove surrounding backticks by default', () => {
|
|
39
|
+
const result = trimQuotes('`hello`')
|
|
40
|
+
assert.equal(result, 'hello')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('trimQuotes - should not remove backticks when includeBackticks is false', () => {
|
|
44
|
+
const result = trimQuotes('`hello`', false)
|
|
45
|
+
assert.equal(result, '`hello`')
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('trimQuotes - should preserve internal backticks', () => {
|
|
49
|
+
const result = trimQuotes('`has `nested` ticks`')
|
|
50
|
+
assert.equal(result, '`has `nested` ticks`')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
// Tests for mixed quotes
|
|
54
|
+
test('trimQuotes - should not remove mismatched quotes', () => {
|
|
55
|
+
const result = trimQuotes('"hello\'')
|
|
56
|
+
assert.equal(result, '"hello\'')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('trimQuotes - should handle empty quotes', () => {
|
|
60
|
+
const result = trimQuotes('""')
|
|
61
|
+
assert.equal(result, '')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('trimQuotes - should handle empty single quotes', () => {
|
|
65
|
+
const result = trimQuotes("''")
|
|
66
|
+
assert.equal(result, '')
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('trimQuotes - should handle empty backticks', () => {
|
|
70
|
+
const result = trimQuotes('``')
|
|
71
|
+
assert.equal(result, '')
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Tests for edge cases
|
|
75
|
+
test('trimQuotes - should handle empty string', () => {
|
|
76
|
+
const result = trimQuotes('')
|
|
77
|
+
assert.equal(result, '')
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
test('trimQuotes - should handle undefined', () => {
|
|
81
|
+
const result = trimQuotes()
|
|
82
|
+
assert.equal(result, '')
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test('trimQuotes - should handle strings without quotes', () => {
|
|
86
|
+
const result = trimQuotes('hello world')
|
|
87
|
+
assert.equal(result, 'hello world')
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test('trimQuotes - should handle strings with only opening quote', () => {
|
|
91
|
+
const result = trimQuotes('"hello')
|
|
92
|
+
assert.equal(result, '"hello')
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
test('trimQuotes - should handle strings with only closing quote', () => {
|
|
96
|
+
const result = trimQuotes('hello"')
|
|
97
|
+
assert.equal(result, 'hello"')
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
test('trimQuotes - should not remove quotes from multi-line strings', () => {
|
|
101
|
+
const result = trimQuotes('"hello\nworld"')
|
|
102
|
+
assert.equal(result, '"hello\nworld"')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test('trimQuotes - should handle spaces inside quotes', () => {
|
|
106
|
+
const result = trimQuotes('" hello "')
|
|
107
|
+
assert.equal(result, ' hello ')
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
test('trimQuotes - should handle special characters inside quotes', () => {
|
|
111
|
+
const result = trimQuotes('"hello@#$%world"')
|
|
112
|
+
assert.equal(result, 'hello@#$%world')
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
test('trimQuotes - should handle numbers as strings', () => {
|
|
116
|
+
const result = trimQuotes('"12345"')
|
|
117
|
+
assert.equal(result, '12345')
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
test('trimQuotes - should handle JSON-like strings', () => {
|
|
121
|
+
const result = trimQuotes('"{key: value}"')
|
|
122
|
+
assert.equal(result, '{key: value}')
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
// Tests for backtick parameter
|
|
126
|
+
test('trimQuotes - should process all quote types when includeBackticks is true', () => {
|
|
127
|
+
assert.equal(trimQuotes('"test"', true), 'test')
|
|
128
|
+
assert.equal(trimQuotes("'test'", true), 'test')
|
|
129
|
+
assert.equal(trimQuotes('`test`', true), 'test')
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
test('trimQuotes - should not process backticks when includeBackticks is false', () => {
|
|
133
|
+
assert.equal(trimQuotes('"test"', false), 'test')
|
|
134
|
+
assert.equal(trimQuotes("'test'", false), 'test')
|
|
135
|
+
assert.equal(trimQuotes('`test`', false), '`test`')
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
// Tests for ensureQuote
|
|
139
|
+
test('ensureQuote - should add double quotes to unquoted string', () => {
|
|
140
|
+
assert.equal(ensureQuote('hello'), '"hello"')
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
test('ensureQuote - should not double-quote already quoted string', () => {
|
|
144
|
+
assert.equal(ensureQuote('"hello"'), '"hello"')
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
test('ensureQuote - should use custom open/close characters', () => {
|
|
148
|
+
assert.equal(ensureQuote('hello', "'"), "'hello'")
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
test('ensureQuote - should handle different open and close characters', () => {
|
|
152
|
+
assert.equal(ensureQuote('hello', '[', ']'), '[hello]')
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
test('ensureQuote - should handle array of strings', () => {
|
|
156
|
+
const result = ensureQuote(['a', 'b', 'c'])
|
|
157
|
+
assert.equal(result, ['"a"', '"b"', '"c"'])
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
test('ensureQuote - should not re-quote already quoted items in array', () => {
|
|
161
|
+
const result = ensureQuote(['"a"', 'b'])
|
|
162
|
+
assert.equal(result, ['"a"', '"b"'])
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
// Tests for isSurroundedByQuotes
|
|
166
|
+
test('isSurroundedByQuotes - should return true for double-quoted string', () => {
|
|
167
|
+
assert.equal(isSurroundedByQuotes('"hello"'), true)
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
test('isSurroundedByQuotes - should return true for single-quoted string', () => {
|
|
171
|
+
assert.equal(isSurroundedByQuotes("'hello'"), true)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
test('isSurroundedByQuotes - should return false for unquoted string', () => {
|
|
175
|
+
assert.equal(isSurroundedByQuotes('hello'), false)
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
test('isSurroundedByQuotes - should return false for mismatched quotes', () => {
|
|
179
|
+
assert.equal(isSurroundedByQuotes('"hello\''), false)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
test('isSurroundedByQuotes - should return false for empty string', () => {
|
|
183
|
+
assert.equal(isSurroundedByQuotes(''), false)
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
test('isSurroundedByQuotes - should return false for null/undefined', () => {
|
|
187
|
+
assert.equal(isSurroundedByQuotes(null), false)
|
|
188
|
+
assert.equal(isSurroundedByQuotes(undefined), false)
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
test('isSurroundedByQuotes - should return false for single character', () => {
|
|
192
|
+
assert.equal(isSurroundedByQuotes('"'), false)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
// Tests for startsWithQuotedPipe
|
|
196
|
+
test('startsWithQuotedPipe - should match single-quoted value with pipe', () => {
|
|
197
|
+
assert.equal(startsWithQuotedPipe("'value' | filter"), true)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
test('startsWithQuotedPipe - should match double-quoted value with pipe', () => {
|
|
201
|
+
assert.equal(startsWithQuotedPipe('"value" | filter'), true)
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
test('startsWithQuotedPipe - should not match unquoted value with pipe', () => {
|
|
205
|
+
assert.equal(startsWithQuotedPipe('value | filter'), false)
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
test('startsWithQuotedPipe - should not match quoted value without pipe', () => {
|
|
209
|
+
assert.equal(startsWithQuotedPipe('"value"'), false)
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
test('startsWithQuotedPipe - should handle spaces around pipe', () => {
|
|
213
|
+
assert.equal(startsWithQuotedPipe("'xyz' | something"), true)
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
// Run all tests
|
|
217
|
+
test.run()
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const { test } = require('uvu')
|
|
2
|
+
const assert = require('uvu/assert')
|
|
3
|
+
const { replaceAll } = require('./replaceAll')
|
|
4
|
+
|
|
5
|
+
test('replaceAll - should replace simple string', () => {
|
|
6
|
+
const result = replaceAll('foo', 'bar', 'foo is foo')
|
|
7
|
+
assert.equal(result, 'bar is bar')
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
test('replaceAll - should replace all occurrences', () => {
|
|
11
|
+
const result = replaceAll('a', 'x', 'aaa bbb aaa')
|
|
12
|
+
assert.equal(result, 'xxx bbb xxx')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test('replaceAll - should handle regex special characters in search string', () => {
|
|
16
|
+
const result = replaceAll('.', 'X', 'a.b.c')
|
|
17
|
+
assert.equal(result, 'aXbXc')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('replaceAll - should handle $ in replacement string', () => {
|
|
21
|
+
const result = replaceAll('foo', '$bar', 'foo is foo')
|
|
22
|
+
assert.equal(result, '$bar is $bar')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('replaceAll - should handle parentheses in search string', () => {
|
|
26
|
+
const result = replaceAll('(test)', 'result', 'this (test) is a (test)')
|
|
27
|
+
assert.equal(result, 'this result is a result')
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('replaceAll - should handle square brackets in search string', () => {
|
|
31
|
+
const result = replaceAll('[item]', 'value', 'get [item] and [item]')
|
|
32
|
+
assert.equal(result, 'get value and value')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('replaceAll - should handle forward slashes', () => {
|
|
36
|
+
const result = replaceAll('/', '-', 'path/to/file')
|
|
37
|
+
assert.equal(result, 'path-to-file')
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('replaceAll - should handle backslashes', () => {
|
|
41
|
+
const result = replaceAll('\\', '/', 'path\\to\\file')
|
|
42
|
+
assert.equal(result, 'path/to/file')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('replaceAll - should handle curly braces', () => {
|
|
46
|
+
const result = replaceAll('{var}', 'value', 'get {var} and {var}')
|
|
47
|
+
assert.equal(result, 'get value and value')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('replaceAll - should handle asterisks', () => {
|
|
51
|
+
const result = replaceAll('*', 'star', '* is *')
|
|
52
|
+
assert.equal(result, 'star is star')
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('replaceAll - should handle plus signs', () => {
|
|
56
|
+
const result = replaceAll('+', 'plus', 'a+b+c')
|
|
57
|
+
console.log('result', result)
|
|
58
|
+
assert.equal(result, 'aplusbplusc')
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test('replaceAll - should handle question marks', () => {
|
|
62
|
+
const result = replaceAll('?', 'Q', 'what? why?')
|
|
63
|
+
assert.equal(result, 'whatQ whyQ')
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
test('replaceAll - should handle empty replacement', () => {
|
|
67
|
+
const result = replaceAll('foo', '', 'foo bar foo')
|
|
68
|
+
assert.equal(result, ' bar ')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('replaceAll - should handle no matches', () => {
|
|
72
|
+
const result = replaceAll('xyz', 'abc', 'hello world')
|
|
73
|
+
assert.equal(result, 'hello world')
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
test('replaceAll - should handle complex regex special characters', () => {
|
|
77
|
+
const result = replaceAll('${var}', 'value', 'get ${var} and ${var}')
|
|
78
|
+
assert.equal(result, 'get value and value')
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
// Run all tests
|
|
82
|
+
test.run()
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const { splitByComma } = require('./splitByComma')
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Split a string by comma while preserving quoted content
|
|
5
|
+
* NOTE: This is a simpler version that delegates to splitByComma for consistency.
|
|
6
|
+
* For advanced use cases with bracket depth tracking and regex protection, use splitByComma directly.
|
|
7
|
+
* @param {string} str - String to split
|
|
8
|
+
* @param {string} splitter - Optional custom splitter (defaults to ',')
|
|
9
|
+
* @returns {string[]} Array of split strings
|
|
10
|
+
*/
|
|
11
|
+
function splitCsv(str, splitter) {
|
|
12
|
+
// If custom splitter is provided, fall back to original simple implementation
|
|
13
|
+
if (splitter && splitter !== ',') {
|
|
14
|
+
const splitSyntax = splitter
|
|
15
|
+
return str.split(splitSyntax).reduce(
|
|
16
|
+
(acc, curr) => {
|
|
17
|
+
if (acc.isConcatting) {
|
|
18
|
+
acc.soFar[acc.soFar.length - 1] += splitter + curr
|
|
19
|
+
} else {
|
|
20
|
+
acc.soFar.push(curr)
|
|
21
|
+
}
|
|
22
|
+
if (curr.split('"').length % 2 == 0) {
|
|
23
|
+
acc.isConcatting = !acc.isConcatting
|
|
24
|
+
}
|
|
25
|
+
return acc
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
soFar: [],
|
|
29
|
+
isConcatting: false,
|
|
30
|
+
},
|
|
31
|
+
).soFar
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// For standard comma splitting, use the more robust splitByComma
|
|
35
|
+
return splitByComma(str)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = { splitCsv }
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const { test } = require('uvu')
|
|
2
|
+
const assert = require('uvu/assert')
|
|
3
|
+
const { splitCsv } = require('./splitCsv')
|
|
4
|
+
|
|
5
|
+
// Tests for default comma splitting (uses splitByComma internally)
|
|
6
|
+
test('splitCsv - should split simple comma-separated values', () => {
|
|
7
|
+
const result = splitCsv('first,second,third')
|
|
8
|
+
assert.equal(result, ['first', 'second', 'third'])
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
test('splitCsv - should handle spaces around commas', () => {
|
|
12
|
+
const result = splitCsv('first, second, third')
|
|
13
|
+
assert.equal(result, ['first', 'second', 'third'])
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('splitCsv - should preserve quoted strings with commas', () => {
|
|
17
|
+
const result = splitCsv("'string, with comma', normal")
|
|
18
|
+
assert.equal(result, ["'string, with comma'", 'normal'])
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('splitCsv - should handle double quotes', () => {
|
|
22
|
+
const result = splitCsv('"quoted, value", normal')
|
|
23
|
+
assert.equal(result, ['"quoted, value"', 'normal'])
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('splitCsv - should handle parentheses (function calls)', () => {
|
|
27
|
+
const result = splitCsv('func(arg1, arg2), other')
|
|
28
|
+
assert.equal(result, ['func(arg1, arg2)', 'other'])
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('splitCsv - should handle square brackets (arrays)', () => {
|
|
32
|
+
const result = splitCsv('[item1, item2], other')
|
|
33
|
+
assert.equal(result, ['[item1, item2]', 'other'])
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('splitCsv - should return array with single element when no commas', () => {
|
|
37
|
+
const result = splitCsv('singleValue')
|
|
38
|
+
assert.equal(result, ['singleValue'])
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test('splitCsv - should handle empty string', () => {
|
|
42
|
+
const result = splitCsv('')
|
|
43
|
+
assert.equal(result, [''])
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
// Tests for custom splitter (uses original simple implementation)
|
|
47
|
+
test('splitCsv - should use custom splitter', () => {
|
|
48
|
+
const result = splitCsv('first|second|third', '|')
|
|
49
|
+
assert.equal(result, ['first', 'second', 'third'])
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('splitCsv - should preserve quoted content with custom splitter', () => {
|
|
53
|
+
const result = splitCsv('first|"quoted|content"|third', '|')
|
|
54
|
+
assert.equal(result, ['first', '"quoted|content"', 'third'])
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('splitCsv - should handle semicolon splitter', () => {
|
|
58
|
+
const result = splitCsv('a;b;c', ';')
|
|
59
|
+
assert.equal(result, ['a', 'b', 'c'])
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('splitCsv - custom splitter with quotes preserving internal splitters', () => {
|
|
63
|
+
const result = splitCsv('"has;semicolon";normal', ';')
|
|
64
|
+
assert.equal(result, ['"has;semicolon"', 'normal'])
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// Edge cases
|
|
68
|
+
test('splitCsv - should handle mixed quotes and brackets', () => {
|
|
69
|
+
const result = splitCsv('[array], "string", func(a, b)')
|
|
70
|
+
assert.equal(result, ['[array]', '"string"', 'func(a, b)'])
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
test('splitCsv - should handle deeply nested structures', () => {
|
|
74
|
+
const result = splitCsv('func(obj[0, 1], "str, comma"), other')
|
|
75
|
+
assert.equal(result, ['func(obj[0, 1], "str, comma")', 'other'])
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('splitCsv - should handle serverless variable syntax', () => {
|
|
79
|
+
const result = splitCsv('opt:stage, ${opt:stageOne}')
|
|
80
|
+
// Default behavior splits inside ${}, but splitByComma handles this better
|
|
81
|
+
// This test just verifies it doesn't crash
|
|
82
|
+
assert.ok(Array.isArray(result))
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test('splitCsv - should preserve whitespace in quoted strings', () => {
|
|
86
|
+
const result = splitCsv('" spaces ", normal')
|
|
87
|
+
assert.equal(result, ['" spaces "', 'normal'])
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test('splitCsv - should handle consecutive commas with custom splitter', () => {
|
|
91
|
+
const result = splitCsv('a||c', '|')
|
|
92
|
+
assert.equal(result, ['a', '', 'c'])
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// Run all tests
|
|
96
|
+
test.run()
|