dazscript-framework 0.1.15 → 0.1.16

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.
Files changed (82) hide show
  1. package/README.md +365 -93
  2. package/babel.config.js +33 -33
  3. package/dist/babel/trace-babel-plugin.js +243 -243
  4. package/dist/babel/trace-log-babel-plugin.js +164 -164
  5. package/dist/scripts/install-generator.js +185 -185
  6. package/package.json +72 -70
  7. package/src/common/dz-dump.ts +120 -120
  8. package/src/common/log.ts +56 -56
  9. package/src/common/trace.ts +26 -26
  10. package/src/core/action-decorator.ts +15 -15
  11. package/src/core/base-script.ts +30 -30
  12. package/src/core/custom-action.ts +11 -11
  13. package/src/core/global.ts +4 -4
  14. package/src/dialog/basic-dialog.ts +40 -32
  15. package/src/dialog/builders/button-builder.ts +52 -52
  16. package/src/dialog/builders/checkbox-builder.ts +29 -29
  17. package/src/dialog/builders/color-picker-builder.ts +35 -35
  18. package/src/dialog/builders/combo-box-builder.ts +38 -35
  19. package/src/dialog/builders/combo-edit-builder.ts +35 -35
  20. package/src/dialog/builders/dialog-builder.ts +49 -49
  21. package/src/dialog/builders/groupbox-builder.ts +121 -82
  22. package/src/dialog/builders/label-builder.ts +33 -28
  23. package/src/dialog/builders/layout-builder.ts +59 -59
  24. package/src/dialog/builders/line-edit-builder.ts +124 -119
  25. package/src/dialog/builders/list-box-builder.ts +103 -0
  26. package/src/dialog/builders/list-view-builder.ts +396 -328
  27. package/src/dialog/builders/node-selection-builder.ts +55 -55
  28. package/src/dialog/builders/path-combo-box-builder.ts +24 -24
  29. package/src/dialog/builders/popup-menu-builder.ts +46 -46
  30. package/src/dialog/builders/radio-builder.ts +42 -42
  31. package/src/dialog/builders/slider-builder.ts +39 -22
  32. package/src/dialog/builders/splitter-builder.ts +88 -88
  33. package/src/dialog/builders/tab-builder.ts +120 -106
  34. package/src/dialog/builders/widget-builder.ts +136 -124
  35. package/src/dialog/builders/widgets-builder.ts +140 -135
  36. package/src/dialog/input-dialog.ts +30 -27
  37. package/src/dialog/input-validator.ts +8 -8
  38. package/src/dialog/selection-dialog.ts +47 -0
  39. package/src/dialog/shared.ts +8 -8
  40. package/src/helpers/action-helper.ts +214 -81
  41. package/src/helpers/array-helper.ts +170 -145
  42. package/src/helpers/camera-helper.ts +12 -12
  43. package/src/helpers/custom-action-helper.ts +176 -176
  44. package/src/helpers/directory-helper.ts +14 -0
  45. package/src/helpers/file-helper.ts +90 -90
  46. package/src/helpers/http-helper.ts +186 -0
  47. package/src/helpers/input-helper.ts +18 -18
  48. package/src/helpers/list-view-helper.ts +105 -89
  49. package/src/helpers/menu-helper.ts +28 -28
  50. package/src/helpers/message-box-helper.ts +25 -15
  51. package/src/helpers/node-helper.ts +461 -236
  52. package/src/helpers/number-helper.ts +10 -10
  53. package/src/helpers/numeric-property-helper.ts +91 -91
  54. package/src/helpers/object-helper.ts +2 -2
  55. package/src/helpers/pane-helper.ts +28 -20
  56. package/src/helpers/progress-helper.ts +51 -33
  57. package/src/helpers/property-helper.ts +61 -52
  58. package/src/helpers/record-helper.ts +16 -16
  59. package/src/helpers/scene-helper.ts +144 -94
  60. package/src/helpers/script-helper.ts +15 -15
  61. package/src/helpers/skeleton-helper.ts +26 -26
  62. package/src/helpers/splitter-helper.ts +8 -8
  63. package/src/helpers/string-helper.ts +39 -31
  64. package/src/helpers/surface-helper.ts +5 -5
  65. package/src/helpers/undo-helper.ts +8 -8
  66. package/src/helpers/viewport-helper.ts +21 -8
  67. package/src/lib/delayed.ts +38 -38
  68. package/src/lib/dictionary.ts +3 -0
  69. package/src/lib/frame-keys.ts +67 -67
  70. package/src/lib/guid.ts +2 -2
  71. package/src/lib/menu-item.ts +10 -9
  72. package/src/lib/observable.ts +147 -94
  73. package/src/lib/set.ts +50 -25
  74. package/src/lib/settings.ts +112 -104
  75. package/src/lib/tree-node.ts +149 -145
  76. package/src/samples/config.ts +2 -2
  77. package/src/samples/hello-world.dsa.ts +12 -12
  78. package/src/samples/sample-dialog.dsa.ts +51 -51
  79. package/src/samples/sample-dialog.ts +48 -48
  80. package/src/shared/set-keyboard-shortcut.ts +146 -102
  81. package/tsconfig.json +116 -116
  82. package/webpack.config.js +70 -70
@@ -1,11 +1,11 @@
1
- export const tryParse = (input: string): { valid: boolean, value: number } => {
2
- const parsedValue = Number(input);
3
- if (isNaN(parsedValue)) {
4
- return { valid: false, value: 0 }
5
- }
6
- return { valid: true, value: parsedValue }
7
- }
8
-
9
- export const clamp = (value: number, min: number, max: number): number => {
10
- return Math.min(Math.max(value, min), max);
1
+ export const tryParse = (input: string): { valid: boolean, value: number } => {
2
+ const parsedValue = Number(input);
3
+ if (isNaN(parsedValue)) {
4
+ return { valid: false, value: 0 }
5
+ }
6
+ return { valid: true, value: parsedValue }
7
+ }
8
+
9
+ export const clamp = (value: number, min: number, max: number): number => {
10
+ return Math.min(Math.max(value, min), max);
11
11
  }
@@ -1,92 +1,92 @@
1
- import { scene } from '@dsf/core/global';
2
- import { PropertyKey, PropertyKeys } from '@dsf/lib/frame-keys';
3
- import { isNumeric, toFloat } from './property-helper';
4
- import { timeToFrame } from './scene-helper';
5
-
6
- /**
7
- * Adjust the value of the property based on the contribution of property controllers.
8
- * @param property the property to adjust
9
- * @param value the 'final' value desired for the property
10
- * @param time the animation time to adjust the property at or current time if not specified
11
- * @param interpolation the animation interpolation of DzProperty
12
- * @deprecated use adjust instead
13
- */
14
- export const adjustFn = (property: DzFloatProperty | DzIntProperty, value: number, interpolation?: number, time?: DzTime) => {
15
- return () => {
16
- interpolation = interpolation ?? DzProperty.InterpConstant
17
- time = time ?? scene.getTime()
18
- property.setValue(time, property.adjustValue(time, value), interpolation)
19
- };
20
- }
21
-
22
- /**
23
- * Adjust the value of the property based on the contribution of property controllers.
24
- * @param property the property to adjust
25
- * @param value the 'final' value desired for the property
26
- * @param time the animation time to adjust the property at or current time if not specified
27
- * @param interpolation the animation interpolation of DzProperty
28
- */
29
- export const adjust = (property: DzFloatProperty | DzIntProperty, value: number, interpolation?: number, time?: DzTime) => {
30
- interpolation = interpolation ?? DzProperty.InterpConstant
31
- time = time ?? scene.getTime()
32
-
33
- adjustFn(property, value, interpolation, time)()
34
- }
35
-
36
- export const nudge = (property: DzFloatProperty | DzIntProperty, value: number, interpolation?: number, time?: DzTime) => {
37
- interpolation = interpolation ?? DzProperty.InterpConstant
38
- time = time ?? scene.getTime()
39
-
40
- const sensitivity = property.getSensitivity()
41
- adjust(property, property.getValue() + value * sensitivity, interpolation, time)
42
- //property.setValue(time, property.getValue() + value * sensitivity, interpolation)
43
- }
44
-
45
- export const clamp = (property: DzFloatProperty | DzIntProperty, interpolation?: number, time?: DzTime) => {
46
- interpolation = interpolation ?? DzProperty.InterpConstant
47
- time = time ?? scene.getTime()
48
-
49
- property.setIsClamped(true)
50
-
51
- if (property.getRawValue() > property.getMax()) {
52
- property.setValue(time, property.getMax(), interpolation)
53
- }
54
- else if (property.getRawValue() < property.getMin()) {
55
- property.setValue(time, property.getMin(), interpolation)
56
- }
57
-
58
- }
59
-
60
- export const setInterpolation = (property: DzProperty, keyIndex: number, interpolationType: number) => {
61
- toFloat(property)?.setKeyInterpolation(keyIndex, interpolationType)
62
- }
63
-
64
- /**
65
- * Gets a collection of numeric property keys
66
- * @param property the property to get the keys from
67
- * @returns an array of keys
68
- */
69
- export const getKeys = (property: DzNumericProperty): PropertyKeys => {
70
- if (!isNumeric(property)) throw Error(`The property "${property.getLabel()}" is not numeric`)
71
-
72
- const keys: PropertyKey[] = []
73
-
74
- for (let i = 0; i < property.getNumKeys(); i++) {
75
- const key = new PropertyKey()
76
- key.index = i
77
- key.time = property.getKeyTime(i)
78
- key.value = property.getDoubleValue(key.time)
79
- key.frame = timeToFrame(key.time)
80
- keys.push(key)
81
- }
82
-
83
- const keyCollection = new PropertyKeys(keys);
84
-
85
- // This would make frame the index, but it would not be zero based and
86
- // could lead to trouble
87
- // keys.forEach((key) => {
88
- // keyCollection[key.frame] = key
89
- // })
90
-
91
- return keyCollection
1
+ import { scene } from '@dsf/core/global';
2
+ import { PropertyKey, PropertyKeys } from '@dsf/lib/frame-keys';
3
+ import { isNumeric, toFloat } from './property-helper';
4
+ import { timeToFrame } from './scene-helper';
5
+
6
+ /**
7
+ * Adjust the value of the property based on the contribution of property controllers.
8
+ * @param property the property to adjust
9
+ * @param value the 'final' value desired for the property
10
+ * @param time the animation time to adjust the property at or current time if not specified
11
+ * @param interpolation the animation interpolation of DzProperty
12
+ * @deprecated use adjust instead
13
+ */
14
+ export const adjustFn = (property: DzFloatProperty | DzIntProperty | DzBoolProperty, value: number, interpolation?: number, time?: DzTime) => {
15
+ return () => {
16
+ interpolation = interpolation ?? DzProperty.InterpConstant
17
+ time = time ?? scene.getTime()
18
+ property.setValue(time, property.adjustValue(time, value), interpolation)
19
+ };
20
+ }
21
+
22
+ /**
23
+ * Adjust the value of the property based on the contribution of property controllers.
24
+ * @param property the property to adjust
25
+ * @param value the 'final' value desired for the property
26
+ * @param time the animation time to adjust the property at or current time if not specified
27
+ * @param interpolation the animation interpolation of DzProperty
28
+ */
29
+ export const adjust = (property: DzFloatProperty | DzIntProperty | DzBoolProperty, value: number, interpolation?: number, time?: DzTime) => {
30
+ interpolation = interpolation ?? DzProperty.InterpConstant
31
+ time = time ?? scene.getTime()
32
+
33
+ adjustFn(property, value, interpolation, time)()
34
+ }
35
+
36
+ export const nudge = (property: DzFloatProperty | DzIntProperty, value: number, interpolation?: number, time?: DzTime) => {
37
+ interpolation = interpolation ?? DzProperty.InterpConstant
38
+ time = time ?? scene.getTime()
39
+
40
+ const sensitivity = property.getSensitivity()
41
+ adjust(property, property.getValue() + value * sensitivity, interpolation, time)
42
+ //property.setValue(time, property.getValue() + value * sensitivity, interpolation)
43
+ }
44
+
45
+ export const clamp = (property: DzFloatProperty | DzIntProperty, interpolation?: number, time?: DzTime) => {
46
+ interpolation = interpolation ?? DzProperty.InterpConstant
47
+ time = time ?? scene.getTime()
48
+
49
+ property.setIsClamped(true)
50
+
51
+ if (property.getRawValue() > property.getMax()) {
52
+ property.setValue(time, property.getMax(), interpolation)
53
+ }
54
+ else if (property.getRawValue() < property.getMin()) {
55
+ property.setValue(time, property.getMin(), interpolation)
56
+ }
57
+
58
+ }
59
+
60
+ export const setInterpolation = (property: DzProperty, keyIndex: number, interpolationType: number) => {
61
+ toFloat(property)?.setKeyInterpolation(keyIndex, interpolationType)
62
+ }
63
+
64
+ /**
65
+ * Gets a collection of numeric property keys
66
+ * @param property the property to get the keys from
67
+ * @returns an array of keys
68
+ */
69
+ export const getKeys = (property: DzNumericProperty): PropertyKeys => {
70
+ if (!isNumeric(property)) throw Error(`The property "${property.getLabel()}" is not numeric`)
71
+
72
+ const keys: PropertyKey[] = []
73
+
74
+ for (let i = 0; i < property.getNumKeys(); i++) {
75
+ const key = new PropertyKey()
76
+ key.index = i
77
+ key.time = property.getKeyTime(i)
78
+ key.value = property.getDoubleValue(key.time)
79
+ key.frame = timeToFrame(key.time)
80
+ keys.push(key)
81
+ }
82
+
83
+ const keyCollection = new PropertyKeys(keys);
84
+
85
+ // This would make frame the index, but it would not be zero based and
86
+ // could lead to trouble
87
+ // keys.forEach((key) => {
88
+ // keyCollection[key.frame] = key
89
+ // })
90
+
91
+ return keyCollection
92
92
  }
@@ -1,3 +1,3 @@
1
- export const keys = (o: {}): string[] => {
2
- return Object.keys(o)
1
+ export const keys = (o: {}): string[] => {
2
+ return Object.keys(o)
3
3
  }
@@ -1,21 +1,29 @@
1
- import { mainWindow } from '@dsf/core/global'
2
-
3
- const findPane = <T extends DzPane>(className: string): T => {
4
- return mainWindow.getPaneMgr().findPane(className) as T
5
- }
6
-
7
- export const getSmartContentPane = (): DzSmartContentPane => {
8
- return <DzSmartContentPane>findPane("DzSmartContentPane")
9
- }
10
-
11
- export const getSurfacesPane = (): DzSurfacesPane => {
12
- return findPane<DzSurfacesPane>("DzSurfacesPane")
13
- }
14
-
15
- export const getAuxViewPort = (): DzAuxViewportPane => {
16
- return findPane<DzAuxViewportPane>("DzAuxViewportPane")
17
- }
18
-
19
- export const getParametersPane = (): DzParametersPane => {
20
- return findPane<DzParametersPane>("DzParametersPane")
1
+ import { mainWindow } from '@dsf/core/global'
2
+
3
+ const findPane = <T extends DzPane>(className: string): T => {
4
+ return mainWindow.getPaneMgr().findPane(className) as T
5
+ }
6
+
7
+ export const getSmartContentPane = (): DzSmartContentPane => {
8
+ return <DzSmartContentPane>findPane("DzSmartContentPane")
9
+ }
10
+
11
+ export const getSurfacesPane = (): DzSurfacesPane => {
12
+ return findPane<DzSurfacesPane>("DzSurfacesPane")
13
+ }
14
+
15
+ export const getAuxViewPortPane = (): DzAuxViewportPane => {
16
+ return findPane<DzAuxViewportPane>("DzAuxViewportPane")
17
+ }
18
+
19
+ export const getParametersPane = (): DzParametersPane => {
20
+ return findPane<DzParametersPane>("DzParametersPane")
21
+ }
22
+
23
+ export const getParametersPaneNodeEditor = (): DzPropertySideNavHierarchy => {
24
+ return findPane<DzParametersPane>("DzParametersPane")?.getNodeEditor() ?? null
25
+ }
26
+
27
+ export const getPaneNodeEditor = (pane: DzAbstractNodeEditorPane): DzPropertySideNavHierarchy => {
28
+ return pane.getNodeEditor ? pane.getNodeEditor() : null
21
29
  }
@@ -1,34 +1,52 @@
1
- /**
2
- * Displays a progress dialog to the user if one is not already being displayed and starts a progress tracking operation.
3
- * @param info The string to display in the progress dialog as the current description of the operation.
4
- * @param items The items to process
5
- * @param callback The function to run for every item
6
- * @param isCancellable If true, the user is given the option to cancel the operation.
7
- * @param showTimeElapsed If true, the amount of time since the progress operation was started will be displayed in the dialog.
8
- * @param totalSteps The number of progress steps for the operation to be complete.
9
- */
10
- export const progress = <T>(info: string, items: T[], callback: (item: T) => boolean | void, isCancellable: boolean = true, showTimeElapsed: boolean = true, totalSteps?: number) => {
11
- totalSteps = totalSteps ?? items.length;
12
-
13
- startProgress(info, totalSteps, isCancellable, showTimeElapsed);
14
-
15
- for (let item of items) {
16
- if (isCancellable) {
17
- if (progressIsCancelled()) {
18
- break;
19
- } else {
20
- // This is too slow
21
- //if(progress) processEvents();
22
- }
23
- }
24
-
25
- //============
26
- if (callback && callback(item) === false)
27
- return
28
- //============
29
-
30
- stepProgress(1);
31
- }
32
-
33
- finishProgress();
1
+ import { status } from '@dsf/common/log';
2
+
3
+ /**
4
+ * Displays a progress dialog to the user if one is not already being displayed and starts a progress tracking operation.
5
+ * @param info The string to display in the progress dialog as the current description of the operation.
6
+ * @param items The items to process
7
+ * @param callback The function to run for every item
8
+ * @param isCancellable If true, the user is given the option to cancel the operation.
9
+ * @param showTimeElapsed If true, the amount of time since the progress operation was started will be displayed in the dialog.
10
+ * @param totalSteps The number of progress steps for the operation to be complete.
11
+ */
12
+ export const progress = <T>(info: string | string[], items: T[], callback: (item: T) => boolean | void,
13
+ options?: { isCancellable?: boolean, showTimeElapsed?: boolean, totalSteps?: number }) => {
14
+
15
+ options = {
16
+ isCancellable: true,
17
+ showTimeElapsed: true,
18
+ totalSteps: items.length,
19
+ ...options
20
+ };
21
+
22
+ const infoMessage = Array.isArray(info) ? '' : info;
23
+ startProgress(infoMessage, options.totalSteps, options.isCancellable, options.showTimeElapsed);
24
+
25
+ if (Array.isArray(info)) info.forEach(line => status(line));
26
+
27
+ // const total = Math.max(1, options.totalSteps ?? items.length);
28
+ // let lastQuarter = -1; // -1 so first boundary triggers
29
+
30
+ for (let i = 0; i < items.length; i++) {
31
+ // cancellation
32
+ if (options.isCancellable && progressIsCancelled()) {
33
+ processEvents(); // flush once on cancel
34
+ break;
35
+ }
36
+
37
+ // work
38
+ if (callback && callback(items[i]) === false) return;
39
+
40
+ // progress
41
+ stepProgress(1);
42
+
43
+ // 25/50/75/100 checkpoints
44
+ // const quarter = Math.floor(((i + 1) * 2) / total); // 0..4
45
+ // if (quarter > lastQuarter) {
46
+ // processEvents();
47
+ // lastQuarter = quarter;
48
+ // }
49
+ }
50
+
51
+ finishProgress();
34
52
  }
@@ -1,53 +1,62 @@
1
- import { sceneHelper } from '@dsf/core/global'
2
-
3
- /**
4
- * Sets the DzPropertyGroup path (and appropriate geometryregion_dz) for the given property.
5
- * @param property The property to change the path of.
6
- * @param path The new path for the given property.
7
- */
8
- export const setPath = (property: DzProperty, path: string) => {
9
- sceneHelper.setPropertyPath(property, path)
10
- }
11
-
12
- /**
13
- * Get the internal name of property (or its alias target), or “Unknown”.
14
- * @param property
15
- * @returns The internal name of property (or its alias target), or “Unknown”.
16
- */
17
- export const getName = (property: DzProperty): string => {
18
- return sceneHelper.getInternalName(property).valueOf()
19
- }
20
-
21
- /**
22
- * Unlocks a property temporarily and executes the specified callback while it's unlocked
23
- * @param property the property to unlock
24
- * @param then the callback to exectue while the property is unlocked
25
- */
26
- export const unlock = (property: DzProperty, then: (property: DzProperty) => void) => {
27
- let locked = property.isLocked()
28
- if (locked) property.lock(true)
29
- then(property)
30
- if (locked) property.lock(false)
31
- }
32
-
33
- export const isNumeric = (property: DzProperty): boolean => {
34
- return property.inherits('DzNumericProperty')
35
- }
36
-
37
- export const cast = <T extends DzProperty>(property: DzProperty, type: 'DzNumericProperty' | 'DzFloatProperty' | 'DzIntProperty'): T | null => {
38
- return property.inherits(type)
39
- ? property as T
40
- : null
41
- }
42
-
43
- export const toNumeric = (property: DzProperty): DzFloatProperty | DzIntProperty | null => {
44
- return toFloat(property) ?? toInt(property)
45
- }
46
-
47
- export const toFloat = (property: DzProperty): DzFloatProperty | null => {
48
- return cast<DzFloatProperty>(property, 'DzFloatProperty')
49
- }
50
-
51
- export const toInt = (property: DzProperty): DzIntProperty | null => {
52
- return cast<DzIntProperty>(property, 'DzIntProperty')
1
+ import { sceneHelper } from '@dsf/core/global'
2
+
3
+ /**
4
+ * Sets the DzPropertyGroup path (and appropriate geometryregion_dz) for the given property.
5
+ * @param property The property to change the path of.
6
+ * @param path The new path for the given property.
7
+ */
8
+ export const setPath = (property: DzProperty, path: string) => {
9
+ sceneHelper.setPropertyPath(property, path)
10
+ }
11
+
12
+ /**
13
+ * Get the internal name of property (or its alias target), or “Unknown”.
14
+ * @param property
15
+ * @returns The internal name of property (or its alias target), or “Unknown”.
16
+ */
17
+ export const getName = (property: DzProperty): string => {
18
+ return sceneHelper.getInternalName(property).valueOf()
19
+ }
20
+
21
+ export const ensureNameIsUnique = (property: DzProperty): string => {
22
+ const name = getName(property)
23
+ const uniqueName = sceneHelper.getUniqueMorphName(sceneHelper.getNode(property), name)
24
+ if (name !== uniqueName) {
25
+ sceneHelper.setInternalName(property, uniqueName.valueOf())
26
+ }
27
+ return uniqueName.valueOf()
28
+ }
29
+
30
+ /**
31
+ * Unlocks a property temporarily and executes the specified callback while it's unlocked
32
+ * @param property the property to unlock
33
+ * @param then the callback to exectue while the property is unlocked
34
+ */
35
+ export const unlock = (property: DzProperty, then: (property: DzProperty) => void) => {
36
+ let locked = property.isLocked()
37
+ if (locked) property.lock(true)
38
+ then(property)
39
+ if (locked) property.lock(false)
40
+ }
41
+
42
+ export const isNumeric = (property: DzProperty): boolean => {
43
+ return property.inherits('DzNumericProperty')
44
+ }
45
+
46
+ export const cast = <T extends DzProperty>(property: DzProperty, type: 'DzNumericProperty' | 'DzFloatProperty' | 'DzIntProperty'): T | null => {
47
+ return property.inherits(type)
48
+ ? property as T
49
+ : null
50
+ }
51
+
52
+ export const toNumeric = (property: DzProperty): DzFloatProperty | DzIntProperty | null => {
53
+ return toFloat(property) ?? toInt(property)
54
+ }
55
+
56
+ export const toFloat = (property: DzProperty): DzFloatProperty | null => {
57
+ return cast<DzFloatProperty>(property, 'DzFloatProperty')
58
+ }
59
+
60
+ export const toInt = (property: DzProperty): DzIntProperty | null => {
61
+ return cast<DzIntProperty>(property, 'DzIntProperty')
53
62
  }
@@ -1,16 +1,16 @@
1
- function objectEntries(obj: any) {
2
- const ownProps = Object.keys(obj);
3
- let i = ownProps.length;
4
- const result = new Array(i); // preallocate the Array
5
- while (i--) {
6
- result[i] = [ownProps[i], obj[ownProps[i]]];
7
- }
8
- return result;
9
- };
10
-
11
- export function entries<K extends string, T>(
12
- record: Record<K, T[]>
13
- ): Array<[K, T[]]> {
14
- return (objectEntries(record) as Array<[K, T[]]>);
15
- }
16
-
1
+ function objectEntries(obj: any) {
2
+ const ownProps = Object.keys(obj);
3
+ let i = ownProps.length;
4
+ const result = new Array(i); // preallocate the Array
5
+ while (i--) {
6
+ result[i] = [ownProps[i], obj[ownProps[i]]];
7
+ }
8
+ return result;
9
+ };
10
+
11
+ export function entries<K extends string, T>(
12
+ record: Record<K, T[]>
13
+ ): Array<[K, T[]]> {
14
+ return (objectEntries(record) as Array<[K, T[]]>);
15
+ }
16
+