@harborclient/sdk 0.4.6 → 0.6.1
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/components/AsyncListState/index.d.ts +85 -0
- package/dist/components/AsyncListState/index.d.ts.map +1 -0
- package/dist/components/AsyncListState/index.js +51 -0
- package/dist/components/BackButton/index.d.ts +32 -0
- package/dist/components/BackButton/index.d.ts.map +1 -0
- package/dist/components/BackButton/index.js +19 -0
- package/dist/components/Badge/index.d.ts +29 -0
- package/dist/components/Badge/index.d.ts.map +1 -0
- package/dist/components/Badge/index.js +32 -0
- package/dist/components/BusyIndicator/index.d.ts +16 -0
- package/dist/components/BusyIndicator/index.d.ts.map +1 -0
- package/dist/components/BusyIndicator/index.js +78 -0
- package/dist/components/Button/index.d.ts +29 -0
- package/dist/components/Button/index.d.ts.map +1 -0
- package/dist/components/Button/index.js +25 -0
- package/dist/components/CodeEditor/config.d.ts +51 -0
- package/dist/components/CodeEditor/config.d.ts.map +1 -0
- package/dist/components/CodeEditor/config.js +64 -0
- package/dist/components/CodeEditor/index.d.ts +77 -0
- package/dist/components/CodeEditor/index.d.ts.map +1 -0
- package/dist/components/CodeEditor/index.js +319 -0
- package/dist/components/CodeEditor/themes.d.ts +19 -0
- package/dist/components/CodeEditor/themes.d.ts.map +1 -0
- package/dist/components/CodeEditor/themes.js +37 -0
- package/dist/components/EmptyState/index.d.ts +26 -0
- package/dist/components/EmptyState/index.d.ts.map +1 -0
- package/dist/components/EmptyState/index.js +25 -0
- package/dist/components/FaIcon/index.d.ts +22 -0
- package/dist/components/FaIcon/index.d.ts.map +1 -0
- package/dist/components/FaIcon/index.js +13 -0
- package/dist/components/FieldError/index.d.ts +39 -0
- package/dist/components/FieldError/index.d.ts.map +1 -0
- package/dist/components/FieldError/index.js +34 -0
- package/dist/components/FooterButton/index.d.ts +30 -0
- package/dist/components/FooterButton/index.d.ts.map +1 -0
- package/dist/components/FooterButton/index.js +19 -0
- package/dist/components/FooterIcon/index.d.ts +32 -0
- package/dist/components/FooterIcon/index.d.ts.map +1 -0
- package/dist/components/FooterIcon/index.js +21 -0
- package/dist/components/FormDataEditor/index.d.ts +31 -0
- package/dist/components/FormDataEditor/index.d.ts.map +1 -0
- package/dist/components/FormDataEditor/index.js +109 -0
- package/dist/components/FormGroup/index.d.ts +75 -0
- package/dist/components/FormGroup/index.d.ts.map +1 -0
- package/dist/components/FormGroup/index.js +95 -0
- package/dist/components/KeyValueEditor/index.d.ts +35 -0
- package/dist/components/KeyValueEditor/index.d.ts.map +1 -0
- package/dist/components/KeyValueEditor/index.js +40 -0
- package/dist/components/MethodSelect/index.d.ts +20 -0
- package/dist/components/MethodSelect/index.d.ts.map +1 -0
- package/dist/components/MethodSelect/index.js +9 -0
- package/dist/components/Modal/ModalFooter.d.ts +25 -0
- package/dist/components/Modal/ModalFooter.d.ts.map +1 -0
- package/dist/components/Modal/ModalFooter.js +13 -0
- package/dist/components/Modal/ModalFormLayout.d.ts +31 -0
- package/dist/components/Modal/ModalFormLayout.d.ts.map +1 -0
- package/dist/components/Modal/ModalFormLayout.js +14 -0
- package/dist/components/Modal/ModalHeader.d.ts +34 -0
- package/dist/components/Modal/ModalHeader.d.ts.map +1 -0
- package/dist/components/Modal/ModalHeader.js +11 -0
- package/dist/components/Modal/index.d.ts +59 -0
- package/dist/components/Modal/index.d.ts.map +1 -0
- package/dist/components/Modal/index.js +37 -0
- package/dist/components/OverlayCloseButton/index.d.ts +25 -0
- package/dist/components/OverlayCloseButton/index.d.ts.map +1 -0
- package/dist/components/OverlayCloseButton/index.js +16 -0
- package/dist/components/OverlayPage/index.d.ts +40 -0
- package/dist/components/OverlayPage/index.d.ts.map +1 -0
- package/dist/components/OverlayPage/index.js +18 -0
- package/dist/components/PageHeader/index.d.ts +31 -0
- package/dist/components/PageHeader/index.d.ts.map +1 -0
- package/dist/components/PageHeader/index.js +12 -0
- package/dist/components/PanelCloseButton/index.d.ts +30 -0
- package/dist/components/PanelCloseButton/index.d.ts.map +1 -0
- package/dist/components/PanelCloseButton/index.js +17 -0
- package/dist/components/Resizable/Resizable.d.ts +48 -0
- package/dist/components/Resizable/Resizable.d.ts.map +1 -0
- package/dist/components/Resizable/Resizable.js +32 -0
- package/dist/components/Resizable/ResizeHandle.d.ts +41 -0
- package/dist/components/Resizable/ResizeHandle.d.ts.map +1 -0
- package/dist/components/Resizable/ResizeHandle.js +17 -0
- package/dist/components/Resizable/footerPanelUtils.d.ts +25 -0
- package/dist/components/Resizable/footerPanelUtils.d.ts.map +1 -0
- package/dist/components/Resizable/footerPanelUtils.js +61 -0
- package/dist/components/Resizable/index.d.ts +4 -0
- package/dist/components/Resizable/index.d.ts.map +1 -0
- package/dist/components/Resizable/index.js +3 -0
- package/dist/components/Resizable/useResizable.d.ts +42 -0
- package/dist/components/Resizable/useResizable.d.ts.map +1 -0
- package/dist/components/Resizable/useResizable.js +151 -0
- package/dist/components/ResourceList/index.d.ts +73 -0
- package/dist/components/ResourceList/index.d.ts.map +1 -0
- package/dist/components/ResourceList/index.js +44 -0
- package/dist/components/RowActionsMenu/index.d.ts +33 -0
- package/dist/components/RowActionsMenu/index.d.ts.map +1 -0
- package/dist/components/RowActionsMenu/index.js +54 -0
- package/dist/components/SegmentedTabs/index.d.ts +107 -0
- package/dist/components/SegmentedTabs/index.d.ts.map +1 -0
- package/dist/components/SegmentedTabs/index.js +111 -0
- package/dist/components/Spinner/index.d.ts +26 -0
- package/dist/components/Spinner/index.d.ts.map +1 -0
- package/dist/components/Spinner/index.js +22 -0
- package/dist/components/StatusMessage/index.d.ts +29 -0
- package/dist/components/StatusMessage/index.d.ts.map +1 -0
- package/dist/components/StatusMessage/index.js +13 -0
- package/dist/components/TabCloseButton/index.d.ts +25 -0
- package/dist/components/TabCloseButton/index.d.ts.map +1 -0
- package/dist/components/TabCloseButton/index.js +13 -0
- package/dist/components/VariableInput/index.d.ts +58 -0
- package/dist/components/VariableInput/index.d.ts.map +1 -0
- package/dist/components/VariableInput/index.js +90 -0
- package/dist/components/VariableTable/index.d.ts +22 -0
- package/dist/components/VariableTable/index.d.ts.map +1 -0
- package/dist/components/VariableTable/index.js +43 -0
- package/dist/components/classes.d.ts +11 -0
- package/dist/components/classes.d.ts.map +1 -0
- package/dist/components/classes.js +14 -0
- package/dist/components/forms/Input.d.ts +22 -0
- package/dist/components/forms/Input.d.ts.map +1 -0
- package/dist/components/forms/Input.js +9 -0
- package/dist/components/forms/Select.d.ts +24 -0
- package/dist/components/forms/Select.d.ts.map +1 -0
- package/dist/components/forms/Select.js +10 -0
- package/dist/components/forms/Textarea.d.ts +22 -0
- package/dist/components/forms/Textarea.d.ts.map +1 -0
- package/dist/components/forms/Textarea.js +8 -0
- package/dist/components/forms/classes.d.ts +24 -0
- package/dist/components/forms/classes.d.ts.map +1 -0
- package/dist/components/forms/classes.js +32 -0
- package/dist/components/forms/index.d.ts +5 -0
- package/dist/components/forms/index.d.ts.map +1 -0
- package/dist/components/forms/index.js +4 -0
- package/dist/components/index.d.ts +51 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +37 -0
- package/dist/components/rowActionsMenuHelpers.d.ts +13 -0
- package/dist/components/rowActionsMenuHelpers.d.ts.map +1 -0
- package/dist/components/rowActionsMenuHelpers.js +29 -0
- package/dist/components/useDialogFocus.d.ts +16 -0
- package/dist/components/useDialogFocus.d.ts.map +1 -0
- package/dist/components/useDialogFocus.js +81 -0
- package/dist/components/utils.d.ts +29 -0
- package/dist/components/utils.d.ts.map +1 -0
- package/dist/components/utils.js +89 -0
- package/dist/components/utils.test.d.ts +2 -0
- package/dist/components/utils.test.d.ts.map +1 -0
- package/dist/components/utils.test.js +27 -0
- package/dist/http/substitute.d.ts.map +1 -1
- package/dist/http/substitute.js +9 -3
- package/dist/http/substitute.test.js +8 -0
- package/dist/main.d.ts +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/runtime/react.d.ts +16 -1
- package/dist/runtime/react.js +40 -0
- package/dist/types.d.ts +168 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/codeEditorSettings.d.ts +29 -0
- package/dist/ui/codeEditorSettings.d.ts.map +1 -0
- package/dist/ui/codeEditorSettings.js +52 -0
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +1 -0
- package/dist/variables/dynamic.d.ts +49 -0
- package/dist/variables/dynamic.d.ts.map +1 -0
- package/dist/variables/dynamic.js +735 -0
- package/dist/variables/dynamic.test.d.ts +2 -0
- package/dist/variables/dynamic.test.d.ts.map +1 -0
- package/dist/variables/dynamic.test.js +60 -0
- package/dist/variables/index.d.ts +3 -0
- package/dist/variables/index.d.ts.map +1 -0
- package/dist/variables/index.js +2 -0
- package/dist/variables/tokens.d.ts +44 -0
- package/dist/variables/tokens.d.ts.map +1 -0
- package/dist/variables/tokens.js +76 -0
- package/dist/variables/tokens.test.d.ts +2 -0
- package/dist/variables/tokens.test.d.ts.map +1 -0
- package/dist/variables/tokens.test.js +115 -0
- package/package.json +75 -14
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dynamic.test.d.ts","sourceRoot":"","sources":["../../src/variables/dynamic.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, expect, it } from '@jest/globals';
|
|
2
|
+
import { DYNAMIC_VARIABLE_CATEGORIES, DYNAMIC_VARIABLE_NAMES, DYNAMIC_VARIABLES, getDynamicVariableDescription, isDynamicVariable, resolveDynamicVariable } from './dynamic.js';
|
|
3
|
+
describe('dynamicVariables', () => {
|
|
4
|
+
it('registers all Postman-style dynamic variable names with $ prefix', () => {
|
|
5
|
+
expect(DYNAMIC_VARIABLE_NAMES.length).toBeGreaterThan(100);
|
|
6
|
+
for (const name of DYNAMIC_VARIABLE_NAMES) {
|
|
7
|
+
expect(name.startsWith('$')).toBe(true);
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
it('generates a non-empty value for every registered dynamic variable', () => {
|
|
11
|
+
for (const name of DYNAMIC_VARIABLE_NAMES) {
|
|
12
|
+
const value = resolveDynamicVariable(name);
|
|
13
|
+
expect(value).toBeDefined();
|
|
14
|
+
expect(value.length).toBeGreaterThan(0);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
it('isDynamicVariable and getDynamicVariableDescription reflect the registry', () => {
|
|
18
|
+
expect(isDynamicVariable('$guid')).toBe(true);
|
|
19
|
+
expect(isDynamicVariable('$randomFirstName')).toBe(true);
|
|
20
|
+
expect(isDynamicVariable('host')).toBe(false);
|
|
21
|
+
expect(isDynamicVariable('$unknownDynamic')).toBe(false);
|
|
22
|
+
expect(getDynamicVariableDescription('$guid')).toBe(DYNAMIC_VARIABLES.$guid.description);
|
|
23
|
+
expect(getDynamicVariableDescription('host')).toBeUndefined();
|
|
24
|
+
});
|
|
25
|
+
it('resolveDynamicVariable returns undefined for unknown keys', () => {
|
|
26
|
+
expect(resolveDynamicVariable('$notARealVariable')).toBeUndefined();
|
|
27
|
+
});
|
|
28
|
+
it('$guid and $randomUUID produce uuid-v4 shaped values', () => {
|
|
29
|
+
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
30
|
+
expect(resolveDynamicVariable('$guid')).toMatch(uuidPattern);
|
|
31
|
+
expect(resolveDynamicVariable('$randomUUID')).toMatch(uuidPattern);
|
|
32
|
+
});
|
|
33
|
+
it('$timestamp returns a numeric unix seconds string', () => {
|
|
34
|
+
const value = resolveDynamicVariable('$timestamp');
|
|
35
|
+
expect(value).toMatch(/^\d+$/);
|
|
36
|
+
const seconds = Number(value);
|
|
37
|
+
expect(seconds).toBeGreaterThan(1_500_000_000);
|
|
38
|
+
expect(seconds).toBeLessThanOrEqual(Math.floor(Date.now() / 1000));
|
|
39
|
+
});
|
|
40
|
+
it('$isoTimestamp returns an ISO-8601 UTC string', () => {
|
|
41
|
+
const value = resolveDynamicVariable('$isoTimestamp');
|
|
42
|
+
expect(value).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/);
|
|
43
|
+
expect(() => new Date(value).toISOString()).not.toThrow();
|
|
44
|
+
});
|
|
45
|
+
it('generates fresh values on each resolve call for random variables', () => {
|
|
46
|
+
const first = resolveDynamicVariable('$randomInt');
|
|
47
|
+
const second = resolveDynamicVariable('$randomInt');
|
|
48
|
+
expect(first).toMatch(/^\d+$/);
|
|
49
|
+
expect(second).toMatch(/^\d+$/);
|
|
50
|
+
});
|
|
51
|
+
it('lists every dynamic variable exactly once across documentation categories', () => {
|
|
52
|
+
const categorized = DYNAMIC_VARIABLE_CATEGORIES.flatMap((category) => category.keys);
|
|
53
|
+
const unique = new Set(categorized);
|
|
54
|
+
expect(categorized.length).toBe(DYNAMIC_VARIABLE_NAMES.length);
|
|
55
|
+
expect(unique.size).toBe(DYNAMIC_VARIABLE_NAMES.length);
|
|
56
|
+
for (const name of DYNAMIC_VARIABLE_NAMES) {
|
|
57
|
+
expect(unique.has(name)).toBe(true);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { DYNAMIC_VARIABLES, DYNAMIC_VARIABLE_CATEGORIES, DYNAMIC_VARIABLE_NAMES, getDynamicVariableDescription, isDynamicVariable, resolveDynamicVariable, type DynamicVariableDefinition } from './dynamic.js';
|
|
2
|
+
export { VARIABLE_NAME_CHARS, VARIABLE_TOKEN_PATTERN, resolveVariable, substituteVariables, tokenizeVariables, type VariableToken } from './tokens.js';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/variables/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,2BAA2B,EAC3B,sBAAsB,EACtB,6BAA6B,EAC7B,iBAAiB,EACjB,sBAAsB,EACtB,KAAK,yBAAyB,EAC/B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { DYNAMIC_VARIABLES, DYNAMIC_VARIABLE_CATEGORIES, DYNAMIC_VARIABLE_NAMES, getDynamicVariableDescription, isDynamicVariable, resolveDynamicVariable } from './dynamic.js';
|
|
2
|
+
export { VARIABLE_NAME_CHARS, VARIABLE_TOKEN_PATTERN, resolveVariable, substituteVariables, tokenizeVariables } from './tokens.js';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Variable } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A segment of text, optionally marking a {{variable}} token.
|
|
4
|
+
*/
|
|
5
|
+
export interface VariableToken {
|
|
6
|
+
text: string;
|
|
7
|
+
key?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Allowed characters inside a `{{variable}}` token name (excluding braces).
|
|
11
|
+
* Includes `$` so Postman-style dynamic names such as `$randomUUID` are recognized.
|
|
12
|
+
*/
|
|
13
|
+
export declare const VARIABLE_NAME_CHARS = "\\w$.-";
|
|
14
|
+
/**
|
|
15
|
+
* Global regex matching `{{variableName}}` placeholders in request text.
|
|
16
|
+
*/
|
|
17
|
+
export declare const VARIABLE_TOKEN_PATTERN: RegExp;
|
|
18
|
+
/**
|
|
19
|
+
* Splits text into plain and {{variable}} segments.
|
|
20
|
+
*
|
|
21
|
+
* @param text - Text containing variable placeholders.
|
|
22
|
+
* @returns Ordered tokens for rendering or further processing.
|
|
23
|
+
*/
|
|
24
|
+
export declare function tokenizeVariables(text: string): VariableToken[];
|
|
25
|
+
/**
|
|
26
|
+
* Resolves a single variable key against collection variables.
|
|
27
|
+
*
|
|
28
|
+
* @param key - Variable name from a {{key}} placeholder.
|
|
29
|
+
* @param variables - Collection-scoped variables.
|
|
30
|
+
* @returns Resolved value, or undefined when the key is not defined.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveVariable(key: string, variables: Variable[]): string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Replaces {{key}} placeholders in text with collection variable values.
|
|
35
|
+
*
|
|
36
|
+
* Static collection/environment variables take precedence over dynamic variables.
|
|
37
|
+
* Unknown tokens are left unchanged.
|
|
38
|
+
*
|
|
39
|
+
* @param text - Text containing variable placeholders.
|
|
40
|
+
* @param variables - Collection-scoped variables.
|
|
41
|
+
* @returns Text with known variables substituted; unknown tokens are left unchanged.
|
|
42
|
+
*/
|
|
43
|
+
export declare function substituteVariables(text: string, variables: Variable[]): string;
|
|
44
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/variables/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,WAAW,CAAC;AAE5C;;GAEG;AACH,eAAO,MAAM,sBAAsB,QAGlC,CAAC;AAgBF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAmB/D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,GAAG,SAAS,CAEtF;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CAY/E"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { resolveDynamicVariable } from './dynamic.js';
|
|
2
|
+
/**
|
|
3
|
+
* Allowed characters inside a `{{variable}}` token name (excluding braces).
|
|
4
|
+
* Includes `$` so Postman-style dynamic names such as `$randomUUID` are recognized.
|
|
5
|
+
*/
|
|
6
|
+
export const VARIABLE_NAME_CHARS = '\\w$.-';
|
|
7
|
+
/**
|
|
8
|
+
* Global regex matching `{{variableName}}` placeholders in request text.
|
|
9
|
+
*/
|
|
10
|
+
export const VARIABLE_TOKEN_PATTERN = new RegExp(`\\{\\{\\s*([${VARIABLE_NAME_CHARS}]+)\\s*\\}\\}`, 'g');
|
|
11
|
+
/**
|
|
12
|
+
* Builds a lookup map from collection variables.
|
|
13
|
+
*
|
|
14
|
+
* @param variables - Collection-scoped variables.
|
|
15
|
+
* @returns Map of trimmed keys to resolved values.
|
|
16
|
+
*/
|
|
17
|
+
function variableLookup(variables) {
|
|
18
|
+
return new Map(variables
|
|
19
|
+
.filter((v) => v.key.trim())
|
|
20
|
+
.map((v) => [v.key.trim(), v.value !== '' ? v.value : v.defaultValue]));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Splits text into plain and {{variable}} segments.
|
|
24
|
+
*
|
|
25
|
+
* @param text - Text containing variable placeholders.
|
|
26
|
+
* @returns Ordered tokens for rendering or further processing.
|
|
27
|
+
*/
|
|
28
|
+
export function tokenizeVariables(text) {
|
|
29
|
+
const tokens = [];
|
|
30
|
+
const pattern = new RegExp(VARIABLE_TOKEN_PATTERN.source, 'g');
|
|
31
|
+
let lastIndex = 0;
|
|
32
|
+
for (const match of text.matchAll(pattern)) {
|
|
33
|
+
const index = match.index ?? 0;
|
|
34
|
+
if (index > lastIndex) {
|
|
35
|
+
tokens.push({ text: text.slice(lastIndex, index) });
|
|
36
|
+
}
|
|
37
|
+
tokens.push({ text: match[0], key: match[1] });
|
|
38
|
+
lastIndex = index + match[0].length;
|
|
39
|
+
}
|
|
40
|
+
if (lastIndex < text.length) {
|
|
41
|
+
tokens.push({ text: text.slice(lastIndex) });
|
|
42
|
+
}
|
|
43
|
+
return tokens;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Resolves a single variable key against collection variables.
|
|
47
|
+
*
|
|
48
|
+
* @param key - Variable name from a {{key}} placeholder.
|
|
49
|
+
* @param variables - Collection-scoped variables.
|
|
50
|
+
* @returns Resolved value, or undefined when the key is not defined.
|
|
51
|
+
*/
|
|
52
|
+
export function resolveVariable(key, variables) {
|
|
53
|
+
return variableLookup(variables).get(key);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Replaces {{key}} placeholders in text with collection variable values.
|
|
57
|
+
*
|
|
58
|
+
* Static collection/environment variables take precedence over dynamic variables.
|
|
59
|
+
* Unknown tokens are left unchanged.
|
|
60
|
+
*
|
|
61
|
+
* @param text - Text containing variable placeholders.
|
|
62
|
+
* @param variables - Collection-scoped variables.
|
|
63
|
+
* @returns Text with known variables substituted; unknown tokens are left unchanged.
|
|
64
|
+
*/
|
|
65
|
+
export function substituteVariables(text, variables) {
|
|
66
|
+
const lookup = variableLookup(variables);
|
|
67
|
+
const pattern = new RegExp(VARIABLE_TOKEN_PATTERN.source, 'g');
|
|
68
|
+
return text.replace(pattern, (match, key) => {
|
|
69
|
+
const value = lookup.get(key);
|
|
70
|
+
if (value !== undefined) {
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
const dynamic = resolveDynamicVariable(key);
|
|
74
|
+
return dynamic !== undefined ? dynamic : match;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.test.d.ts","sourceRoot":"","sources":["../../src/variables/tokens.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { describe, expect, it } from '@jest/globals';
|
|
2
|
+
import { resolveVariable, substituteVariables, tokenizeVariables } from './tokens.js';
|
|
3
|
+
/**
|
|
4
|
+
* Builds a test variable row.
|
|
5
|
+
*
|
|
6
|
+
* @param key - Variable name.
|
|
7
|
+
* @param value - Current value.
|
|
8
|
+
* @param defaultValue - Fallback when value is empty.
|
|
9
|
+
* @param share - Whether the variable is shared on export.
|
|
10
|
+
*/
|
|
11
|
+
const variable = (key, value, defaultValue = '', share = false) => ({
|
|
12
|
+
key,
|
|
13
|
+
value,
|
|
14
|
+
defaultValue,
|
|
15
|
+
share
|
|
16
|
+
});
|
|
17
|
+
describe('substituteVariables', () => {
|
|
18
|
+
it('replaces known variable tokens', () => {
|
|
19
|
+
const result = substituteVariables('https://{{host}}/api/{{version}}', [
|
|
20
|
+
variable('host', 'api.example.com'),
|
|
21
|
+
variable('version', 'v1')
|
|
22
|
+
]);
|
|
23
|
+
expect(result).toBe('https://api.example.com/api/v1');
|
|
24
|
+
});
|
|
25
|
+
it('leaves unknown tokens unchanged', () => {
|
|
26
|
+
const result = substituteVariables('https://{{host}}/{{missing}}', [
|
|
27
|
+
variable('host', 'api.example.com')
|
|
28
|
+
]);
|
|
29
|
+
expect(result).toBe('https://api.example.com/{{missing}}');
|
|
30
|
+
});
|
|
31
|
+
it('substitutes {{ host }} when token key has surrounding whitespace', () => {
|
|
32
|
+
const result = substituteVariables('https://{{ host }}/users', [
|
|
33
|
+
variable('host', 'api.example.com')
|
|
34
|
+
]);
|
|
35
|
+
expect(result).toBe('https://api.example.com/users');
|
|
36
|
+
});
|
|
37
|
+
it('trims variable keys when building the lookup', () => {
|
|
38
|
+
const result = substituteVariables('https://{{host}}', [
|
|
39
|
+
variable(' host ', 'api.example.com')
|
|
40
|
+
]);
|
|
41
|
+
expect(result).toBe('https://api.example.com');
|
|
42
|
+
});
|
|
43
|
+
it('ignores blank-key variables', () => {
|
|
44
|
+
const result = substituteVariables('https://{{host}}', [
|
|
45
|
+
variable(' ', 'ignored.example.com'),
|
|
46
|
+
variable('host', 'api.example.com')
|
|
47
|
+
]);
|
|
48
|
+
expect(result).toBe('https://api.example.com');
|
|
49
|
+
});
|
|
50
|
+
it('falls back to defaultValue when value is empty', () => {
|
|
51
|
+
const result = substituteVariables('https://{{host}}/api', [variable('host', '', 'localhost')]);
|
|
52
|
+
expect(result).toBe('https://localhost/api');
|
|
53
|
+
});
|
|
54
|
+
it('prefers value over defaultValue when both are set', () => {
|
|
55
|
+
const result = substituteVariables('https://{{host}}/api', [
|
|
56
|
+
variable('host', 'api.example.com', 'localhost')
|
|
57
|
+
]);
|
|
58
|
+
expect(result).toBe('https://api.example.com/api');
|
|
59
|
+
});
|
|
60
|
+
it('substitutes variables in collection header values', () => {
|
|
61
|
+
const result = substituteVariables('Bearer {{token}}', [variable('token', 'abc123')]);
|
|
62
|
+
expect(result).toBe('Bearer abc123');
|
|
63
|
+
});
|
|
64
|
+
it('resolves dynamic variables when no static variable is defined', () => {
|
|
65
|
+
const result = substituteVariables('id={{ $guid }}', []);
|
|
66
|
+
expect(result).not.toContain('{{');
|
|
67
|
+
expect(result).toMatch(/^id=[0-9a-f-]{36}$/i);
|
|
68
|
+
});
|
|
69
|
+
it('prefers static variables over dynamic variables with the same key', () => {
|
|
70
|
+
const result = substituteVariables('{{$randomInt}}', [variable('$randomInt', '42')]);
|
|
71
|
+
expect(result).toBe('42');
|
|
72
|
+
});
|
|
73
|
+
it('leaves unknown dynamic-style tokens unchanged', () => {
|
|
74
|
+
const result = substituteVariables('{{$notRegistered}}', []);
|
|
75
|
+
expect(result).toBe('{{$notRegistered}}');
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
describe('tokenizeVariables', () => {
|
|
79
|
+
it('returns a single plain-text token when no variables are present', () => {
|
|
80
|
+
expect(tokenizeVariables('https://api.example.com')).toEqual([
|
|
81
|
+
{ text: 'https://api.example.com' }
|
|
82
|
+
]);
|
|
83
|
+
});
|
|
84
|
+
it('splits text around variable tokens', () => {
|
|
85
|
+
expect(tokenizeVariables('https://{{host}}/api/{{version}}')).toEqual([
|
|
86
|
+
{ text: 'https://' },
|
|
87
|
+
{ text: '{{host}}', key: 'host' },
|
|
88
|
+
{ text: '/api/' },
|
|
89
|
+
{ text: '{{version}}', key: 'version' }
|
|
90
|
+
]);
|
|
91
|
+
});
|
|
92
|
+
it('tokenizeVariables extracts host key from {{ host }} token', () => {
|
|
93
|
+
expect(tokenizeVariables('https://{{ host }}/users')).toEqual([
|
|
94
|
+
{ text: 'https://' },
|
|
95
|
+
{ text: '{{ host }}', key: 'host' },
|
|
96
|
+
{ text: '/users' }
|
|
97
|
+
]);
|
|
98
|
+
});
|
|
99
|
+
it('tokenizeVariables recognizes dynamic variable keys with $ prefix', () => {
|
|
100
|
+
expect(tokenizeVariables('{{$randomUUID}}')).toEqual([
|
|
101
|
+
{ text: '{{$randomUUID}}', key: '$randomUUID' }
|
|
102
|
+
]);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
describe('resolveVariable', () => {
|
|
106
|
+
it('returns the resolved value for a known key', () => {
|
|
107
|
+
expect(resolveVariable('host', [variable('host', 'api.example.com')])).toBe('api.example.com');
|
|
108
|
+
});
|
|
109
|
+
it('falls back to defaultValue when value is empty', () => {
|
|
110
|
+
expect(resolveVariable('host', [variable('host', '', 'localhost')])).toBe('localhost');
|
|
111
|
+
});
|
|
112
|
+
it('returns undefined for unknown keys', () => {
|
|
113
|
+
expect(resolveVariable('missing', [variable('host', 'api.example.com')])).toBeUndefined();
|
|
114
|
+
});
|
|
115
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@harborclient/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "TypeScript SDK for HarborClient plugin development.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"harborclient",
|
|
@@ -22,54 +22,89 @@
|
|
|
22
22
|
"email": "contact@harborclient.com"
|
|
23
23
|
},
|
|
24
24
|
"type": "module",
|
|
25
|
+
"sideEffects": false,
|
|
25
26
|
"types": "./dist/client.d.ts",
|
|
26
27
|
"exports": {
|
|
27
28
|
".": {
|
|
28
29
|
"types": "./dist/client.d.ts",
|
|
29
|
-
"import": "./dist/runtime/index.js"
|
|
30
|
+
"import": "./dist/runtime/index.js",
|
|
31
|
+
"require": "./dist/runtime/index.js",
|
|
32
|
+
"default": "./dist/runtime/index.js"
|
|
30
33
|
},
|
|
31
34
|
"./jsx-runtime": {
|
|
32
35
|
"types": "./dist/runtime/jsx-runtime.d.ts",
|
|
33
|
-
"import": "./dist/runtime/jsx-runtime.js"
|
|
36
|
+
"import": "./dist/runtime/jsx-runtime.js",
|
|
37
|
+
"require": "./dist/runtime/jsx-runtime.js",
|
|
38
|
+
"default": "./dist/runtime/jsx-runtime.js"
|
|
34
39
|
},
|
|
35
40
|
"./jsx-dev-runtime": {
|
|
36
41
|
"types": "./dist/runtime/jsx-dev-runtime.d.ts",
|
|
37
|
-
"import": "./dist/runtime/jsx-dev-runtime.js"
|
|
42
|
+
"import": "./dist/runtime/jsx-dev-runtime.js",
|
|
43
|
+
"require": "./dist/runtime/jsx-dev-runtime.js",
|
|
44
|
+
"default": "./dist/runtime/jsx-dev-runtime.js"
|
|
38
45
|
},
|
|
39
46
|
"./react": {
|
|
40
47
|
"types": "./dist/runtime/react.d.ts",
|
|
41
|
-
"import": "./dist/runtime/react.js"
|
|
48
|
+
"import": "./dist/runtime/react.js",
|
|
49
|
+
"require": "./dist/runtime/react.js",
|
|
50
|
+
"default": "./dist/runtime/react.js"
|
|
42
51
|
},
|
|
43
52
|
"./main": {
|
|
44
53
|
"types": "./dist/main.d.ts"
|
|
45
54
|
},
|
|
46
55
|
"./http": {
|
|
47
56
|
"types": "./dist/http/index.d.ts",
|
|
48
|
-
"import": "./dist/http/index.js"
|
|
57
|
+
"import": "./dist/http/index.js",
|
|
58
|
+
"require": "./dist/http/index.js",
|
|
59
|
+
"default": "./dist/http/index.js"
|
|
60
|
+
},
|
|
61
|
+
"./variables": {
|
|
62
|
+
"types": "./dist/variables/index.d.ts",
|
|
63
|
+
"import": "./dist/variables/index.js",
|
|
64
|
+
"require": "./dist/variables/index.js",
|
|
65
|
+
"default": "./dist/variables/index.js"
|
|
49
66
|
},
|
|
50
67
|
"./ui": {
|
|
51
68
|
"types": "./dist/ui/index.d.ts",
|
|
52
|
-
"import": "./dist/ui/index.js"
|
|
69
|
+
"import": "./dist/ui/index.js",
|
|
70
|
+
"require": "./dist/ui/index.js",
|
|
71
|
+
"default": "./dist/ui/index.js"
|
|
72
|
+
},
|
|
73
|
+
"./components": {
|
|
74
|
+
"types": "./dist/components/index.d.ts",
|
|
75
|
+
"import": "./dist/components/index.js",
|
|
76
|
+
"require": "./dist/components/index.js",
|
|
77
|
+
"default": "./dist/components/index.js"
|
|
53
78
|
},
|
|
54
79
|
"./storage": {
|
|
55
80
|
"types": "./dist/storage/index.d.ts",
|
|
56
|
-
"import": "./dist/storage/index.js"
|
|
81
|
+
"import": "./dist/storage/index.js",
|
|
82
|
+
"require": "./dist/storage/index.js",
|
|
83
|
+
"default": "./dist/storage/index.js"
|
|
57
84
|
},
|
|
58
85
|
"./clipboard": {
|
|
59
86
|
"types": "./dist/clipboard.d.ts",
|
|
60
|
-
"import": "./dist/clipboard.js"
|
|
87
|
+
"import": "./dist/clipboard.js",
|
|
88
|
+
"require": "./dist/clipboard.js",
|
|
89
|
+
"default": "./dist/clipboard.js"
|
|
61
90
|
},
|
|
62
91
|
"./runtime-utils": {
|
|
63
92
|
"types": "./dist/runtime-utils.d.ts",
|
|
64
|
-
"import": "./dist/runtime-utils.js"
|
|
93
|
+
"import": "./dist/runtime-utils.js",
|
|
94
|
+
"require": "./dist/runtime-utils.js",
|
|
95
|
+
"default": "./dist/runtime-utils.js"
|
|
65
96
|
},
|
|
66
97
|
"./store": {
|
|
67
98
|
"types": "./dist/runtime/store.d.ts",
|
|
68
|
-
"import": "./dist/runtime/store.js"
|
|
99
|
+
"import": "./dist/runtime/store.js",
|
|
100
|
+
"require": "./dist/runtime/store.js",
|
|
101
|
+
"default": "./dist/runtime/store.js"
|
|
69
102
|
},
|
|
70
103
|
"./signing": {
|
|
71
104
|
"types": "./dist/signing/index.d.ts",
|
|
72
|
-
"import": "./dist/signing/index.js"
|
|
105
|
+
"import": "./dist/signing/index.js",
|
|
106
|
+
"require": "./dist/signing/index.js",
|
|
107
|
+
"default": "./dist/signing/index.js"
|
|
73
108
|
}
|
|
74
109
|
},
|
|
75
110
|
"bin": {
|
|
@@ -85,10 +120,29 @@
|
|
|
85
120
|
"peerDependencies": {
|
|
86
121
|
"react": ">=18"
|
|
87
122
|
},
|
|
123
|
+
"dependencies": {
|
|
124
|
+
"@codemirror/autocomplete": "^6.20.3",
|
|
125
|
+
"@codemirror/lang-javascript": "^6.2.4",
|
|
126
|
+
"@codemirror/lang-json": "^6.0.2",
|
|
127
|
+
"@codemirror/language": "^6.12.3",
|
|
128
|
+
"@codemirror/legacy-modes": "^6.5.3",
|
|
129
|
+
"@codemirror/state": "^6.6.0",
|
|
130
|
+
"@codemirror/view": "^6.43.1",
|
|
131
|
+
"@faker-js/faker": "^10.5.0",
|
|
132
|
+
"@fortawesome/fontawesome-svg-core": "^7.2.0",
|
|
133
|
+
"@fortawesome/free-solid-svg-icons": "^7.2.0",
|
|
134
|
+
"@fortawesome/react-fontawesome": "^3.3.1",
|
|
135
|
+
"@lezer/highlight": "^1.2.3",
|
|
136
|
+
"@uiw/codemirror-themes-all": "^4.25.10",
|
|
137
|
+
"@uiw/react-codemirror": "^4.25.10"
|
|
138
|
+
},
|
|
88
139
|
"devDependencies": {
|
|
89
140
|
"@braintree/sanitize-url": "^7.1.2",
|
|
90
141
|
"@eslint/js": "^10.0.1",
|
|
91
142
|
"@jest/globals": "^30.4.1",
|
|
143
|
+
"@storybook/addon-docs": "^10.4.6",
|
|
144
|
+
"@storybook/react-vite": "^10.4.6",
|
|
145
|
+
"@tailwindcss/vite": "^4.3.1",
|
|
92
146
|
"@types/node": "^26.0.1",
|
|
93
147
|
"@types/react": "^19.1.2",
|
|
94
148
|
"concurrently": "^8.2.2",
|
|
@@ -101,14 +155,19 @@
|
|
|
101
155
|
"jest": "^30.4.2",
|
|
102
156
|
"mermaid": "^11.15.0",
|
|
103
157
|
"prettier": "^3.8.4",
|
|
158
|
+
"react": "^19.2.7",
|
|
159
|
+
"react-dom": "^19.2.7",
|
|
160
|
+
"storybook": "^10.4.6",
|
|
161
|
+
"tailwindcss": "^4.3.1",
|
|
104
162
|
"ts-jest": "^29.4.11",
|
|
105
163
|
"typescript": "^5.8.3",
|
|
106
164
|
"typescript-eslint": "^8.62.0",
|
|
165
|
+
"vite": "^8.1.0",
|
|
107
166
|
"vitepress": "^1.6.4",
|
|
108
167
|
"vitepress-plugin-mermaid": "^2.0.17"
|
|
109
168
|
},
|
|
110
169
|
"scripts": {
|
|
111
|
-
"build": "tsc && node scripts/copy-runtime.mjs",
|
|
170
|
+
"build": "tsc -p tsconfig.build.json && node scripts/copy-runtime.mjs",
|
|
112
171
|
"format": "prettier --write .",
|
|
113
172
|
"format:check": "prettier --check .",
|
|
114
173
|
"lint": "eslint --cache .",
|
|
@@ -120,7 +179,9 @@
|
|
|
120
179
|
"release:patch": "gh workflow run Release --ref main -f release_type=patch",
|
|
121
180
|
"release:minor": "gh workflow run Release --ref main -f release_type=minor",
|
|
122
181
|
"release:major": "gh workflow run Release --ref main -f release_type=major",
|
|
123
|
-
"
|
|
182
|
+
"storybook": "storybook dev -p 6006",
|
|
183
|
+
"build-storybook": "storybook build -o docs/.vitepress/static/storybook",
|
|
184
|
+
"docs:build": "pnpm docs:build:nav && pnpm build-storybook && vitepress build docs",
|
|
124
185
|
"docs:build:nav": "node scripts/build-docs-nav.mjs && node scripts/assert-docs-slugs.mjs",
|
|
125
186
|
"docs:preview": "pnpm docs:build && vitepress preview docs",
|
|
126
187
|
"docs:serve": "pnpm docs:build:nav && concurrently --kill-others --prefixColors=auto -n nav,vp \"node scripts/watch-docs-nav.mjs\" \"vitepress dev docs\"",
|