atom.io 0.28.1 → 0.28.2
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/{chunk-6WL4RQMQ.js → chunk-D3ZPRYEW.js} +15 -17
- package/eslint-plugin/dist/index.js +0 -1
- package/eslint-plugin/src/walk.ts +0 -1
- package/internal/dist/index.d.ts +3 -3
- package/internal/dist/index.js +1 -1
- package/internal/src/operation.ts +7 -7
- package/internal/src/selector/create-writable-selector.ts +1 -1
- package/internal/src/set-state/become.ts +1 -3
- package/internal/src/set-state/evict-downstream.ts +2 -2
- package/internal/src/set-state/set-atom.ts +1 -1
- package/internal/src/set-state/set-into-store.ts +1 -1
- package/internal/src/set-state/stow-update.ts +2 -2
- package/internal/src/store/store.ts +1 -1
- package/introspection/dist/index.d.ts +15 -6
- package/introspection/dist/index.js +620 -1
- package/introspection/src/attach-atom-index.ts +5 -6
- package/introspection/src/attach-introspection-states.ts +5 -6
- package/introspection/src/attach-selector-index.ts +6 -7
- package/introspection/src/attach-timeline-family.ts +3 -4
- package/introspection/src/attach-timeline-index.ts +4 -8
- package/introspection/src/attach-transaction-index.ts +4 -8
- package/introspection/src/attach-transaction-logs.ts +4 -8
- package/introspection/src/attach-type-selectors.ts +13 -6
- package/introspection/src/differ.ts +1 -1
- package/introspection/src/index.ts +1 -0
- package/introspection/src/refinery.ts +9 -7
- package/introspection/src/sprawl.ts +42 -0
- package/json/dist/index.d.ts +12 -1
- package/json/dist/index.js +111 -2
- package/json/src/index.ts +29 -0
- package/package.json +8 -8
- package/react-devtools/dist/index.d.ts +159 -2
- package/react-devtools/dist/index.js +260 -663
- package/react-devtools/src/AtomIODevtools.tsx +24 -13
- package/react-devtools/src/StateEditor.tsx +5 -47
- package/react-devtools/src/StateIndex.tsx +15 -9
- package/react-devtools/src/TimelineIndex.tsx +9 -6
- package/react-devtools/src/TransactionIndex.tsx +9 -11
- package/react-devtools/src/elastic-input/ElasticInput.tsx +86 -0
- package/react-devtools/src/elastic-input/NumberInput.tsx +199 -0
- package/react-devtools/src/elastic-input/TextInput.tsx +47 -0
- package/react-devtools/src/elastic-input/index.ts +3 -0
- package/react-devtools/src/error-boundary/DefaultFallback.tsx +49 -0
- package/react-devtools/src/error-boundary/ReactErrorBoundary.tsx +56 -0
- package/react-devtools/src/error-boundary/index.ts +2 -0
- package/react-devtools/src/index.ts +3 -0
- package/react-devtools/src/json-editor/assets/Untitled-1.ai +1436 -2
- package/react-devtools/src/json-editor/assets/data-vis.ai +1548 -1
- package/react-devtools/src/json-editor/comp/json-editor-sketches.ai +1451 -3
- package/react-devtools/src/json-editor/default-components.tsx +101 -0
- package/react-devtools/src/json-editor/developer-interface.tsx +81 -0
- package/react-devtools/src/json-editor/editors-by-type/array-editor.tsx +38 -0
- package/react-devtools/src/json-editor/editors-by-type/non-json.tsx +23 -0
- package/react-devtools/src/json-editor/editors-by-type/object-editor.tsx +128 -0
- package/react-devtools/src/json-editor/editors-by-type/primitive-editors.tsx +73 -0
- package/react-devtools/src/json-editor/editors-by-type/utilities/array-elements.ts +16 -0
- package/react-devtools/src/json-editor/editors-by-type/utilities/cast-json.ts +57 -0
- package/react-devtools/src/json-editor/editors-by-type/utilities/cast-to-json.ts +156 -0
- package/react-devtools/src/json-editor/editors-by-type/utilities/object-properties.ts +106 -0
- package/react-devtools/src/json-editor/index.ts +32 -0
- package/react-devtools/src/json-editor/json-editor-internal.tsx +128 -0
- package/react-devtools/src/json-editor/todo.md +7 -0
- package/react-devtools/src/store.ts +70 -46
- package/dist/chunk-D52JNVER.js +0 -721
- package/dist/chunk-YQ46F5O2.js +0 -95
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { CSSProperties, FC, ReactNode } from "react"
|
|
2
|
+
|
|
3
|
+
import { ErrorBoundary } from "../error-boundary"
|
|
4
|
+
|
|
5
|
+
export type Dict<T> = Record<string, T>
|
|
6
|
+
|
|
7
|
+
export type WrapperComponent<T extends Dict<unknown> = Dict<unknown>> = FC<
|
|
8
|
+
T & { children: ReactNode; testid?: string | undefined }
|
|
9
|
+
>
|
|
10
|
+
|
|
11
|
+
export type WC<T extends Dict<unknown> = Dict<unknown>> = WrapperComponent<T>
|
|
12
|
+
|
|
13
|
+
export type JsonEditorComponents = {
|
|
14
|
+
ErrorBoundary: WC
|
|
15
|
+
|
|
16
|
+
Button: WC<{
|
|
17
|
+
onClick?: () => void
|
|
18
|
+
disabled?: boolean
|
|
19
|
+
}>
|
|
20
|
+
DeleteIcon: FC
|
|
21
|
+
|
|
22
|
+
EditorWrapper: WC<{
|
|
23
|
+
style?: CSSProperties | undefined
|
|
24
|
+
className?: string | undefined
|
|
25
|
+
testid?: string | undefined
|
|
26
|
+
}>
|
|
27
|
+
|
|
28
|
+
ArrayWrapper: WC
|
|
29
|
+
ObjectWrapper: WC
|
|
30
|
+
StringWrapper: WC
|
|
31
|
+
NumberWrapper: WC
|
|
32
|
+
BooleanWrapper: WC
|
|
33
|
+
Null: FC<{ testid?: string | undefined }>
|
|
34
|
+
|
|
35
|
+
MissingPropertyWrapper: WC
|
|
36
|
+
KeyWrapper: WC
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const DEFAULT_JSON_EDITOR_COMPONENTS: JsonEditorComponents = {
|
|
40
|
+
ErrorBoundary: ({ children }) => <ErrorBoundary>{children}</ErrorBoundary>,
|
|
41
|
+
Button: ({ onClick, children, disabled, testid }) => (
|
|
42
|
+
<button
|
|
43
|
+
type="button"
|
|
44
|
+
className="json_editor_button"
|
|
45
|
+
onClick={onClick}
|
|
46
|
+
disabled={disabled}
|
|
47
|
+
data-testid={testid}
|
|
48
|
+
>
|
|
49
|
+
{children}
|
|
50
|
+
</button>
|
|
51
|
+
),
|
|
52
|
+
EditorWrapper: ({ children, className, testid }) => (
|
|
53
|
+
<div
|
|
54
|
+
className={`json_editor` + (className ? ` ${className}` : ``)}
|
|
55
|
+
data-testid={testid}
|
|
56
|
+
>
|
|
57
|
+
{children}
|
|
58
|
+
</div>
|
|
59
|
+
),
|
|
60
|
+
ArrayWrapper: ({ children, testid }) => (
|
|
61
|
+
<div className="json_editor_array" data-testid={testid}>
|
|
62
|
+
{children}
|
|
63
|
+
</div>
|
|
64
|
+
),
|
|
65
|
+
ObjectWrapper: ({ children, testid }) => (
|
|
66
|
+
<div className="json_editor_object" data-testid={testid}>
|
|
67
|
+
{children}
|
|
68
|
+
</div>
|
|
69
|
+
),
|
|
70
|
+
StringWrapper: ({ children, testid }) => (
|
|
71
|
+
<span className="json_editor_string" data-testid={testid}>
|
|
72
|
+
{children}
|
|
73
|
+
</span>
|
|
74
|
+
),
|
|
75
|
+
NumberWrapper: ({ children, testid }) => (
|
|
76
|
+
<span className="json_editor_number" data-testid={testid}>
|
|
77
|
+
{children}
|
|
78
|
+
</span>
|
|
79
|
+
),
|
|
80
|
+
BooleanWrapper: ({ children, testid }) => (
|
|
81
|
+
<span className="json_editor_boolean" data-testid={testid}>
|
|
82
|
+
{children}
|
|
83
|
+
</span>
|
|
84
|
+
),
|
|
85
|
+
Null: ({ testid }) => (
|
|
86
|
+
<span className="json_editor_null" data-testid={testid} />
|
|
87
|
+
),
|
|
88
|
+
DeleteIcon: () => (
|
|
89
|
+
<span className="json_editor_icon json_editor_delete">x</span>
|
|
90
|
+
),
|
|
91
|
+
MissingPropertyWrapper: ({ children, testid }) => (
|
|
92
|
+
<span className="json_editor_missing_property" data-testid={testid}>
|
|
93
|
+
{children}
|
|
94
|
+
</span>
|
|
95
|
+
),
|
|
96
|
+
KeyWrapper: ({ children, testid }) => (
|
|
97
|
+
<span className="json_editor_key" data-testid={testid}>
|
|
98
|
+
{children}
|
|
99
|
+
</span>
|
|
100
|
+
),
|
|
101
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Json, JsonTypes } from "atom.io/json"
|
|
2
|
+
import type { CSSProperties, FC, ReactElement } from "react"
|
|
3
|
+
|
|
4
|
+
import type { JsonEditorComponents } from "./default-components"
|
|
5
|
+
import { DEFAULT_JSON_EDITOR_COMPONENTS } from "./default-components"
|
|
6
|
+
import { ArrayEditor } from "./editors-by-type/array-editor"
|
|
7
|
+
import { ObjectEditor } from "./editors-by-type/object-editor"
|
|
8
|
+
import {
|
|
9
|
+
BooleanEditor,
|
|
10
|
+
NullEditor,
|
|
11
|
+
NumberEditor,
|
|
12
|
+
StringEditor,
|
|
13
|
+
} from "./editors-by-type/primitive-editors"
|
|
14
|
+
import type { JsonEditorProps_INTERNAL } from "./json-editor-internal"
|
|
15
|
+
import { JsonEditor_INTERNAL } from "./json-editor-internal"
|
|
16
|
+
|
|
17
|
+
export const SubEditors: Record<
|
|
18
|
+
keyof JsonTypes,
|
|
19
|
+
FC<JsonEditorProps_INTERNAL<any>>
|
|
20
|
+
> = {
|
|
21
|
+
array: ArrayEditor,
|
|
22
|
+
boolean: BooleanEditor,
|
|
23
|
+
null: NullEditor,
|
|
24
|
+
number: NumberEditor,
|
|
25
|
+
object: ObjectEditor,
|
|
26
|
+
string: StringEditor,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type JsonEditorProps<T> = {
|
|
30
|
+
data: T
|
|
31
|
+
set: (valOrUpdater: T | ((currVal: T) => T)) => void
|
|
32
|
+
name?: string | undefined
|
|
33
|
+
rename?: ((newKey: string) => void) | undefined
|
|
34
|
+
remove?: () => void
|
|
35
|
+
path?: ReadonlyArray<number | string>
|
|
36
|
+
isReadonly?: (path: ReadonlyArray<number | string>) => boolean
|
|
37
|
+
isHidden?: (path: ReadonlyArray<number | string>) => boolean
|
|
38
|
+
className?: string
|
|
39
|
+
style?: CSSProperties
|
|
40
|
+
Header?: FC<{ data: T }>
|
|
41
|
+
Components?: Partial<JsonEditorComponents>
|
|
42
|
+
testid?: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const JsonEditor = <T,>({
|
|
46
|
+
data,
|
|
47
|
+
set,
|
|
48
|
+
name,
|
|
49
|
+
rename,
|
|
50
|
+
remove,
|
|
51
|
+
isReadonly = () => false,
|
|
52
|
+
isHidden = () => false,
|
|
53
|
+
className,
|
|
54
|
+
Header,
|
|
55
|
+
style,
|
|
56
|
+
Components: CustomComponents = {},
|
|
57
|
+
testid,
|
|
58
|
+
}: JsonEditorProps<T>): ReactElement => {
|
|
59
|
+
const Components = {
|
|
60
|
+
...DEFAULT_JSON_EDITOR_COMPONENTS,
|
|
61
|
+
...CustomComponents,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<JsonEditor_INTERNAL
|
|
66
|
+
data={data}
|
|
67
|
+
set={set}
|
|
68
|
+
name={name}
|
|
69
|
+
rename={rename}
|
|
70
|
+
remove={remove}
|
|
71
|
+
path={[]}
|
|
72
|
+
isReadonly={isReadonly}
|
|
73
|
+
isHidden={isHidden}
|
|
74
|
+
className={className}
|
|
75
|
+
Header={Header}
|
|
76
|
+
style={style}
|
|
77
|
+
Components={Components}
|
|
78
|
+
testid={testid}
|
|
79
|
+
/>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Json } from "atom.io/json"
|
|
2
|
+
import type { ReactElement } from "react"
|
|
3
|
+
|
|
4
|
+
import type { JsonEditorProps_INTERNAL } from "../json-editor-internal"
|
|
5
|
+
import { JsonEditor_INTERNAL } from "../json-editor-internal"
|
|
6
|
+
import { makeElementSetters } from "./utilities/array-elements"
|
|
7
|
+
|
|
8
|
+
export const ArrayEditor = ({
|
|
9
|
+
path = [],
|
|
10
|
+
isReadonly = () => false,
|
|
11
|
+
isHidden = () => false,
|
|
12
|
+
data,
|
|
13
|
+
set,
|
|
14
|
+
Components,
|
|
15
|
+
testid,
|
|
16
|
+
}: JsonEditorProps_INTERNAL<Json.Tree.Array>): ReactElement => {
|
|
17
|
+
const setElement = makeElementSetters(data, set)
|
|
18
|
+
return (
|
|
19
|
+
<>
|
|
20
|
+
{data.map((element, index) => {
|
|
21
|
+
const newPath = [...path, index]
|
|
22
|
+
return (
|
|
23
|
+
<JsonEditor_INTERNAL
|
|
24
|
+
key={newPath.join(``)}
|
|
25
|
+
path={newPath}
|
|
26
|
+
isReadonly={isReadonly}
|
|
27
|
+
isHidden={isHidden}
|
|
28
|
+
data={element}
|
|
29
|
+
set={setElement[index]}
|
|
30
|
+
Components={Components}
|
|
31
|
+
className="json_editor_element"
|
|
32
|
+
testid={`${testid}-element-${index}`}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
})}
|
|
36
|
+
</>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ElasticInput } from "../../elastic-input"
|
|
2
|
+
import type { JsonEditorProps } from "../developer-interface"
|
|
3
|
+
|
|
4
|
+
export const NonJsonEditor: React.FC<JsonEditorProps<never>> = ({
|
|
5
|
+
data,
|
|
6
|
+
testid,
|
|
7
|
+
}) => {
|
|
8
|
+
return data === undefined ? (
|
|
9
|
+
<ElasticInput
|
|
10
|
+
disabled
|
|
11
|
+
value="undefined"
|
|
12
|
+
data-testid={`${testid}-undefined`}
|
|
13
|
+
/>
|
|
14
|
+
) : (
|
|
15
|
+
<ElasticInput
|
|
16
|
+
disabled
|
|
17
|
+
value={
|
|
18
|
+
Object.getPrototypeOf(data).constructor.name + ` ` + JSON.stringify(data)
|
|
19
|
+
}
|
|
20
|
+
data-testid={`${testid}-non-json-${Object.getPrototypeOf(data).constructor.name}`}
|
|
21
|
+
/>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { Json } from "atom.io/json"
|
|
2
|
+
import type { FC, ReactElement } from "react"
|
|
3
|
+
import { useRef } from "react"
|
|
4
|
+
|
|
5
|
+
import { ElasticInput } from "../../elastic-input"
|
|
6
|
+
import type { JsonEditorComponents } from "../default-components"
|
|
7
|
+
import type { JsonEditorProps_INTERNAL } from "../json-editor-internal"
|
|
8
|
+
import { JsonEditor_INTERNAL } from "../json-editor-internal"
|
|
9
|
+
import {
|
|
10
|
+
makePropertyCreationInterface,
|
|
11
|
+
makePropertyRecasters,
|
|
12
|
+
makePropertyRemovers,
|
|
13
|
+
makePropertyRenamers,
|
|
14
|
+
makePropertySetters,
|
|
15
|
+
makePropertySorter,
|
|
16
|
+
} from "./utilities/object-properties"
|
|
17
|
+
|
|
18
|
+
export type PropertyAdderProps = {
|
|
19
|
+
addProperty: () => void
|
|
20
|
+
disabled: boolean
|
|
21
|
+
propertyKey: string
|
|
22
|
+
Components: JsonEditorComponents
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const PropertyAdder: FC<PropertyAdderProps> = ({
|
|
26
|
+
addProperty,
|
|
27
|
+
disabled,
|
|
28
|
+
propertyKey,
|
|
29
|
+
Components,
|
|
30
|
+
}) => (
|
|
31
|
+
<Components.MissingPropertyWrapper>
|
|
32
|
+
<ElasticInput disabled defaultValue={propertyKey} />
|
|
33
|
+
{` `}
|
|
34
|
+
<ElasticInput disabled defaultValue="is missing" />
|
|
35
|
+
<Components.Button
|
|
36
|
+
onClick={() => {
|
|
37
|
+
addProperty()
|
|
38
|
+
}}
|
|
39
|
+
disabled={disabled}
|
|
40
|
+
>
|
|
41
|
+
+
|
|
42
|
+
</Components.Button>
|
|
43
|
+
</Components.MissingPropertyWrapper>
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
export const ObjectEditor = <T extends Json.Tree.Object>({
|
|
47
|
+
path = [],
|
|
48
|
+
isReadonly = () => false,
|
|
49
|
+
isHidden = () => false,
|
|
50
|
+
data,
|
|
51
|
+
set,
|
|
52
|
+
Components,
|
|
53
|
+
testid,
|
|
54
|
+
}: JsonEditorProps_INTERNAL<T>): ReactElement => {
|
|
55
|
+
const disabled = isReadonly(path)
|
|
56
|
+
|
|
57
|
+
const stableKeyMap = useRef<Record<keyof T, keyof T>>(
|
|
58
|
+
Object.keys(data).reduce(
|
|
59
|
+
(acc, key: keyof T) => {
|
|
60
|
+
acc[key] = key
|
|
61
|
+
return acc
|
|
62
|
+
},
|
|
63
|
+
{} as Record<keyof T, keyof T>,
|
|
64
|
+
),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
const setProperty = makePropertySetters(data, set)
|
|
68
|
+
const renameProperty = makePropertyRenamers(data, set, stableKeyMap)
|
|
69
|
+
const removeProperty = makePropertyRemovers(data, set)
|
|
70
|
+
const recastProperty = makePropertyRecasters(data, set)
|
|
71
|
+
const sortProperties = makePropertySorter(data, set)
|
|
72
|
+
const makePropertyAdder = makePropertyCreationInterface(data, set)
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<>
|
|
76
|
+
<Components.Button
|
|
77
|
+
testid={`${testid}-sort-properties`}
|
|
78
|
+
onClick={() => {
|
|
79
|
+
sortProperties()
|
|
80
|
+
}}
|
|
81
|
+
disabled={disabled}
|
|
82
|
+
>
|
|
83
|
+
Sort
|
|
84
|
+
</Components.Button>
|
|
85
|
+
<Components.ObjectWrapper>
|
|
86
|
+
<div className="json_editor_properties">
|
|
87
|
+
{Object.keys(data).map((key) => {
|
|
88
|
+
const originalKey = stableKeyMap.current[key]
|
|
89
|
+
const newPath = [...path, key]
|
|
90
|
+
const originalPath = [...path, originalKey]
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<JsonEditor_INTERNAL
|
|
94
|
+
key={originalPath.join(`.`)}
|
|
95
|
+
path={newPath}
|
|
96
|
+
name={key}
|
|
97
|
+
isReadonly={isReadonly}
|
|
98
|
+
isHidden={isHidden}
|
|
99
|
+
data={data[key as keyof T]}
|
|
100
|
+
set={setProperty[key as keyof T]}
|
|
101
|
+
rename={renameProperty[key as keyof T]}
|
|
102
|
+
remove={removeProperty[key as keyof T]}
|
|
103
|
+
recast={recastProperty[key as keyof T]}
|
|
104
|
+
className="json_editor_property"
|
|
105
|
+
Components={Components}
|
|
106
|
+
testid={`${testid}-property-${key}`}
|
|
107
|
+
/>
|
|
108
|
+
)
|
|
109
|
+
})}
|
|
110
|
+
</div>
|
|
111
|
+
{disabled ? (
|
|
112
|
+
<Components.Button disabled testid={`${testid}-add-property`}>
|
|
113
|
+
+
|
|
114
|
+
</Components.Button>
|
|
115
|
+
) : (
|
|
116
|
+
<Components.Button
|
|
117
|
+
testid={`${testid}-add-property`}
|
|
118
|
+
onClick={() => {
|
|
119
|
+
makePropertyAdder(`new_property`, `string`)()
|
|
120
|
+
}}
|
|
121
|
+
>
|
|
122
|
+
+
|
|
123
|
+
</Components.Button>
|
|
124
|
+
)}
|
|
125
|
+
</Components.ObjectWrapper>
|
|
126
|
+
</>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { ReactElement } from "react"
|
|
2
|
+
|
|
3
|
+
import { NumberInput, TextInput } from "../../elastic-input"
|
|
4
|
+
import type { JsonEditorProps_INTERNAL } from "../json-editor-internal"
|
|
5
|
+
|
|
6
|
+
export const BooleanEditor = ({
|
|
7
|
+
data,
|
|
8
|
+
set,
|
|
9
|
+
Components,
|
|
10
|
+
testid,
|
|
11
|
+
}: JsonEditorProps_INTERNAL<boolean>): ReactElement => (
|
|
12
|
+
<Components.BooleanWrapper>
|
|
13
|
+
<input
|
|
14
|
+
data-testid={`${testid}-boolean-input`}
|
|
15
|
+
type="checkbox"
|
|
16
|
+
checked={data}
|
|
17
|
+
onChange={(event) => {
|
|
18
|
+
set(event.target.checked)
|
|
19
|
+
}}
|
|
20
|
+
/>
|
|
21
|
+
</Components.BooleanWrapper>
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
export const NullEditor = ({
|
|
25
|
+
Components,
|
|
26
|
+
testid,
|
|
27
|
+
}: JsonEditorProps_INTERNAL<null>): ReactElement => (
|
|
28
|
+
<Components.Null testid={`${testid}-null`} />
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
export const NumberEditor = ({
|
|
32
|
+
path = [],
|
|
33
|
+
isReadonly = () => false,
|
|
34
|
+
data,
|
|
35
|
+
set,
|
|
36
|
+
Components,
|
|
37
|
+
testid,
|
|
38
|
+
}: JsonEditorProps_INTERNAL<number>): ReactElement => (
|
|
39
|
+
<Components.NumberWrapper>
|
|
40
|
+
<NumberInput
|
|
41
|
+
testid={`${testid}-number-input`}
|
|
42
|
+
value={data}
|
|
43
|
+
set={
|
|
44
|
+
isReadonly(path)
|
|
45
|
+
? undefined
|
|
46
|
+
: (newValue) => {
|
|
47
|
+
set(Number(newValue))
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
autoSize={true}
|
|
51
|
+
/>
|
|
52
|
+
</Components.NumberWrapper>
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
export const StringEditor = ({
|
|
56
|
+
path = [],
|
|
57
|
+
isReadonly = () => false,
|
|
58
|
+
data,
|
|
59
|
+
set,
|
|
60
|
+
Components,
|
|
61
|
+
testid,
|
|
62
|
+
}: JsonEditorProps_INTERNAL<string>): ReactElement => {
|
|
63
|
+
return (
|
|
64
|
+
<Components.StringWrapper>
|
|
65
|
+
<TextInput
|
|
66
|
+
testid={`${testid}-string-input`}
|
|
67
|
+
value={data}
|
|
68
|
+
set={isReadonly(path) ? undefined : set}
|
|
69
|
+
autoSize={true}
|
|
70
|
+
/>
|
|
71
|
+
</Components.StringWrapper>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { become } from "atom.io/internal"
|
|
2
|
+
import type { Json } from "atom.io/json"
|
|
3
|
+
|
|
4
|
+
import type { SetterOrUpdater } from "../.."
|
|
5
|
+
|
|
6
|
+
export const makeElementSetters = <T extends Json.Tree.Array>(
|
|
7
|
+
data: T,
|
|
8
|
+
set: SetterOrUpdater<T>,
|
|
9
|
+
): SetterOrUpdater<T[number]>[] =>
|
|
10
|
+
data.map((value, index) => (newValue) => {
|
|
11
|
+
set((): T => {
|
|
12
|
+
const newData = [...data]
|
|
13
|
+
newData[index] = become(newValue)(value)
|
|
14
|
+
return newData as unknown as T
|
|
15
|
+
})
|
|
16
|
+
})
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Json } from "atom.io/json"
|
|
2
|
+
|
|
3
|
+
export const stringToBoolean = (str: string): boolean => str === `true`
|
|
4
|
+
export const stringToNumber = (str: string): number => Number(str)
|
|
5
|
+
export const stringToArray = (str: string): string[] => str.split(`,`)
|
|
6
|
+
export const stringToObject = (str: string): Json.Tree.Object => {
|
|
7
|
+
try {
|
|
8
|
+
return JSON.parse(str)
|
|
9
|
+
} catch (e) {
|
|
10
|
+
return { [str]: str }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const objectToString = (obj: Json.Tree.Object): string =>
|
|
15
|
+
JSON.stringify(obj)
|
|
16
|
+
export const objectToBoolean = (obj: Json.Tree.Object): boolean =>
|
|
17
|
+
obj.true === true
|
|
18
|
+
export const objectToNumber = (obj: Json.Tree.Object): number =>
|
|
19
|
+
Number(obj.number ?? obj.size ?? obj.count ?? 0)
|
|
20
|
+
export const objectToArray = <T>(
|
|
21
|
+
obj: Json.Tree.Object<string, T>,
|
|
22
|
+
): [key: string, value: T][] => Object.entries(obj)
|
|
23
|
+
|
|
24
|
+
export const booleanToString = (bool: boolean): string => bool.toString()
|
|
25
|
+
export const booleanToNumber = (bool: boolean): number => +bool
|
|
26
|
+
export const booleanToObject = (bool: boolean): Json.Tree.Object => ({
|
|
27
|
+
[bool.toString()]: bool,
|
|
28
|
+
})
|
|
29
|
+
export const booleanToArray = (bool: boolean): boolean[] => [bool]
|
|
30
|
+
|
|
31
|
+
export const numberToString = (num: number): string => num.toString()
|
|
32
|
+
export const numberToBoolean = (num: number): boolean => num === 1
|
|
33
|
+
export const numberToObject = (num: number): Json.Tree.Object => ({
|
|
34
|
+
number: num,
|
|
35
|
+
})
|
|
36
|
+
export const numberToArray = (num: number): null[] => Array(num).fill(null)
|
|
37
|
+
|
|
38
|
+
export const arrayToString = (arr: Json.Tree.Array): string => arr.join(`,`)
|
|
39
|
+
export const arrayToNumber = (arr: Json.Tree.Array): number => arr.length
|
|
40
|
+
export const arrayToBoolean = (arr: Json.Tree.Array): boolean =>
|
|
41
|
+
typeof arr[0] === `boolean` ? arr[0] : arr.length > 0
|
|
42
|
+
export const arrayToObject = <T>(
|
|
43
|
+
arr: Json.Tree.Array<T>,
|
|
44
|
+
): Json.Tree.Object<`${number}`, T> =>
|
|
45
|
+
arr.reduce(
|
|
46
|
+
(acc, cur, idx) => {
|
|
47
|
+
acc[`${idx}`] = cur
|
|
48
|
+
return acc
|
|
49
|
+
},
|
|
50
|
+
{} as Json.Tree.Object<`${number}`, T>,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
export const nullToString = (): string => ``
|
|
54
|
+
export const nullToNumber = (): number => 0
|
|
55
|
+
export const nullToBoolean = (): boolean => false
|
|
56
|
+
export const nullToArray = (): Json.Tree.Array => []
|
|
57
|
+
export const nullToObject = (): Json.Tree.Object => ({})
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { jsonRefinery } from "atom.io/introspection"
|
|
2
|
+
import type { Json } from "atom.io/json"
|
|
3
|
+
|
|
4
|
+
import * as Cast from "./cast-json"
|
|
5
|
+
|
|
6
|
+
export const castToJson = (
|
|
7
|
+
input: unknown,
|
|
8
|
+
): {
|
|
9
|
+
array: Json.Tree.Array
|
|
10
|
+
boolean: boolean
|
|
11
|
+
number: number
|
|
12
|
+
object: Json.Tree.Object
|
|
13
|
+
string: string
|
|
14
|
+
null: null
|
|
15
|
+
} => {
|
|
16
|
+
const refined = jsonRefinery.refine(input)
|
|
17
|
+
switch (refined?.type) {
|
|
18
|
+
case `array`: {
|
|
19
|
+
const data = refined.data
|
|
20
|
+
return {
|
|
21
|
+
get array() {
|
|
22
|
+
return data
|
|
23
|
+
},
|
|
24
|
+
get boolean() {
|
|
25
|
+
return Cast.arrayToBoolean(data)
|
|
26
|
+
},
|
|
27
|
+
get number() {
|
|
28
|
+
return Cast.arrayToNumber(data)
|
|
29
|
+
},
|
|
30
|
+
get object() {
|
|
31
|
+
return Cast.arrayToObject(data)
|
|
32
|
+
},
|
|
33
|
+
get string() {
|
|
34
|
+
return Cast.arrayToString(data)
|
|
35
|
+
},
|
|
36
|
+
get null() {
|
|
37
|
+
return null
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
case `boolean`: {
|
|
42
|
+
const data = refined.data
|
|
43
|
+
return {
|
|
44
|
+
get array() {
|
|
45
|
+
return Cast.booleanToArray(data)
|
|
46
|
+
},
|
|
47
|
+
get boolean() {
|
|
48
|
+
return data
|
|
49
|
+
},
|
|
50
|
+
get number() {
|
|
51
|
+
return Cast.booleanToNumber(data)
|
|
52
|
+
},
|
|
53
|
+
get object() {
|
|
54
|
+
return Cast.booleanToObject(data)
|
|
55
|
+
},
|
|
56
|
+
get string() {
|
|
57
|
+
return Cast.booleanToString(data)
|
|
58
|
+
},
|
|
59
|
+
get null() {
|
|
60
|
+
return null
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
case `number`: {
|
|
65
|
+
const data = refined.data
|
|
66
|
+
return {
|
|
67
|
+
get array() {
|
|
68
|
+
return Cast.numberToArray(data)
|
|
69
|
+
},
|
|
70
|
+
get boolean() {
|
|
71
|
+
return Cast.numberToBoolean(data)
|
|
72
|
+
},
|
|
73
|
+
get number() {
|
|
74
|
+
return data
|
|
75
|
+
},
|
|
76
|
+
get object() {
|
|
77
|
+
return Cast.numberToObject(data)
|
|
78
|
+
},
|
|
79
|
+
get string() {
|
|
80
|
+
return Cast.numberToString(data)
|
|
81
|
+
},
|
|
82
|
+
get null() {
|
|
83
|
+
return null
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
case `object`: {
|
|
88
|
+
const data = refined.data
|
|
89
|
+
return {
|
|
90
|
+
get array() {
|
|
91
|
+
return Cast.objectToArray(data)
|
|
92
|
+
},
|
|
93
|
+
get boolean() {
|
|
94
|
+
return Cast.objectToBoolean(data)
|
|
95
|
+
},
|
|
96
|
+
get number() {
|
|
97
|
+
return Cast.objectToNumber(data)
|
|
98
|
+
},
|
|
99
|
+
get object() {
|
|
100
|
+
return data
|
|
101
|
+
},
|
|
102
|
+
get string() {
|
|
103
|
+
return Cast.objectToString(data)
|
|
104
|
+
},
|
|
105
|
+
get null() {
|
|
106
|
+
return null
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
case `string`: {
|
|
111
|
+
const data = refined.data
|
|
112
|
+
return {
|
|
113
|
+
get array() {
|
|
114
|
+
return Cast.stringToArray(data)
|
|
115
|
+
},
|
|
116
|
+
get boolean() {
|
|
117
|
+
return Cast.stringToBoolean(data)
|
|
118
|
+
},
|
|
119
|
+
get number() {
|
|
120
|
+
return Cast.stringToNumber(data)
|
|
121
|
+
},
|
|
122
|
+
get object() {
|
|
123
|
+
return Cast.stringToObject(data)
|
|
124
|
+
},
|
|
125
|
+
get string() {
|
|
126
|
+
return data
|
|
127
|
+
},
|
|
128
|
+
get null() {
|
|
129
|
+
return null
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
default: {
|
|
134
|
+
return {
|
|
135
|
+
get array() {
|
|
136
|
+
return Cast.nullToArray()
|
|
137
|
+
},
|
|
138
|
+
get boolean() {
|
|
139
|
+
return Cast.nullToBoolean()
|
|
140
|
+
},
|
|
141
|
+
get number() {
|
|
142
|
+
return Cast.nullToNumber()
|
|
143
|
+
},
|
|
144
|
+
get object() {
|
|
145
|
+
return Cast.nullToObject()
|
|
146
|
+
},
|
|
147
|
+
get string() {
|
|
148
|
+
return Cast.nullToString()
|
|
149
|
+
},
|
|
150
|
+
get null() {
|
|
151
|
+
return null
|
|
152
|
+
},
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|