@memberjunction/global 5.4.0 → 5.5.0
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/__tests__/UUIDCompliance.test.d.ts +2 -0
- package/dist/__tests__/UUIDCompliance.test.d.ts.map +1 -0
- package/dist/__tests__/UUIDCompliance.test.js +137 -0
- package/dist/__tests__/UUIDCompliance.test.js.map +1 -0
- package/dist/__tests__/UUIDUtils.test.d.ts +2 -0
- package/dist/__tests__/UUIDUtils.test.d.ts.map +1 -0
- package/dist/__tests__/UUIDUtils.test.js +75 -0
- package/dist/__tests__/UUIDUtils.test.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/util/UUIDUtils.d.ts +44 -0
- package/dist/util/UUIDUtils.d.ts.map +1 -0
- package/dist/util/UUIDUtils.js +54 -0
- package/dist/util/UUIDUtils.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UUIDCompliance.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/UUIDCompliance.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UUID Compliance Tests
|
|
3
|
+
*
|
|
4
|
+
* These tests scan the MemberJunction source tree for direct UUID comparison
|
|
5
|
+
* patterns (=== / !==) that should use UUIDsEqual() or NormalizeUUID() instead.
|
|
6
|
+
*
|
|
7
|
+
* PostgreSQL returns UUIDs in lowercase while SQL Server returns uppercase.
|
|
8
|
+
* Direct string comparisons break cross-database compatibility.
|
|
9
|
+
*
|
|
10
|
+
* If this test fails, it means new code introduced a direct UUID comparison.
|
|
11
|
+
* Fix by replacing `x.ID === y` with `UUIDsEqual(x.ID, y)`.
|
|
12
|
+
*/
|
|
13
|
+
import { describe, it, expect } from 'vitest';
|
|
14
|
+
import * as fs from 'fs';
|
|
15
|
+
import * as path from 'path';
|
|
16
|
+
/** Directories that should never contain UUID comparison anti-patterns */
|
|
17
|
+
const SCAN_ROOT = path.resolve(__dirname, '..', '..', '..'); // packages/
|
|
18
|
+
/** Patterns that indicate direct UUID comparison (anti-patterns) */
|
|
19
|
+
const ANTI_PATTERNS = [
|
|
20
|
+
/\.ID\s*===\s*(?!['"]|true|false|null|undefined|0\b)/, // .ID === someVar (not string literals or primitives)
|
|
21
|
+
/===\s*\w+\.ID\b/, // something === x.ID
|
|
22
|
+
/\.ID\s*!==\s*(?!['"]|true|false|null|undefined|0\b)/, // .ID !== someVar
|
|
23
|
+
/!==\s*\w+\.ID\b/, // something !== x.ID
|
|
24
|
+
/\.includes\(\w+\.ID\b\)/, // array.includes(x.ID) — uses === internally
|
|
25
|
+
];
|
|
26
|
+
/** Files/directories to exclude from scanning */
|
|
27
|
+
const EXCLUDE_PATTERNS = [
|
|
28
|
+
/node_modules/,
|
|
29
|
+
/\/dist\//,
|
|
30
|
+
/\/generated\//,
|
|
31
|
+
/\.test\.ts$/,
|
|
32
|
+
/\.spec\.ts$/,
|
|
33
|
+
/__tests__/,
|
|
34
|
+
/UUIDUtils\.ts$/, // The utility itself
|
|
35
|
+
/\.js$/, // Only scan TypeScript source
|
|
36
|
+
/\.d\.ts$/, // Skip declaration files
|
|
37
|
+
/\.map$/, // Skip source maps
|
|
38
|
+
/package-lock\.json$/,
|
|
39
|
+
];
|
|
40
|
+
/** Known exceptions — files where .ID === is comparing non-UUID values (e.g., numeric IDs, string enum values) */
|
|
41
|
+
const KNOWN_EXCEPTIONS = {
|
|
42
|
+
// Add file paths (relative to packages/) and the reason they're excepted
|
|
43
|
+
// Example: 'SomePackage/src/file.ts': ['Uses numeric IDs, not UUIDs'],
|
|
44
|
+
};
|
|
45
|
+
function shouldScanFile(filePath) {
|
|
46
|
+
if (!filePath.endsWith('.ts'))
|
|
47
|
+
return false;
|
|
48
|
+
return !EXCLUDE_PATTERNS.some(pattern => pattern.test(filePath));
|
|
49
|
+
}
|
|
50
|
+
function findTsFiles(dir) {
|
|
51
|
+
const results = [];
|
|
52
|
+
if (!fs.existsSync(dir))
|
|
53
|
+
return results;
|
|
54
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
55
|
+
for (const entry of entries) {
|
|
56
|
+
const fullPath = path.join(dir, entry.name);
|
|
57
|
+
if (entry.isDirectory()) {
|
|
58
|
+
if (entry.name === 'node_modules' || entry.name === 'dist' || entry.name === '.git') {
|
|
59
|
+
continue; // Skip these directories entirely for performance
|
|
60
|
+
}
|
|
61
|
+
results.push(...findTsFiles(fullPath));
|
|
62
|
+
}
|
|
63
|
+
else if (shouldScanFile(fullPath)) {
|
|
64
|
+
results.push(fullPath);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return results;
|
|
68
|
+
}
|
|
69
|
+
function scanFileForViolations(filePath) {
|
|
70
|
+
const violations = [];
|
|
71
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
72
|
+
const lines = content.split('\n');
|
|
73
|
+
// Check if file is in known exceptions
|
|
74
|
+
const relativePath = path.relative(SCAN_ROOT, filePath);
|
|
75
|
+
if (KNOWN_EXCEPTIONS[relativePath]) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
for (let i = 0; i < lines.length; i++) {
|
|
79
|
+
const line = lines[i];
|
|
80
|
+
const trimmed = line.trim();
|
|
81
|
+
// Skip comments
|
|
82
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*')) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
// Skip import lines
|
|
86
|
+
if (trimmed.startsWith('import ')) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
for (const pattern of ANTI_PATTERNS) {
|
|
90
|
+
if (pattern.test(line)) {
|
|
91
|
+
// Additional filter: skip comparisons with empty string '', string literals, null, undefined, or type checks
|
|
92
|
+
if (/\.ID\s*[!=]==?\s*''/.test(line) || /[!=]==?\s*''/.test(line))
|
|
93
|
+
continue; // Comparing to empty string
|
|
94
|
+
if (/\.ID\s*[!=]==?\s*['"]/.test(line))
|
|
95
|
+
continue; // Comparing to any string literal
|
|
96
|
+
if (/[!=]==?\s*['"]/.test(line) && /\.ID\b/.test(line))
|
|
97
|
+
continue; // String literal comparison involving .ID
|
|
98
|
+
if (/typeof\s+\w+\.ID\s*===/.test(line))
|
|
99
|
+
continue; // typeof check
|
|
100
|
+
if (/\.ID\s*===\s*null\b/.test(line) || /\.ID\s*===\s*undefined\b/.test(line))
|
|
101
|
+
continue; // null/undefined check
|
|
102
|
+
if (/\.ID\s*!==\s*null\b/.test(line) || /\.ID\s*!==\s*undefined\b/.test(line))
|
|
103
|
+
continue; // negated null/undefined check
|
|
104
|
+
violations.push({
|
|
105
|
+
file: relativePath,
|
|
106
|
+
line: i + 1,
|
|
107
|
+
content: trimmed.substring(0, 120),
|
|
108
|
+
pattern: pattern.source,
|
|
109
|
+
});
|
|
110
|
+
break; // One violation per line is enough
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return violations;
|
|
115
|
+
}
|
|
116
|
+
describe('UUID Comparison Compliance', () => {
|
|
117
|
+
it('should not have direct UUID comparisons (=== / !==) in source files', () => {
|
|
118
|
+
const tsFiles = findTsFiles(SCAN_ROOT);
|
|
119
|
+
const allViolations = [];
|
|
120
|
+
for (const file of tsFiles) {
|
|
121
|
+
allViolations.push(...scanFileForViolations(file));
|
|
122
|
+
}
|
|
123
|
+
if (allViolations.length > 0) {
|
|
124
|
+
const report = allViolations
|
|
125
|
+
.map(v => ` ${v.file}:${v.line}: ${v.content}`)
|
|
126
|
+
.join('\n');
|
|
127
|
+
expect.fail(`Found ${allViolations.length} direct UUID comparison(s) that should use UUIDsEqual():\n${report}\n\n` +
|
|
128
|
+
`Fix by replacing:\n` +
|
|
129
|
+
` - 'x.ID === y' with 'UUIDsEqual(x.ID, y)'\n` +
|
|
130
|
+
` - 'x.ID !== y' with '!UUIDsEqual(x.ID, y)'\n` +
|
|
131
|
+
` - 'arr.includes(x.ID)' with 'arr.some(id => UUIDsEqual(id, x.ID))'\n` +
|
|
132
|
+
`Import UUIDsEqual from '@memberjunction/global'.\n` +
|
|
133
|
+
`If a comparison is NOT a UUID (e.g., numeric ID), add it to KNOWN_EXCEPTIONS in this test file.`);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
//# sourceMappingURL=UUIDCompliance.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UUIDCompliance.test.js","sourceRoot":"","sources":["../../src/__tests__/UUIDCompliance.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UUIDUtils.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/UUIDUtils.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { NormalizeUUID, UUIDsEqual } from '../util/UUIDUtils.js';
|
|
3
|
+
describe('NormalizeUUID', () => {
|
|
4
|
+
it('should lowercase an uppercase UUID (SQL Server format)', () => {
|
|
5
|
+
expect(NormalizeUUID('A1B2C3D4-E5F6-7890-ABCD-EF1234567890'))
|
|
6
|
+
.toBe('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
|
|
7
|
+
});
|
|
8
|
+
it('should pass through a lowercase UUID unchanged (PostgreSQL format)', () => {
|
|
9
|
+
expect(NormalizeUUID('a1b2c3d4-e5f6-7890-abcd-ef1234567890'))
|
|
10
|
+
.toBe('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
|
|
11
|
+
});
|
|
12
|
+
it('should handle mixed-case UUIDs', () => {
|
|
13
|
+
expect(NormalizeUUID('A1b2C3d4-E5f6-7890-AbCd-Ef1234567890'))
|
|
14
|
+
.toBe('a1b2c3d4-e5f6-7890-abcd-ef1234567890');
|
|
15
|
+
});
|
|
16
|
+
it('should trim whitespace', () => {
|
|
17
|
+
expect(NormalizeUUID(' A1B2C3D4 ')).toBe('a1b2c3d4');
|
|
18
|
+
});
|
|
19
|
+
it('should return empty string for null', () => {
|
|
20
|
+
expect(NormalizeUUID(null)).toBe('');
|
|
21
|
+
});
|
|
22
|
+
it('should return empty string for undefined', () => {
|
|
23
|
+
expect(NormalizeUUID(undefined)).toBe('');
|
|
24
|
+
});
|
|
25
|
+
it('should return empty string for whitespace-only input', () => {
|
|
26
|
+
expect(NormalizeUUID(' ')).toBe('');
|
|
27
|
+
});
|
|
28
|
+
it('should handle empty string', () => {
|
|
29
|
+
expect(NormalizeUUID('')).toBe('');
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
describe('UUIDsEqual', () => {
|
|
33
|
+
const upperUUID = 'A1B2C3D4-E5F6-7890-ABCD-EF1234567890';
|
|
34
|
+
const lowerUUID = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';
|
|
35
|
+
it('should consider SQL Server (uppercase) and PostgreSQL (lowercase) UUIDs equal', () => {
|
|
36
|
+
expect(UUIDsEqual(upperUUID, lowerUUID)).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
it('should consider identical uppercase UUIDs equal', () => {
|
|
39
|
+
expect(UUIDsEqual(upperUUID, upperUUID)).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
it('should consider identical lowercase UUIDs equal', () => {
|
|
42
|
+
expect(UUIDsEqual(lowerUUID, lowerUUID)).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
it('should return false for different UUIDs', () => {
|
|
45
|
+
expect(UUIDsEqual('A1B2C3D4-0000-0000-0000-000000000000', 'A1B2C3D4-0000-0000-0000-000000000001')).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
it('should consider two nulls equal', () => {
|
|
48
|
+
expect(UUIDsEqual(null, null)).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
it('should consider two undefineds equal', () => {
|
|
51
|
+
expect(UUIDsEqual(undefined, undefined)).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
it('should consider null and undefined equal', () => {
|
|
54
|
+
expect(UUIDsEqual(null, undefined)).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
it('should return false for null vs non-null', () => {
|
|
57
|
+
expect(UUIDsEqual(null, lowerUUID)).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
it('should return false for non-null vs null', () => {
|
|
60
|
+
expect(UUIDsEqual(upperUUID, null)).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
it('should return false for undefined vs non-undefined', () => {
|
|
63
|
+
expect(UUIDsEqual(undefined, lowerUUID)).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
it('should handle UUIDs with surrounding whitespace', () => {
|
|
66
|
+
expect(UUIDsEqual(' ' + upperUUID + ' ', lowerUUID)).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
it('should handle mixed-case comparison', () => {
|
|
69
|
+
expect(UUIDsEqual('AbCd1234', 'aBcD1234')).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
it('should handle empty strings as equal', () => {
|
|
72
|
+
expect(UUIDsEqual('', '')).toBe(true);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=UUIDUtils.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UUIDUtils.test.js","sourceRoot":"","sources":["../../src/__tests__/UUIDUtils.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export * from './BaseSingleton.js';
|
|
|
6
6
|
export * from './DeepDiff.js';
|
|
7
7
|
export * from './ClassUtils.js';
|
|
8
8
|
export * from './util/PatternUtils.js';
|
|
9
|
+
export * from './util/UUIDUtils.js';
|
|
9
10
|
export * from './ValidationTypes.js';
|
|
10
11
|
export * from './JSONValidator.js';
|
|
11
12
|
export * from './SafeExpressionEvaluator.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,2BAA2B,CAAA;AACzC,cAAc,0BAA0B,CAAA;AACxC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AAMjC,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,wBAAwB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,2BAA2B,CAAA;AACzC,cAAc,0BAA0B,CAAA;AACxC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AAMjC,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,wBAAwB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export * from './BaseSingleton.js';
|
|
|
7
7
|
export * from './DeepDiff.js';
|
|
8
8
|
export * from './ClassUtils.js';
|
|
9
9
|
export * from './util/PatternUtils.js';
|
|
10
|
+
export * from './util/UUIDUtils.js';
|
|
10
11
|
export * from './ValidationTypes.js';
|
|
11
12
|
export * from './JSONValidator.js';
|
|
12
13
|
export * from './SafeExpressionEvaluator.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,2BAA2B,CAAA;AACzC,cAAc,0BAA0B,CAAA;AACxC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AAEjC,2DAA2D;AAC3D,oCAAoC;AAEpC,0BAA0B;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,wBAAwB,CAAA;AAEtC,6DAA6D;AAC7D,oCAAoC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,2BAA2B,CAAA;AACzC,cAAc,0BAA0B,CAAA;AACxC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AAEjC,2DAA2D;AAC3D,oCAAoC;AAEpC,0BAA0B;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,wBAAwB,CAAA;AAEtC,6DAA6D;AAC7D,oCAAoC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview UUID comparison utility functions for MemberJunction
|
|
3
|
+
*
|
|
4
|
+
* Provides case-insensitive UUID comparison to handle the difference between
|
|
5
|
+
* SQL Server (returns UUIDs in UPPERCASE) and PostgreSQL (returns UUIDs in lowercase).
|
|
6
|
+
* These utilities ensure consistent UUID handling across all database platforms.
|
|
7
|
+
*
|
|
8
|
+
* @module @memberjunction/global/UUIDUtils
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Normalizes a UUID string for consistent comparison by trimming whitespace
|
|
12
|
+
* and converting to lowercase. Returns an empty string for null/undefined input.
|
|
13
|
+
*
|
|
14
|
+
* @param uuid - The UUID string to normalize
|
|
15
|
+
* @returns The normalized (lowercased, trimmed) UUID string, or empty string if input is nullish
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* NormalizeUUID('A1B2C3D4-E5F6-7890-ABCD-EF1234567890')
|
|
19
|
+
* // Returns: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
|
|
20
|
+
*
|
|
21
|
+
* NormalizeUUID(null) // Returns: ''
|
|
22
|
+
* NormalizeUUID(' A1B2C3D4 ') // Returns: 'a1b2c3d4'
|
|
23
|
+
*/
|
|
24
|
+
export declare function NormalizeUUID(uuid: string | null | undefined): string;
|
|
25
|
+
/**
|
|
26
|
+
* Performs a case-insensitive comparison of two UUID strings.
|
|
27
|
+
* Handles null/undefined gracefully — two nullish values are considered equal,
|
|
28
|
+
* but a nullish value is never equal to a non-nullish value.
|
|
29
|
+
*
|
|
30
|
+
* @param uuid1 - First UUID to compare
|
|
31
|
+
* @param uuid2 - Second UUID to compare
|
|
32
|
+
* @returns true if the UUIDs are equal (case-insensitive), false otherwise
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // Cross-platform comparison (SQL Server uppercase vs PostgreSQL lowercase)
|
|
36
|
+
* UUIDsEqual('A1B2C3D4-E5F6-7890-ABCD-EF1234567890',
|
|
37
|
+
* 'a1b2c3d4-e5f6-7890-abcd-ef1234567890') // true
|
|
38
|
+
*
|
|
39
|
+
* UUIDsEqual(null, null) // true
|
|
40
|
+
* UUIDsEqual(null, 'some-id') // false
|
|
41
|
+
* UUIDsEqual('abc', 'ABC') // true
|
|
42
|
+
*/
|
|
43
|
+
export declare function UUIDsEqual(uuid1: string | null | undefined, uuid2: string | null | undefined): boolean;
|
|
44
|
+
//# sourceMappingURL=UUIDUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UUIDUtils.d.ts","sourceRoot":"","sources":["../../src/util/UUIDUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGrE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAItG"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview UUID comparison utility functions for MemberJunction
|
|
3
|
+
*
|
|
4
|
+
* Provides case-insensitive UUID comparison to handle the difference between
|
|
5
|
+
* SQL Server (returns UUIDs in UPPERCASE) and PostgreSQL (returns UUIDs in lowercase).
|
|
6
|
+
* These utilities ensure consistent UUID handling across all database platforms.
|
|
7
|
+
*
|
|
8
|
+
* @module @memberjunction/global/UUIDUtils
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Normalizes a UUID string for consistent comparison by trimming whitespace
|
|
12
|
+
* and converting to lowercase. Returns an empty string for null/undefined input.
|
|
13
|
+
*
|
|
14
|
+
* @param uuid - The UUID string to normalize
|
|
15
|
+
* @returns The normalized (lowercased, trimmed) UUID string, or empty string if input is nullish
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* NormalizeUUID('A1B2C3D4-E5F6-7890-ABCD-EF1234567890')
|
|
19
|
+
* // Returns: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
|
|
20
|
+
*
|
|
21
|
+
* NormalizeUUID(null) // Returns: ''
|
|
22
|
+
* NormalizeUUID(' A1B2C3D4 ') // Returns: 'a1b2c3d4'
|
|
23
|
+
*/
|
|
24
|
+
export function NormalizeUUID(uuid) {
|
|
25
|
+
if (uuid == null)
|
|
26
|
+
return '';
|
|
27
|
+
return uuid.trim().toLowerCase();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Performs a case-insensitive comparison of two UUID strings.
|
|
31
|
+
* Handles null/undefined gracefully — two nullish values are considered equal,
|
|
32
|
+
* but a nullish value is never equal to a non-nullish value.
|
|
33
|
+
*
|
|
34
|
+
* @param uuid1 - First UUID to compare
|
|
35
|
+
* @param uuid2 - Second UUID to compare
|
|
36
|
+
* @returns true if the UUIDs are equal (case-insensitive), false otherwise
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* // Cross-platform comparison (SQL Server uppercase vs PostgreSQL lowercase)
|
|
40
|
+
* UUIDsEqual('A1B2C3D4-E5F6-7890-ABCD-EF1234567890',
|
|
41
|
+
* 'a1b2c3d4-e5f6-7890-abcd-ef1234567890') // true
|
|
42
|
+
*
|
|
43
|
+
* UUIDsEqual(null, null) // true
|
|
44
|
+
* UUIDsEqual(null, 'some-id') // false
|
|
45
|
+
* UUIDsEqual('abc', 'ABC') // true
|
|
46
|
+
*/
|
|
47
|
+
export function UUIDsEqual(uuid1, uuid2) {
|
|
48
|
+
if (uuid1 == null && uuid2 == null)
|
|
49
|
+
return true;
|
|
50
|
+
if (uuid1 == null || uuid2 == null)
|
|
51
|
+
return false;
|
|
52
|
+
return uuid1.trim().toLowerCase() === uuid2.trim().toLowerCase();
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=UUIDUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UUIDUtils.js","sourceRoot":"","sources":["../../src/util/UUIDUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,aAAa,CAAC,IAA+B;IACzD,IAAI,IAAI,IAAI,IAAI;QAAE,OAAO,EAAE,CAAC;IAC5B,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,UAAU,CAAC,KAAgC,EAAE,KAAgC;IACzF,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAChD,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,KAAK,CAAC;IACjD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACrE,CAAC"}
|
package/package.json
CHANGED