opticedge-cloud-utils 1.1.27 → 1.1.29
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.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/pricecharting.d.ts +18 -0
- package/dist/pricecharting.js +50 -0
- package/package.json +6 -3
- package/src/index.ts +1 -0
- package/src/pricecharting.ts +51 -0
- package/tests/pricecharting.test.ts +75 -0
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ __exportStar(require("./env"), exports);
|
|
|
25
25
|
__exportStar(require("./logger"), exports);
|
|
26
26
|
__exportStar(require("./number"), exports);
|
|
27
27
|
__exportStar(require("./parser"), exports);
|
|
28
|
+
__exportStar(require("./pricecharting"), exports);
|
|
28
29
|
__exportStar(require("./pub"), exports);
|
|
29
30
|
__exportStar(require("./regex"), exports);
|
|
30
31
|
__exportStar(require("./retry"), exports);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type CardParts = {
|
|
2
|
+
name: string;
|
|
3
|
+
number: string | null;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Split a card label into `{ name, number }`.
|
|
7
|
+
*
|
|
8
|
+
* Logic:
|
|
9
|
+
* 1. If `realNumber` (string) is provided — try to find it as a whole token at the END of `input`.
|
|
10
|
+
* Accepts " #123", "# 123", " 123", or "123" at the very end.
|
|
11
|
+
* If found, returns `{ name: <before>, number: realNumber }`.
|
|
12
|
+
* DOES NOT match numeric suffixes that are part of a larger token (e.g. "X123" won't match "123").
|
|
13
|
+
* 2. If `realNumber` is `null` or `undefined`, or not found — fallback:
|
|
14
|
+
* Use the last `#` to split, as in the legacy logic.
|
|
15
|
+
* 3. If no valid number found — returns `{ name: original, number: null }`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function splitNameAndNumber(input: string, realNumber?: string | null): CardParts;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.splitNameAndNumber = splitNameAndNumber;
|
|
4
|
+
const regex_1 = require("./regex");
|
|
5
|
+
/**
|
|
6
|
+
* Split a card label into `{ name, number }`.
|
|
7
|
+
*
|
|
8
|
+
* Logic:
|
|
9
|
+
* 1. If `realNumber` (string) is provided — try to find it as a whole token at the END of `input`.
|
|
10
|
+
* Accepts " #123", "# 123", " 123", or "123" at the very end.
|
|
11
|
+
* If found, returns `{ name: <before>, number: realNumber }`.
|
|
12
|
+
* DOES NOT match numeric suffixes that are part of a larger token (e.g. "X123" won't match "123").
|
|
13
|
+
* 2. If `realNumber` is `null` or `undefined`, or not found — fallback:
|
|
14
|
+
* Use the last `#` to split, as in the legacy logic.
|
|
15
|
+
* 3. If no valid number found — returns `{ name: original, number: null }`.
|
|
16
|
+
*/
|
|
17
|
+
function splitNameAndNumber(input, realNumber) {
|
|
18
|
+
const s = (input ?? '').trim();
|
|
19
|
+
if (!s)
|
|
20
|
+
return { name: '', number: null };
|
|
21
|
+
// 1) Try realNumber match at the end (if provided)
|
|
22
|
+
if (realNumber) {
|
|
23
|
+
const rn = String(realNumber).trim();
|
|
24
|
+
if (rn !== '') {
|
|
25
|
+
const escaped = (0, regex_1.escapeForRegex)(rn);
|
|
26
|
+
// require either start-of-string or a separator (# or whitespace) before the number,
|
|
27
|
+
// and anchor to the end to ensure it's at the end of the input.
|
|
28
|
+
// Examples matched: "... #123", "... # 123", "... 123", "...123" (if preceded by whitespace or start)
|
|
29
|
+
const re = new RegExp(`(?:^|[\\s#])${escaped}\\s*$`, 'i');
|
|
30
|
+
const match = re.exec(s);
|
|
31
|
+
if (match) {
|
|
32
|
+
// match.index points at start of the (?:^|[\s#]) group
|
|
33
|
+
let namePart = s.slice(0, match.index);
|
|
34
|
+
// remove trailing separators (# and whitespace) that preceded the number
|
|
35
|
+
namePart = namePart.replace(/[#\s]+$/g, '').trim();
|
|
36
|
+
return { name: namePart, number: rn };
|
|
37
|
+
}
|
|
38
|
+
// else fall through to fallback
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// 2) Fallback: use last "#" style split (legacy behaviour)
|
|
42
|
+
const idx = s.lastIndexOf('#');
|
|
43
|
+
if (idx === -1)
|
|
44
|
+
return { name: s, number: null };
|
|
45
|
+
const namePart = s.slice(0, idx).trim();
|
|
46
|
+
const numberPart = s.slice(idx + 1).trim();
|
|
47
|
+
if (numberPart === '')
|
|
48
|
+
return { name: s, number: null };
|
|
49
|
+
return { name: namePart, number: numberPart };
|
|
50
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opticedge-cloud-utils",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.29",
|
|
4
4
|
"description": "Common utilities for cloud functions",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -20,8 +20,7 @@
|
|
|
20
20
|
"@google-cloud/secret-manager": "^6.0.1",
|
|
21
21
|
"@google-cloud/tasks": "^6.1.0",
|
|
22
22
|
"axios": "^1.10.0",
|
|
23
|
-
"google-auth-library": "^9.15.1"
|
|
24
|
-
"mongodb": "^7.0.0"
|
|
23
|
+
"google-auth-library": "^9.15.1"
|
|
25
24
|
},
|
|
26
25
|
"devDependencies": {
|
|
27
26
|
"@google-cloud/functions-framework": "^4.0.0",
|
|
@@ -34,8 +33,12 @@
|
|
|
34
33
|
"eslint-plugin-jest": "^28.11.1",
|
|
35
34
|
"eslint-plugin-prettier": "^5.4.0",
|
|
36
35
|
"jest": "^29.7.0",
|
|
36
|
+
"mongodb": "*",
|
|
37
37
|
"prettier": "^3.5.3",
|
|
38
38
|
"ts-jest": "^29.3.4",
|
|
39
39
|
"typescript": "^5.8.3"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"mongodb": "^7.1.1"
|
|
40
43
|
}
|
|
41
44
|
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { escapeForRegex } from './regex'
|
|
2
|
+
|
|
3
|
+
type CardParts = { name: string; number: string | null }
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Split a card label into `{ name, number }`.
|
|
7
|
+
*
|
|
8
|
+
* Logic:
|
|
9
|
+
* 1. If `realNumber` (string) is provided — try to find it as a whole token at the END of `input`.
|
|
10
|
+
* Accepts " #123", "# 123", " 123", or "123" at the very end.
|
|
11
|
+
* If found, returns `{ name: <before>, number: realNumber }`.
|
|
12
|
+
* DOES NOT match numeric suffixes that are part of a larger token (e.g. "X123" won't match "123").
|
|
13
|
+
* 2. If `realNumber` is `null` or `undefined`, or not found — fallback:
|
|
14
|
+
* Use the last `#` to split, as in the legacy logic.
|
|
15
|
+
* 3. If no valid number found — returns `{ name: original, number: null }`.
|
|
16
|
+
*/
|
|
17
|
+
export function splitNameAndNumber(input: string, realNumber?: string | null): CardParts {
|
|
18
|
+
const s = (input ?? '').trim()
|
|
19
|
+
if (!s) return { name: '', number: null }
|
|
20
|
+
|
|
21
|
+
// 1) Try realNumber match at the end (if provided)
|
|
22
|
+
if (realNumber) {
|
|
23
|
+
const rn = String(realNumber).trim()
|
|
24
|
+
if (rn !== '') {
|
|
25
|
+
const escaped = escapeForRegex(rn)
|
|
26
|
+
// require either start-of-string or a separator (# or whitespace) before the number,
|
|
27
|
+
// and anchor to the end to ensure it's at the end of the input.
|
|
28
|
+
// Examples matched: "... #123", "... # 123", "... 123", "...123" (if preceded by whitespace or start)
|
|
29
|
+
const re = new RegExp(`(?:^|[\\s#])${escaped}\\s*$`, 'i')
|
|
30
|
+
const match = re.exec(s)
|
|
31
|
+
if (match) {
|
|
32
|
+
// match.index points at start of the (?:^|[\s#]) group
|
|
33
|
+
let namePart = s.slice(0, match.index)
|
|
34
|
+
// remove trailing separators (# and whitespace) that preceded the number
|
|
35
|
+
namePart = namePart.replace(/[#\s]+$/g, '').trim()
|
|
36
|
+
return { name: namePart, number: rn }
|
|
37
|
+
}
|
|
38
|
+
// else fall through to fallback
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 2) Fallback: use last "#" style split (legacy behaviour)
|
|
43
|
+
const idx = s.lastIndexOf('#')
|
|
44
|
+
if (idx === -1) return { name: s, number: null }
|
|
45
|
+
|
|
46
|
+
const namePart = s.slice(0, idx).trim()
|
|
47
|
+
const numberPart = s.slice(idx + 1).trim()
|
|
48
|
+
if (numberPart === '') return { name: s, number: null }
|
|
49
|
+
|
|
50
|
+
return { name: namePart, number: numberPart }
|
|
51
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// tests/utils.test.ts
|
|
2
|
+
|
|
3
|
+
import { splitNameAndNumber } from '../src/pricecharting'
|
|
4
|
+
|
|
5
|
+
describe('splitNameAndNumber (legacy fallback and new realNumber param)', () => {
|
|
6
|
+
const legacyCases: Array<[string, { name: string; number: string | null }]> = [
|
|
7
|
+
['Charizard [1st Edition] #4', { name: 'Charizard [1st Edition]', number: '4' }],
|
|
8
|
+
['Pikachu', { name: 'Pikachu', number: null }],
|
|
9
|
+
['Mystery #', { name: 'Mystery #', number: null }], // nothing after '#'
|
|
10
|
+
['#7', { name: '', number: '7' }], // valid number but empty name
|
|
11
|
+
['Name # 123 ', { name: 'Name', number: '123' }], // trims spaces
|
|
12
|
+
['X#Y #42', { name: 'X#Y', number: '42' }], // uses last '#'
|
|
13
|
+
[' ', { name: '', number: null }], // whitespace-only input
|
|
14
|
+
['', { name: '', number: null }] // empty string
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
test.each(legacyCases)('splitNameAndNumber("%s") -> %j (legacy fallback)', (input, expected) => {
|
|
18
|
+
expect(splitNameAndNumber(input)).toEqual(expected)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('does not treat an internal "#" before last as separator', () => {
|
|
22
|
+
const input = 'Foo#bar#999'
|
|
23
|
+
expect(splitNameAndNumber(input)).toEqual({ name: 'Foo#bar', number: '999' })
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('handles undefined / null input gracefully', () => {
|
|
27
|
+
// @ts-expect-error intentional: testing undefined input
|
|
28
|
+
expect(splitNameAndNumber(undefined)).toEqual({ name: '', number: null })
|
|
29
|
+
// @ts-expect-error intentional: testing null input
|
|
30
|
+
expect(splitNameAndNumber(null)).toEqual({ name: '', number: null })
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
// -----------------------
|
|
34
|
+
// New tests for realNumber parameter
|
|
35
|
+
// -----------------------
|
|
36
|
+
const realNumberCases: Array<
|
|
37
|
+
[string, string | null | undefined, { name: string; number: string | null }]
|
|
38
|
+
> = [
|
|
39
|
+
// exact match with trailing "#"
|
|
40
|
+
['test product name #123', '123', { name: 'test product name', number: '123' }],
|
|
41
|
+
|
|
42
|
+
// exact match with trailing plain digits
|
|
43
|
+
['test product name 123', '123', { name: 'test product name', number: '123' }],
|
|
44
|
+
|
|
45
|
+
// realNumber provided and found even when there is a space before the number
|
|
46
|
+
['foo bar # 42', '42', { name: 'foo bar', number: '42' }],
|
|
47
|
+
|
|
48
|
+
// realNumber provided that appears at the end with no '#'
|
|
49
|
+
['Some Card 007', '007', { name: 'Some Card', number: '007' }],
|
|
50
|
+
|
|
51
|
+
// realNumber provided but NOT found as a whole token at end -> fallback to last '#' behavior
|
|
52
|
+
// input ends with "#123abc", realNumber '123' is a suffix of larger token -> fallback to last '#'
|
|
53
|
+
['test product name #123abc', '123', { name: 'test product name', number: '123abc' }],
|
|
54
|
+
|
|
55
|
+
// multiple #'s; realNumber found at end
|
|
56
|
+
['A#B#999', '999', { name: 'A#B', number: '999' }],
|
|
57
|
+
|
|
58
|
+
// realNumber is undefined/null -> fallback behavior (legacy)
|
|
59
|
+
['Charizard [1st Edition] #4', undefined, { name: 'Charizard [1st Edition]', number: '4' }],
|
|
60
|
+
['Charizard [1st Edition] #4', null, { name: 'Charizard [1st Edition]', number: '4' }]
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
test.each(realNumberCases)(
|
|
64
|
+
'splitNameAndNumber("%s", realNumber=%s) -> %j (realNumber cases)',
|
|
65
|
+
(input, realNumber, expected) => {
|
|
66
|
+
expect(splitNameAndNumber(input, realNumber)).toEqual(expected)
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
test('when realNumber is provided but not matched as whole token, fallback applies', () => {
|
|
71
|
+
const input = 'Example #X123'
|
|
72
|
+
// '123' is part of larger token 'X123' -> should FALLBACK and use last '#' -> number = 'X123'
|
|
73
|
+
expect(splitNameAndNumber(input, '123')).toEqual({ name: 'Example', number: 'X123' })
|
|
74
|
+
})
|
|
75
|
+
})
|