@tinacms/app 0.0.0-003e348-20251023020516
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/CHANGELOG.md +1203 -0
- package/LICENSE +176 -0
- package/index.html +69 -0
- package/package.json +32 -0
- package/src/App.tsx +79 -0
- package/src/Playground.tsx +161 -0
- package/src/dummy-client.ts +1 -0
- package/src/fields/rich-text/index.tsx +6 -0
- package/src/fields/rich-text/monaco/error-message.tsx +118 -0
- package/src/fields/rich-text/monaco/index.tsx +230 -0
- package/src/fields/rich-text/monaco/use-debounce.ts +25 -0
- package/src/global.css +120 -0
- package/src/index.css +388 -0
- package/src/lib/build-form.ts +49 -0
- package/src/lib/errors.tsx +24 -0
- package/src/lib/expand-query.ts +273 -0
- package/src/lib/graphql-reducer.ts +1014 -0
- package/src/lib/types.ts +53 -0
- package/src/lib/util.ts +129 -0
- package/src/main.tsx +12 -0
- package/src/preflight.css +233 -0
- package/src/preview.tsx +27 -0
- package/src/vite-env.d.ts +8 -0
- package/tsconfig.json +32 -0
- package/tsconfig.node.json +10 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import * as G from 'graphql';
|
|
2
|
+
|
|
3
|
+
export const expandQuery = ({
|
|
4
|
+
schema,
|
|
5
|
+
documentNode,
|
|
6
|
+
}: {
|
|
7
|
+
schema: G.GraphQLSchema;
|
|
8
|
+
documentNode: G.DocumentNode;
|
|
9
|
+
}): G.DocumentNode => {
|
|
10
|
+
const documentNodeWithTypenames = addTypenameToDocument(documentNode);
|
|
11
|
+
return addMetaFieldsToQuery(
|
|
12
|
+
documentNodeWithTypenames,
|
|
13
|
+
new G.TypeInfo(schema)
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const addTypenameToDocument = (doc: G.DocumentNode) => {
|
|
18
|
+
function isField(selection: G.SelectionNode): selection is G.FieldNode {
|
|
19
|
+
return selection.kind === 'Field';
|
|
20
|
+
}
|
|
21
|
+
return G.visit(doc, {
|
|
22
|
+
SelectionSet: {
|
|
23
|
+
enter(node, _key, parent) {
|
|
24
|
+
// Don't add __typename to OperationDefinitions.
|
|
25
|
+
if (
|
|
26
|
+
parent &&
|
|
27
|
+
(parent as G.OperationDefinitionNode).kind ===
|
|
28
|
+
G.Kind.OPERATION_DEFINITION
|
|
29
|
+
) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// No changes if no selections.
|
|
34
|
+
const { selections } = node;
|
|
35
|
+
if (!selections) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// If selections already have a __typename, or are part of an
|
|
40
|
+
// introspection query, do nothing.
|
|
41
|
+
const skip = selections.some((selection) => {
|
|
42
|
+
return (
|
|
43
|
+
isField(selection) &&
|
|
44
|
+
(selection.name.value === '__typename' ||
|
|
45
|
+
selection.name.value.lastIndexOf('__', 0) === 0)
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
if (skip) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// If this SelectionSet is @export-ed as an input variable, it should
|
|
53
|
+
// not have a __typename field (see issue #4691).
|
|
54
|
+
const field = parent as G.FieldNode;
|
|
55
|
+
if (
|
|
56
|
+
isField(field) &&
|
|
57
|
+
field.directives &&
|
|
58
|
+
field.directives.some((d) => d.name.value === 'export')
|
|
59
|
+
) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Create and return a new SelectionSet with a __typename Field.
|
|
64
|
+
return {
|
|
65
|
+
...node,
|
|
66
|
+
selections: [...selections, TYPENAME_FIELD],
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const CONTENT_SOURCE_FIELD: G.FieldNode = {
|
|
74
|
+
kind: G.Kind.FIELD,
|
|
75
|
+
name: {
|
|
76
|
+
kind: G.Kind.NAME,
|
|
77
|
+
value: '_content_source',
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
const METADATA_FIELD: G.FieldNode = {
|
|
81
|
+
kind: G.Kind.FIELD,
|
|
82
|
+
name: {
|
|
83
|
+
kind: G.Kind.NAME,
|
|
84
|
+
value: '_tina_metadata',
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const TYPENAME_FIELD: G.FieldNode = {
|
|
89
|
+
kind: G.Kind.FIELD,
|
|
90
|
+
name: {
|
|
91
|
+
kind: G.Kind.NAME,
|
|
92
|
+
value: '__typename',
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const addMetadataField = (
|
|
97
|
+
node: G.FieldNode | G.InlineFragmentNode | G.FragmentDefinitionNode
|
|
98
|
+
): G.ASTNode => {
|
|
99
|
+
return {
|
|
100
|
+
...node,
|
|
101
|
+
selectionSet: {
|
|
102
|
+
...(node.selectionSet || {
|
|
103
|
+
kind: 'SelectionSet',
|
|
104
|
+
selections: [],
|
|
105
|
+
}),
|
|
106
|
+
selections: [
|
|
107
|
+
...(node.selectionSet?.selections || []),
|
|
108
|
+
METADATA_FIELD,
|
|
109
|
+
CONTENT_SOURCE_FIELD,
|
|
110
|
+
],
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const addMetaFieldsToQuery = (
|
|
116
|
+
documentNode: G.DocumentNode,
|
|
117
|
+
typeInfo: G.TypeInfo
|
|
118
|
+
) => {
|
|
119
|
+
const addMetaFields: G.VisitFn<G.ASTNode, G.FieldNode> = (
|
|
120
|
+
node: G.FieldNode
|
|
121
|
+
): G.ASTNode => {
|
|
122
|
+
return {
|
|
123
|
+
...node,
|
|
124
|
+
selectionSet: {
|
|
125
|
+
...(node.selectionSet || {
|
|
126
|
+
kind: 'SelectionSet',
|
|
127
|
+
selections: [],
|
|
128
|
+
}),
|
|
129
|
+
selections: [...(node.selectionSet?.selections || []), ...metaFields],
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const formifyVisitor: G.Visitor<G.ASTKindToNode, G.ASTNode> = {
|
|
135
|
+
FragmentDefinition: {
|
|
136
|
+
enter: (node, key, parent, path, ancestors) => {
|
|
137
|
+
typeInfo.enter(node);
|
|
138
|
+
const type = typeInfo.getType();
|
|
139
|
+
if (type) {
|
|
140
|
+
const namedType = G.getNamedType(type);
|
|
141
|
+
if (G.isObjectType(namedType)) {
|
|
142
|
+
if (namedType.getFields()['_tina_metadata']) {
|
|
143
|
+
return addMetadataField(node);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return node;
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
InlineFragment: {
|
|
151
|
+
enter: (node, key, parent, path, ancestors) => {
|
|
152
|
+
typeInfo.enter(node);
|
|
153
|
+
const type = typeInfo.getType();
|
|
154
|
+
if (type) {
|
|
155
|
+
const namedType = G.getNamedType(type);
|
|
156
|
+
if (G.isObjectType(namedType)) {
|
|
157
|
+
if (namedType.getFields()['_tina_metadata']) {
|
|
158
|
+
return addMetadataField(node);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return node;
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
Field: {
|
|
166
|
+
enter: (node, key, parent, path, ancestors) => {
|
|
167
|
+
typeInfo.enter(node);
|
|
168
|
+
const type = typeInfo.getType();
|
|
169
|
+
if (type) {
|
|
170
|
+
if (isNodeType(type)) {
|
|
171
|
+
return addMetaFields(node, key, parent, path, ancestors);
|
|
172
|
+
}
|
|
173
|
+
const namedType = G.getNamedType(type);
|
|
174
|
+
if (G.isObjectType(namedType)) {
|
|
175
|
+
if (namedType.getFields()['_tina_metadata']) {
|
|
176
|
+
return addMetadataField(node);
|
|
177
|
+
}
|
|
178
|
+
return node;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return node;
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
return G.visit(documentNode, G.visitWithTypeInfo(typeInfo, formifyVisitor));
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* This is a dummy query which we pull apart and spread
|
|
189
|
+
* back into the the selectionSet for all "Node" fields
|
|
190
|
+
*/
|
|
191
|
+
const node = G.parse(`
|
|
192
|
+
query Sample {
|
|
193
|
+
...on Document {
|
|
194
|
+
_internalValues: _values
|
|
195
|
+
_internalSys: _sys {
|
|
196
|
+
breadcrumbs
|
|
197
|
+
basename
|
|
198
|
+
filename
|
|
199
|
+
path
|
|
200
|
+
extension
|
|
201
|
+
relativePath
|
|
202
|
+
title
|
|
203
|
+
template
|
|
204
|
+
collection {
|
|
205
|
+
name
|
|
206
|
+
slug
|
|
207
|
+
label
|
|
208
|
+
path
|
|
209
|
+
format
|
|
210
|
+
matches
|
|
211
|
+
templates
|
|
212
|
+
fields
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}`);
|
|
217
|
+
const metaFields: G.SelectionNode[] =
|
|
218
|
+
// @ts-ignore
|
|
219
|
+
node.definitions[0].selectionSet.selections;
|
|
220
|
+
|
|
221
|
+
export const isNodeType = (type: G.GraphQLOutputType) => {
|
|
222
|
+
const namedType = G.getNamedType(type);
|
|
223
|
+
if (G.isInterfaceType(namedType)) {
|
|
224
|
+
if (namedType.name === 'Node') {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (G.isUnionType(namedType)) {
|
|
229
|
+
const types = namedType.getTypes();
|
|
230
|
+
if (
|
|
231
|
+
types.every((type) => {
|
|
232
|
+
return type.getInterfaces().some((intfc) => intfc.name === 'Node');
|
|
233
|
+
})
|
|
234
|
+
) {
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (G.isObjectType(namedType)) {
|
|
239
|
+
if (namedType.getInterfaces().some((intfc) => intfc.name === 'Node')) {
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return false;
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
export const isConnectionType = (type: G.GraphQLOutputType) => {
|
|
247
|
+
const namedType = G.getNamedType(type);
|
|
248
|
+
if (G.isInterfaceType(namedType)) {
|
|
249
|
+
if (namedType.name === 'Connection') {
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (G.isUnionType(namedType)) {
|
|
254
|
+
const types = namedType.getTypes();
|
|
255
|
+
if (
|
|
256
|
+
types.every((type) => {
|
|
257
|
+
return type
|
|
258
|
+
.getInterfaces()
|
|
259
|
+
.some((intfc) => intfc.name === 'Connection');
|
|
260
|
+
})
|
|
261
|
+
) {
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (G.isObjectType(namedType)) {
|
|
266
|
+
if (
|
|
267
|
+
namedType.getInterfaces().some((intfc) => intfc.name === 'Connection')
|
|
268
|
+
) {
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return false;
|
|
273
|
+
};
|