@questwork/q-utilities 0.1.20 ā 0.1.21
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/dist/index.min.cjs +132 -5
- package/dist/q-utilities.esm.js +131 -6
- package/dist/q-utilities.min.js +132 -5
- package/package.json +1 -1
package/dist/index.min.cjs
CHANGED
|
@@ -69,6 +69,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
69
69
|
changeCreatorOwner: () => (/* reexport */ changeCreatorOwner),
|
|
70
70
|
concatStringByArray: () => (/* reexport */ concatStringByArray),
|
|
71
71
|
convertString: () => (/* reexport */ convertString),
|
|
72
|
+
detectControlCharacters: () => (/* reexport */ detectControlCharacters),
|
|
72
73
|
escapeRegex: () => (/* reexport */ escapeRegex),
|
|
73
74
|
expressHelper: () => (/* reexport */ expressHelper),
|
|
74
75
|
extractEmails: () => (/* reexport */ extractEmails),
|
|
@@ -87,6 +88,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
87
88
|
objectHelper: () => (/* reexport */ objectHelper),
|
|
88
89
|
pReduce: () => (/* reexport */ pReduce),
|
|
89
90
|
padZeros: () => (/* reexport */ padZeros),
|
|
91
|
+
printControlCharReport: () => (/* reexport */ printControlCharReport),
|
|
90
92
|
replacePlaceholders: () => (/* reexport */ replacePlaceholders),
|
|
91
93
|
sanitizeText: () => (/* reexport */ sanitizeText),
|
|
92
94
|
shuffleArray: () => (/* reexport */ shuffleArray),
|
|
@@ -1605,6 +1607,107 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1605
1607
|
;// ./lib/helpers/convertString/index.js
|
|
1606
1608
|
|
|
1607
1609
|
|
|
1610
|
+
;// ./lib/helpers/detectControlCharacters/detectControlCharacters.js
|
|
1611
|
+
/**
|
|
1612
|
+
* Detects and reports hidden/control characters in a string without modifying it.
|
|
1613
|
+
* @param {string} input - The string to analyze.
|
|
1614
|
+
* @param {Object} [options] - Configuration options.
|
|
1615
|
+
* @param {boolean} [options.preserveBasicWhitespace=true] - Whether to consider basic whitespace as valid.
|
|
1616
|
+
* @returns {Object} Report object with detection results.
|
|
1617
|
+
*/
|
|
1618
|
+
function detectControlCharacters(input, options = {}) {
|
|
1619
|
+
const {
|
|
1620
|
+
preserveBasicWhitespace = true,
|
|
1621
|
+
removeNewlines = false
|
|
1622
|
+
} = options
|
|
1623
|
+
|
|
1624
|
+
if (typeof input !== 'string') {
|
|
1625
|
+
return {
|
|
1626
|
+
hasControlChars: false,
|
|
1627
|
+
matches: [],
|
|
1628
|
+
inputType: typeof input,
|
|
1629
|
+
message: 'Input is not a string'
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
const matches = []
|
|
1634
|
+
let regex
|
|
1635
|
+
|
|
1636
|
+
if (preserveBasicWhitespace && !removeNewlines) {
|
|
1637
|
+
// Same regex as Phase 1 preserve mode - keep tab (\t), newline (\n), carriage return (\r)
|
|
1638
|
+
regex = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g
|
|
1639
|
+
} else {
|
|
1640
|
+
// Same regex as Phase 1 full removal mode - use consistent escape sequences
|
|
1641
|
+
regex = /[\x00-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
// Use a replacer function to capture matches without modifying the string
|
|
1645
|
+
input.replace(regex, (match, offset) => {
|
|
1646
|
+
matches.push({
|
|
1647
|
+
character: match,
|
|
1648
|
+
code: match.charCodeAt(0),
|
|
1649
|
+
hex: '0x' + match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0'),
|
|
1650
|
+
position: offset,
|
|
1651
|
+
context: getContext(input, offset, 10) // Show surrounding text
|
|
1652
|
+
})
|
|
1653
|
+
return '' // Return empty but we don't use the result
|
|
1654
|
+
})
|
|
1655
|
+
|
|
1656
|
+
return {
|
|
1657
|
+
hasControlChars: matches.length > 0,
|
|
1658
|
+
matches: matches,
|
|
1659
|
+
totalFound: matches.length,
|
|
1660
|
+
inputPreview: input.length > 50 ? input.substring(0, 50) + '...' : input,
|
|
1661
|
+
inputLength: input.length,
|
|
1662
|
+
optionsUsed: { preserveBasicWhitespace },
|
|
1663
|
+
regexPattern: regex.toString()
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
/**
|
|
1668
|
+
* Helper function to get context around a match
|
|
1669
|
+
*/
|
|
1670
|
+
function getContext(str, position, contextLength = 10) {
|
|
1671
|
+
const start = Math.max(0, position - contextLength)
|
|
1672
|
+
const end = Math.min(str.length, position + contextLength + 1)
|
|
1673
|
+
let context = str.substring(start, end)
|
|
1674
|
+
|
|
1675
|
+
// Replace control characters with their escape sequences for readability
|
|
1676
|
+
context = context.replace(/[\x00-\x1F\x7F-\x9F]/g, (match) => {
|
|
1677
|
+
return '\\u' + match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')
|
|
1678
|
+
})
|
|
1679
|
+
|
|
1680
|
+
return context
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
/**
|
|
1684
|
+
* Pretty print the detection results to console
|
|
1685
|
+
*/
|
|
1686
|
+
function printControlCharReport(report) {
|
|
1687
|
+
console.log('=== Control Character Detection Report ===')
|
|
1688
|
+
console.log(`Input: "${report.inputPreview}" (${report.inputLength} chars)`)
|
|
1689
|
+
console.log(`Options: preserveBasicWhitespace = ${report.optionsUsed.preserveBasicWhitespace}`)
|
|
1690
|
+
console.log(`Regex pattern: ${report.regexPattern}`)
|
|
1691
|
+
console.log(`Control characters found: ${report.totalFound}`)
|
|
1692
|
+
|
|
1693
|
+
if (report.hasControlChars) {
|
|
1694
|
+
console.log('\nš Matches found:')
|
|
1695
|
+
report.matches.forEach((match, index) => {
|
|
1696
|
+
console.log(`\n${index + 1}. Character: ${JSON.stringify(match.character)}`)
|
|
1697
|
+
console.log(` Code: ${match.code} (${match.hex})`)
|
|
1698
|
+
console.log(` Position: ${match.position}`)
|
|
1699
|
+
console.log(` Context: "...${match.context}..."`)
|
|
1700
|
+
})
|
|
1701
|
+
} else {
|
|
1702
|
+
console.log('ā
No control characters detected in Phase 1 range')
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
console.log('=== End Report ===')
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
;// ./lib/helpers/detectControlCharacters/index.js
|
|
1709
|
+
|
|
1710
|
+
|
|
1608
1711
|
;// ./lib/helpers/escapeRegex/escapeRegex.js
|
|
1609
1712
|
function escapeRegex(string) {
|
|
1610
1713
|
return String(string).replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
@@ -2953,6 +3056,7 @@ function tenantPlugin(schema, options) {
|
|
|
2953
3056
|
|
|
2954
3057
|
|
|
2955
3058
|
|
|
3059
|
+
|
|
2956
3060
|
|
|
2957
3061
|
|
|
2958
3062
|
;// ./lib/models/apiResponse/index.js
|
|
@@ -3872,24 +3976,47 @@ class StatusDocument extends Status {
|
|
|
3872
3976
|
|
|
3873
3977
|
this.archived = this._ActionRecord.init(options.archived)
|
|
3874
3978
|
this.completed = this._ActionRecord.init(options.completed)
|
|
3875
|
-
this.drafted = this._ActionRecord.init(options.drafted)
|
|
3876
3979
|
this.discarded = this._ActionRecord.init(options.discarded)
|
|
3980
|
+
this.drafted = this._ActionRecord.init(options.drafted)
|
|
3877
3981
|
// this.statusType = 'StatusDocument'
|
|
3878
3982
|
}
|
|
3879
3983
|
|
|
3880
|
-
get isValid() {
|
|
3881
|
-
return super.isValid
|
|
3882
|
-
}
|
|
3883
|
-
|
|
3884
3984
|
static get _classname() {
|
|
3885
3985
|
return 'StatusDocument'
|
|
3886
3986
|
}
|
|
3987
|
+
get _classname() {
|
|
3988
|
+
return 'StatusDocument'
|
|
3989
|
+
}
|
|
3990
|
+
get isArchived() {
|
|
3991
|
+
return this.created?.timestamp !== null
|
|
3992
|
+
}
|
|
3993
|
+
get isCompleted() {
|
|
3994
|
+
return this.completed?.timestamp !== null
|
|
3995
|
+
}
|
|
3996
|
+
get isDiscarded() {
|
|
3997
|
+
return this.discarded?.timestamp !== null
|
|
3998
|
+
}
|
|
3999
|
+
get isDrafted() {
|
|
4000
|
+
return this.drafted?.timestamp !== null
|
|
4001
|
+
}
|
|
4002
|
+
get isValid() {
|
|
4003
|
+
return super.isValid
|
|
4004
|
+
}
|
|
3887
4005
|
setArchived(value, actorCode) {
|
|
3888
4006
|
// const timestamp = value || Date.now()
|
|
3889
4007
|
// this.archived = this.archived instanceof this._ActionRecord ? this.archived.update({ actorCode, timestamp }) : this._ActionRecord.init({ actorCode, timestamp })
|
|
3890
4008
|
// return this
|
|
3891
4009
|
return this.setValue(value, actorCode, 'archived')
|
|
3892
4010
|
}
|
|
4011
|
+
setCompleted(value, actorCode) {
|
|
4012
|
+
return this.setValue(value, actorCode, 'completed')
|
|
4013
|
+
}
|
|
4014
|
+
setDiscarded(value, actorCode) {
|
|
4015
|
+
return this.setValue(value, actorCode, 'discarded')
|
|
4016
|
+
}
|
|
4017
|
+
setDrafted(value, actorCode) {
|
|
4018
|
+
return this.setValue(value, actorCode, 'drafted')
|
|
4019
|
+
}
|
|
3893
4020
|
}
|
|
3894
4021
|
|
|
3895
4022
|
;// ./lib/models/status/index.js
|
package/dist/q-utilities.esm.js
CHANGED
|
@@ -1508,6 +1508,107 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1508
1508
|
;// ./lib/helpers/convertString/index.js
|
|
1509
1509
|
|
|
1510
1510
|
|
|
1511
|
+
;// ./lib/helpers/detectControlCharacters/detectControlCharacters.js
|
|
1512
|
+
/**
|
|
1513
|
+
* Detects and reports hidden/control characters in a string without modifying it.
|
|
1514
|
+
* @param {string} input - The string to analyze.
|
|
1515
|
+
* @param {Object} [options] - Configuration options.
|
|
1516
|
+
* @param {boolean} [options.preserveBasicWhitespace=true] - Whether to consider basic whitespace as valid.
|
|
1517
|
+
* @returns {Object} Report object with detection results.
|
|
1518
|
+
*/
|
|
1519
|
+
function detectControlCharacters(input, options = {}) {
|
|
1520
|
+
const {
|
|
1521
|
+
preserveBasicWhitespace = true,
|
|
1522
|
+
removeNewlines = false
|
|
1523
|
+
} = options
|
|
1524
|
+
|
|
1525
|
+
if (typeof input !== 'string') {
|
|
1526
|
+
return {
|
|
1527
|
+
hasControlChars: false,
|
|
1528
|
+
matches: [],
|
|
1529
|
+
inputType: typeof input,
|
|
1530
|
+
message: 'Input is not a string'
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
const matches = []
|
|
1535
|
+
let regex
|
|
1536
|
+
|
|
1537
|
+
if (preserveBasicWhitespace && !removeNewlines) {
|
|
1538
|
+
// Same regex as Phase 1 preserve mode - keep tab (\t), newline (\n), carriage return (\r)
|
|
1539
|
+
regex = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g
|
|
1540
|
+
} else {
|
|
1541
|
+
// Same regex as Phase 1 full removal mode - use consistent escape sequences
|
|
1542
|
+
regex = /[\x00-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
// Use a replacer function to capture matches without modifying the string
|
|
1546
|
+
input.replace(regex, (match, offset) => {
|
|
1547
|
+
matches.push({
|
|
1548
|
+
character: match,
|
|
1549
|
+
code: match.charCodeAt(0),
|
|
1550
|
+
hex: '0x' + match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0'),
|
|
1551
|
+
position: offset,
|
|
1552
|
+
context: getContext(input, offset, 10) // Show surrounding text
|
|
1553
|
+
})
|
|
1554
|
+
return '' // Return empty but we don't use the result
|
|
1555
|
+
})
|
|
1556
|
+
|
|
1557
|
+
return {
|
|
1558
|
+
hasControlChars: matches.length > 0,
|
|
1559
|
+
matches: matches,
|
|
1560
|
+
totalFound: matches.length,
|
|
1561
|
+
inputPreview: input.length > 50 ? input.substring(0, 50) + '...' : input,
|
|
1562
|
+
inputLength: input.length,
|
|
1563
|
+
optionsUsed: { preserveBasicWhitespace },
|
|
1564
|
+
regexPattern: regex.toString()
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
/**
|
|
1569
|
+
* Helper function to get context around a match
|
|
1570
|
+
*/
|
|
1571
|
+
function getContext(str, position, contextLength = 10) {
|
|
1572
|
+
const start = Math.max(0, position - contextLength)
|
|
1573
|
+
const end = Math.min(str.length, position + contextLength + 1)
|
|
1574
|
+
let context = str.substring(start, end)
|
|
1575
|
+
|
|
1576
|
+
// Replace control characters with their escape sequences for readability
|
|
1577
|
+
context = context.replace(/[\x00-\x1F\x7F-\x9F]/g, (match) => {
|
|
1578
|
+
return '\\u' + match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')
|
|
1579
|
+
})
|
|
1580
|
+
|
|
1581
|
+
return context
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
/**
|
|
1585
|
+
* Pretty print the detection results to console
|
|
1586
|
+
*/
|
|
1587
|
+
function printControlCharReport(report) {
|
|
1588
|
+
console.log('=== Control Character Detection Report ===')
|
|
1589
|
+
console.log(`Input: "${report.inputPreview}" (${report.inputLength} chars)`)
|
|
1590
|
+
console.log(`Options: preserveBasicWhitespace = ${report.optionsUsed.preserveBasicWhitespace}`)
|
|
1591
|
+
console.log(`Regex pattern: ${report.regexPattern}`)
|
|
1592
|
+
console.log(`Control characters found: ${report.totalFound}`)
|
|
1593
|
+
|
|
1594
|
+
if (report.hasControlChars) {
|
|
1595
|
+
console.log('\nš Matches found:')
|
|
1596
|
+
report.matches.forEach((match, index) => {
|
|
1597
|
+
console.log(`\n${index + 1}. Character: ${JSON.stringify(match.character)}`)
|
|
1598
|
+
console.log(` Code: ${match.code} (${match.hex})`)
|
|
1599
|
+
console.log(` Position: ${match.position}`)
|
|
1600
|
+
console.log(` Context: "...${match.context}..."`)
|
|
1601
|
+
})
|
|
1602
|
+
} else {
|
|
1603
|
+
console.log('ā
No control characters detected in Phase 1 range')
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
console.log('=== End Report ===')
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
;// ./lib/helpers/detectControlCharacters/index.js
|
|
1610
|
+
|
|
1611
|
+
|
|
1511
1612
|
;// ./lib/helpers/escapeRegex/escapeRegex.js
|
|
1512
1613
|
function escapeRegex(string) {
|
|
1513
1614
|
return String(string).replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
@@ -2856,6 +2957,7 @@ function tenantPlugin(schema, options) {
|
|
|
2856
2957
|
|
|
2857
2958
|
|
|
2858
2959
|
|
|
2960
|
+
|
|
2859
2961
|
|
|
2860
2962
|
|
|
2861
2963
|
;// ./lib/models/apiResponse/index.js
|
|
@@ -3775,24 +3877,47 @@ class StatusDocument extends Status {
|
|
|
3775
3877
|
|
|
3776
3878
|
this.archived = this._ActionRecord.init(options.archived)
|
|
3777
3879
|
this.completed = this._ActionRecord.init(options.completed)
|
|
3778
|
-
this.drafted = this._ActionRecord.init(options.drafted)
|
|
3779
3880
|
this.discarded = this._ActionRecord.init(options.discarded)
|
|
3881
|
+
this.drafted = this._ActionRecord.init(options.drafted)
|
|
3780
3882
|
// this.statusType = 'StatusDocument'
|
|
3781
3883
|
}
|
|
3782
3884
|
|
|
3783
|
-
get isValid() {
|
|
3784
|
-
return super.isValid
|
|
3785
|
-
}
|
|
3786
|
-
|
|
3787
3885
|
static get _classname() {
|
|
3788
3886
|
return 'StatusDocument'
|
|
3789
3887
|
}
|
|
3888
|
+
get _classname() {
|
|
3889
|
+
return 'StatusDocument'
|
|
3890
|
+
}
|
|
3891
|
+
get isArchived() {
|
|
3892
|
+
return this.created?.timestamp !== null
|
|
3893
|
+
}
|
|
3894
|
+
get isCompleted() {
|
|
3895
|
+
return this.completed?.timestamp !== null
|
|
3896
|
+
}
|
|
3897
|
+
get isDiscarded() {
|
|
3898
|
+
return this.discarded?.timestamp !== null
|
|
3899
|
+
}
|
|
3900
|
+
get isDrafted() {
|
|
3901
|
+
return this.drafted?.timestamp !== null
|
|
3902
|
+
}
|
|
3903
|
+
get isValid() {
|
|
3904
|
+
return super.isValid
|
|
3905
|
+
}
|
|
3790
3906
|
setArchived(value, actorCode) {
|
|
3791
3907
|
// const timestamp = value || Date.now()
|
|
3792
3908
|
// this.archived = this.archived instanceof this._ActionRecord ? this.archived.update({ actorCode, timestamp }) : this._ActionRecord.init({ actorCode, timestamp })
|
|
3793
3909
|
// return this
|
|
3794
3910
|
return this.setValue(value, actorCode, 'archived')
|
|
3795
3911
|
}
|
|
3912
|
+
setCompleted(value, actorCode) {
|
|
3913
|
+
return this.setValue(value, actorCode, 'completed')
|
|
3914
|
+
}
|
|
3915
|
+
setDiscarded(value, actorCode) {
|
|
3916
|
+
return this.setValue(value, actorCode, 'discarded')
|
|
3917
|
+
}
|
|
3918
|
+
setDrafted(value, actorCode) {
|
|
3919
|
+
return this.setValue(value, actorCode, 'drafted')
|
|
3920
|
+
}
|
|
3796
3921
|
}
|
|
3797
3922
|
|
|
3798
3923
|
;// ./lib/models/status/index.js
|
|
@@ -3948,4 +4073,4 @@ function _makeSetCode(fieldName, options) {
|
|
|
3948
4073
|
;// ./index.js
|
|
3949
4074
|
|
|
3950
4075
|
|
|
3951
|
-
export { ActionRecord, ApiResponse, AwsStsS3Client, KeyValueObject, Metadata, PushEnvelope, QMeta, Repo, Service, Status, StatusDocument, TemplateCompiler, TenantAwareEntity, TrackedEntity, UniqueKeyGenerator, authorize, calculateAge, changeCreatorOwner, concatStringByArray, convertString, escapeRegex, expressHelper, extractEmails, formatDate, generalPost, getValidation, getValueByKeys_getValueByKeys as getValueByKeys, groupArrayByKey, init, initFromArray, initOnlyValidFromArray, isConvertibleToNumber, makeApiResponse, makeService, mergeArraysByKey, objectHelper, pReduce, padZeros, replacePlaceholders, sanitizeText, shuffleArray, stringFormatter, stringHelper, tenantPlugin, trackingPlugin };
|
|
4076
|
+
export { ActionRecord, ApiResponse, AwsStsS3Client, KeyValueObject, Metadata, PushEnvelope, QMeta, Repo, Service, Status, StatusDocument, TemplateCompiler, TenantAwareEntity, TrackedEntity, UniqueKeyGenerator, authorize, calculateAge, changeCreatorOwner, concatStringByArray, convertString, detectControlCharacters, escapeRegex, expressHelper, extractEmails, formatDate, generalPost, getValidation, getValueByKeys_getValueByKeys as getValueByKeys, groupArrayByKey, init, initFromArray, initOnlyValidFromArray, isConvertibleToNumber, makeApiResponse, makeService, mergeArraysByKey, objectHelper, pReduce, padZeros, printControlCharReport, replacePlaceholders, sanitizeText, shuffleArray, stringFormatter, stringHelper, tenantPlugin, trackingPlugin };
|
package/dist/q-utilities.min.js
CHANGED
|
@@ -68,6 +68,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
68
68
|
changeCreatorOwner: () => (/* reexport */ changeCreatorOwner),
|
|
69
69
|
concatStringByArray: () => (/* reexport */ concatStringByArray),
|
|
70
70
|
convertString: () => (/* reexport */ convertString),
|
|
71
|
+
detectControlCharacters: () => (/* reexport */ detectControlCharacters),
|
|
71
72
|
escapeRegex: () => (/* reexport */ escapeRegex),
|
|
72
73
|
expressHelper: () => (/* reexport */ expressHelper),
|
|
73
74
|
extractEmails: () => (/* reexport */ extractEmails),
|
|
@@ -86,6 +87,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
86
87
|
objectHelper: () => (/* reexport */ objectHelper),
|
|
87
88
|
pReduce: () => (/* reexport */ pReduce),
|
|
88
89
|
padZeros: () => (/* reexport */ padZeros),
|
|
90
|
+
printControlCharReport: () => (/* reexport */ printControlCharReport),
|
|
89
91
|
replacePlaceholders: () => (/* reexport */ replacePlaceholders),
|
|
90
92
|
sanitizeText: () => (/* reexport */ sanitizeText),
|
|
91
93
|
shuffleArray: () => (/* reexport */ shuffleArray),
|
|
@@ -1604,6 +1606,107 @@ function convertString(string, patternMatch = /\$\{(.+?)\}/g, value, getValueByK
|
|
|
1604
1606
|
;// ./lib/helpers/convertString/index.js
|
|
1605
1607
|
|
|
1606
1608
|
|
|
1609
|
+
;// ./lib/helpers/detectControlCharacters/detectControlCharacters.js
|
|
1610
|
+
/**
|
|
1611
|
+
* Detects and reports hidden/control characters in a string without modifying it.
|
|
1612
|
+
* @param {string} input - The string to analyze.
|
|
1613
|
+
* @param {Object} [options] - Configuration options.
|
|
1614
|
+
* @param {boolean} [options.preserveBasicWhitespace=true] - Whether to consider basic whitespace as valid.
|
|
1615
|
+
* @returns {Object} Report object with detection results.
|
|
1616
|
+
*/
|
|
1617
|
+
function detectControlCharacters(input, options = {}) {
|
|
1618
|
+
const {
|
|
1619
|
+
preserveBasicWhitespace = true,
|
|
1620
|
+
removeNewlines = false
|
|
1621
|
+
} = options
|
|
1622
|
+
|
|
1623
|
+
if (typeof input !== 'string') {
|
|
1624
|
+
return {
|
|
1625
|
+
hasControlChars: false,
|
|
1626
|
+
matches: [],
|
|
1627
|
+
inputType: typeof input,
|
|
1628
|
+
message: 'Input is not a string'
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
const matches = []
|
|
1633
|
+
let regex
|
|
1634
|
+
|
|
1635
|
+
if (preserveBasicWhitespace && !removeNewlines) {
|
|
1636
|
+
// Same regex as Phase 1 preserve mode - keep tab (\t), newline (\n), carriage return (\r)
|
|
1637
|
+
regex = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g
|
|
1638
|
+
} else {
|
|
1639
|
+
// Same regex as Phase 1 full removal mode - use consistent escape sequences
|
|
1640
|
+
regex = /[\x00-\x1F\x7F-\x9F\u200B-\u200D\uFEFF\u202A-\u202E]/g
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
// Use a replacer function to capture matches without modifying the string
|
|
1644
|
+
input.replace(regex, (match, offset) => {
|
|
1645
|
+
matches.push({
|
|
1646
|
+
character: match,
|
|
1647
|
+
code: match.charCodeAt(0),
|
|
1648
|
+
hex: '0x' + match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0'),
|
|
1649
|
+
position: offset,
|
|
1650
|
+
context: getContext(input, offset, 10) // Show surrounding text
|
|
1651
|
+
})
|
|
1652
|
+
return '' // Return empty but we don't use the result
|
|
1653
|
+
})
|
|
1654
|
+
|
|
1655
|
+
return {
|
|
1656
|
+
hasControlChars: matches.length > 0,
|
|
1657
|
+
matches: matches,
|
|
1658
|
+
totalFound: matches.length,
|
|
1659
|
+
inputPreview: input.length > 50 ? input.substring(0, 50) + '...' : input,
|
|
1660
|
+
inputLength: input.length,
|
|
1661
|
+
optionsUsed: { preserveBasicWhitespace },
|
|
1662
|
+
regexPattern: regex.toString()
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
/**
|
|
1667
|
+
* Helper function to get context around a match
|
|
1668
|
+
*/
|
|
1669
|
+
function getContext(str, position, contextLength = 10) {
|
|
1670
|
+
const start = Math.max(0, position - contextLength)
|
|
1671
|
+
const end = Math.min(str.length, position + contextLength + 1)
|
|
1672
|
+
let context = str.substring(start, end)
|
|
1673
|
+
|
|
1674
|
+
// Replace control characters with their escape sequences for readability
|
|
1675
|
+
context = context.replace(/[\x00-\x1F\x7F-\x9F]/g, (match) => {
|
|
1676
|
+
return '\\u' + match.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')
|
|
1677
|
+
})
|
|
1678
|
+
|
|
1679
|
+
return context
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
/**
|
|
1683
|
+
* Pretty print the detection results to console
|
|
1684
|
+
*/
|
|
1685
|
+
function printControlCharReport(report) {
|
|
1686
|
+
console.log('=== Control Character Detection Report ===')
|
|
1687
|
+
console.log(`Input: "${report.inputPreview}" (${report.inputLength} chars)`)
|
|
1688
|
+
console.log(`Options: preserveBasicWhitespace = ${report.optionsUsed.preserveBasicWhitespace}`)
|
|
1689
|
+
console.log(`Regex pattern: ${report.regexPattern}`)
|
|
1690
|
+
console.log(`Control characters found: ${report.totalFound}`)
|
|
1691
|
+
|
|
1692
|
+
if (report.hasControlChars) {
|
|
1693
|
+
console.log('\nš Matches found:')
|
|
1694
|
+
report.matches.forEach((match, index) => {
|
|
1695
|
+
console.log(`\n${index + 1}. Character: ${JSON.stringify(match.character)}`)
|
|
1696
|
+
console.log(` Code: ${match.code} (${match.hex})`)
|
|
1697
|
+
console.log(` Position: ${match.position}`)
|
|
1698
|
+
console.log(` Context: "...${match.context}..."`)
|
|
1699
|
+
})
|
|
1700
|
+
} else {
|
|
1701
|
+
console.log('ā
No control characters detected in Phase 1 range')
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
console.log('=== End Report ===')
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
;// ./lib/helpers/detectControlCharacters/index.js
|
|
1708
|
+
|
|
1709
|
+
|
|
1607
1710
|
;// ./lib/helpers/escapeRegex/escapeRegex.js
|
|
1608
1711
|
function escapeRegex(string) {
|
|
1609
1712
|
return String(string).replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
|
|
@@ -2952,6 +3055,7 @@ function tenantPlugin(schema, options) {
|
|
|
2952
3055
|
|
|
2953
3056
|
|
|
2954
3057
|
|
|
3058
|
+
|
|
2955
3059
|
|
|
2956
3060
|
|
|
2957
3061
|
;// ./lib/models/apiResponse/index.js
|
|
@@ -3871,24 +3975,47 @@ class StatusDocument extends Status {
|
|
|
3871
3975
|
|
|
3872
3976
|
this.archived = this._ActionRecord.init(options.archived)
|
|
3873
3977
|
this.completed = this._ActionRecord.init(options.completed)
|
|
3874
|
-
this.drafted = this._ActionRecord.init(options.drafted)
|
|
3875
3978
|
this.discarded = this._ActionRecord.init(options.discarded)
|
|
3979
|
+
this.drafted = this._ActionRecord.init(options.drafted)
|
|
3876
3980
|
// this.statusType = 'StatusDocument'
|
|
3877
3981
|
}
|
|
3878
3982
|
|
|
3879
|
-
get isValid() {
|
|
3880
|
-
return super.isValid
|
|
3881
|
-
}
|
|
3882
|
-
|
|
3883
3983
|
static get _classname() {
|
|
3884
3984
|
return 'StatusDocument'
|
|
3885
3985
|
}
|
|
3986
|
+
get _classname() {
|
|
3987
|
+
return 'StatusDocument'
|
|
3988
|
+
}
|
|
3989
|
+
get isArchived() {
|
|
3990
|
+
return this.created?.timestamp !== null
|
|
3991
|
+
}
|
|
3992
|
+
get isCompleted() {
|
|
3993
|
+
return this.completed?.timestamp !== null
|
|
3994
|
+
}
|
|
3995
|
+
get isDiscarded() {
|
|
3996
|
+
return this.discarded?.timestamp !== null
|
|
3997
|
+
}
|
|
3998
|
+
get isDrafted() {
|
|
3999
|
+
return this.drafted?.timestamp !== null
|
|
4000
|
+
}
|
|
4001
|
+
get isValid() {
|
|
4002
|
+
return super.isValid
|
|
4003
|
+
}
|
|
3886
4004
|
setArchived(value, actorCode) {
|
|
3887
4005
|
// const timestamp = value || Date.now()
|
|
3888
4006
|
// this.archived = this.archived instanceof this._ActionRecord ? this.archived.update({ actorCode, timestamp }) : this._ActionRecord.init({ actorCode, timestamp })
|
|
3889
4007
|
// return this
|
|
3890
4008
|
return this.setValue(value, actorCode, 'archived')
|
|
3891
4009
|
}
|
|
4010
|
+
setCompleted(value, actorCode) {
|
|
4011
|
+
return this.setValue(value, actorCode, 'completed')
|
|
4012
|
+
}
|
|
4013
|
+
setDiscarded(value, actorCode) {
|
|
4014
|
+
return this.setValue(value, actorCode, 'discarded')
|
|
4015
|
+
}
|
|
4016
|
+
setDrafted(value, actorCode) {
|
|
4017
|
+
return this.setValue(value, actorCode, 'drafted')
|
|
4018
|
+
}
|
|
3892
4019
|
}
|
|
3893
4020
|
|
|
3894
4021
|
;// ./lib/models/status/index.js
|