@tinacms/app 0.0.9 → 0.0.12

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.
@@ -0,0 +1,23 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/tina.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>TinaCMS</title>
8
+ </head>
9
+
10
+ <!-- if development -->
11
+ <script type="module">
12
+ import RefreshRuntime from 'http://localhost:5173/@react-refresh'
13
+ RefreshRuntime.injectIntoGlobalHook(window)
14
+ window.$RefreshReg$ = () => {}
15
+ window.$RefreshSig$ = () => (type) => type
16
+ window.__vite_plugin_react_preamble_installed__ = true
17
+ </script>
18
+ <script type="module" src="http://localhost:5173/@vite/client"></script>
19
+ <script type="module" src="http://localhost:5173/admin/src/main.tsx"></script>
20
+ <body class="tina-tailwind">
21
+ <div id="root"></div>
22
+ </body>
23
+ </html>
@@ -0,0 +1,299 @@
1
+ /**
2
+ Copyright 2021 Forestry.io Holdings, Inc.
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+ http://www.apache.org/licenses/LICENSE-2.0
7
+ Unless required by applicable law or agreed to in writing, software
8
+ distributed under the License is distributed on an "AS IS" BASIS,
9
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ See the License for the specific language governing permissions and
11
+ limitations under the License.
12
+ */
13
+
14
+ import * as G from 'graphql'
15
+
16
+ import type { BlueprintPath } from './types'
17
+ import { getBlueprintNamePath } from './util'
18
+
19
+ /**
20
+ *
21
+ * This check ensures that at type is a Document, but only one
22
+ * that can be "formified". When using `Node` or `Document`, those
23
+ * query fields should not have forms generated since they can't contain
24
+ * fields.
25
+ *
26
+ * ```graphql
27
+ * # Can be formified
28
+ * {
29
+ * getPostDocument(relativePath: "") {
30
+ * data {
31
+ * title
32
+ * }
33
+ * }
34
+ * }
35
+ * ```
36
+ *
37
+ * ```graphql
38
+ * # cannot be formified, even though it is a document field
39
+ * {
40
+ * getPostDocument(relativePath: "") {
41
+ * ...on Document {
42
+ * id
43
+ * }
44
+ * }
45
+ * }
46
+ * ```
47
+ */
48
+ export const isFormifiableDocument = (t: G.GraphQLOutputType) => {
49
+ const type = G.getNamedType(t)
50
+ if (G.isUnionType(type)) {
51
+ return type.getTypes().every((type) => {
52
+ return type.getInterfaces().find((intfc) => intfc.name === 'Node')
53
+ })
54
+ } else if (G.isObjectType(type)) {
55
+ return !!type.getInterfaces().find((intfc) => intfc.name === 'Node')
56
+ } else {
57
+ return false
58
+ }
59
+ }
60
+
61
+ export const isScalarType = (t: G.GraphQLOutputType) => {
62
+ const namedType = G.getNamedType(t)
63
+ return G.isScalarType(namedType)
64
+ }
65
+
66
+ export const isConnectionField = (t: G.GraphQLOutputType) => {
67
+ const type = G.getNamedType(t)
68
+ if (G.isObjectType(type)) {
69
+ return !!type.getInterfaces().find((intfc) => intfc.name === 'Connection')
70
+ } else {
71
+ throw new Error(`Expected GraphQLObjectType for isConnectionField check`)
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Selects the appropriate field from a GraphQLObject based on the selection's name
77
+ */
78
+ export const getObjectField = (
79
+ object: G.GraphQLOutputType,
80
+ selectionNode: G.FieldNode
81
+ ) => {
82
+ const namedType = G.getNamedType(object)
83
+ ensureObjectOrInterfaceType(namedType)
84
+ return namedType.getFields()[selectionNode.name.value]
85
+ }
86
+
87
+ /**
88
+ * Selects the appropriate type from a union based on the selection's typeCondition
89
+ *
90
+ * ```graphql
91
+ * post {
92
+ * # would return PostDocument
93
+ * ...on PostDocument { ... }
94
+ * }
95
+ * ```
96
+ */
97
+ export const getSelectedUnionType = (
98
+ unionType: G.GraphQLOutputType,
99
+ selectionNode: G.InlineFragmentNode
100
+ ) => {
101
+ const namedType = G.getNamedType(unionType)
102
+ if (!G.isUnionType(namedType)) {
103
+ return
104
+ }
105
+ const types = namedType.getTypes()
106
+
107
+ const typeCondition = selectionNode.typeCondition.name.value
108
+ let intfc
109
+ types.forEach((type) => {
110
+ intfc = type.getInterfaces().find((intfc) => intfc.name === typeCondition)
111
+ })
112
+ if (intfc) {
113
+ return intfc
114
+ }
115
+
116
+ return namedType.getTypes().find((type) => type.name === typeCondition)
117
+ }
118
+
119
+ /**
120
+ * Checks if the given type is a list type. Even though
121
+ * this function is built-in to GraphQL it doesn't handle
122
+ * the scenario where the list type is wrapped in a non-null
123
+ * type, so the extra check here is needed.
124
+ */
125
+ export function isListType(type: unknown) {
126
+ if (G.isListType(type)) {
127
+ return true
128
+ } else if (G.isNonNullType(type)) {
129
+ if (G.isListType(type.ofType)) {
130
+ return true
131
+ }
132
+ }
133
+ return false
134
+ }
135
+
136
+ /**
137
+ *
138
+ * Throws an error if the provided type is not a GraphQLUnionType
139
+ */
140
+ function ensureUnionType(type: unknown): asserts type is G.GraphQLUnionType {
141
+ if (!G.isUnionType(type)) {
142
+ throw new Error(`Expected type to be GraphQLUnionType`)
143
+ }
144
+ }
145
+
146
+ /**
147
+ *
148
+ * Throws an error if the provided type is not a GraphQLObjectType or GraphQLInterfaceType
149
+ */
150
+ function ensureObjectOrInterfaceType(
151
+ type: unknown
152
+ ): asserts type is G.GraphQLObjectType | G.GraphQLInterfaceType {
153
+ if (G.isInterfaceType(type) || G.isObjectType(type)) {
154
+ } else {
155
+ console.log(
156
+ 'Expected type to be GraphQLObjectType or GraphQLInterfaceType',
157
+ type
158
+ )
159
+ throw new Error(
160
+ `Expected type to be GraphQLObjectType or GraphQLInterfaceType`
161
+ )
162
+ }
163
+ }
164
+
165
+ /**
166
+ *
167
+ * Throws an error if the provided type is not a GraphQLUnionType
168
+ */
169
+ export function ensureOperationDefinition(
170
+ type: G.DefinitionNode
171
+ ): asserts type is G.OperationDefinitionNode {
172
+ if (type.kind !== 'OperationDefinition') {
173
+ throw new Error(
174
+ `Expected top-level definition to be an OperationDefinition node, ensure your query has been optimized before calling formify`
175
+ )
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Generates the name and alias information for a given field node
181
+ * and appends it to a shallow copy of the path provided
182
+ */
183
+ export function buildPath({
184
+ fieldNode,
185
+ type,
186
+ parentTypename,
187
+ path,
188
+ }: {
189
+ fieldNode: G.FieldNode
190
+ type: G.GraphQLOutputType
191
+ parentTypename?: string
192
+ path?: BlueprintPath[]
193
+ }): BlueprintPath[] {
194
+ const p = path || []
195
+ const list = isListType(type)
196
+ const isNode = isFormifiableDocument(type)
197
+ return [
198
+ ...p,
199
+ {
200
+ name: fieldNode.name.value,
201
+ alias: fieldNode.alias ? fieldNode.alias.value : fieldNode.name.value,
202
+ parentTypename: parentTypename,
203
+ list: !!list,
204
+ isNode: !!isNode,
205
+ },
206
+ ]
207
+ }
208
+
209
+ /**
210
+ * This is a dummy query which we pull apart and spread
211
+ * back into the the selectionSet for all "Node" fields
212
+ */
213
+ const node = G.parse(`
214
+ query Sample {
215
+ ...on Document {
216
+ _internalSys: _sys {
217
+ path
218
+ relativePath
219
+ collection {
220
+ name
221
+ }
222
+ }
223
+ _values
224
+ }
225
+ }`)
226
+ export const metaFields: G.SelectionNode[] =
227
+ // @ts-ignore
228
+ node.definitions[0].selectionSet.selections
229
+
230
+ export const getRelativeBlueprint = (path: BlueprintPath[]) => {
231
+ let indexOfLastNode = 0
232
+ path.forEach((item, i) => {
233
+ if (item.isNode) {
234
+ if (i === path.length - 1) {
235
+ // skip if the item is a node, we still want to treat it as a field for the parent
236
+ } else {
237
+ indexOfLastNode = i
238
+ }
239
+ }
240
+ })
241
+
242
+ const documentBlueprintPath = path.slice(0, indexOfLastNode + 1)
243
+ return getBlueprintNamePath({ path: documentBlueprintPath })
244
+ }
245
+
246
+ export const isSysField = (fieldNode: G.FieldNode) => {
247
+ if (fieldNode.name.value === '__typename') {
248
+ return true
249
+ }
250
+ if (fieldNode.name.value === '_sys') {
251
+ return true
252
+ }
253
+ if (fieldNode.name.value === '_values') {
254
+ return true
255
+ }
256
+ if (fieldNode.name.value === 'id') {
257
+ return true
258
+ }
259
+
260
+ return false
261
+ }
262
+
263
+ export const getBlueprintId = (path: BlueprintPath[]) => {
264
+ const namePath = []
265
+ const aliasPath = []
266
+ path.forEach((p) => {
267
+ namePath.push(p.name)
268
+ aliasPath.push(p.alias)
269
+ if (p.list) {
270
+ namePath.push('[]')
271
+ aliasPath.push('[]')
272
+ }
273
+ })
274
+
275
+ return namePath.join('.')
276
+ }
277
+
278
+ export const getFieldAliasForBlueprint = (path: BlueprintPath[]) => {
279
+ const reversePath = [...path].reverse()
280
+ const accum = []
281
+ reversePath.every((item, index) => {
282
+ if (index === 0) {
283
+ if (item.list) {
284
+ accum.push('[]')
285
+ }
286
+ accum.push(item.alias)
287
+ } else {
288
+ if (item.isNode) {
289
+ return false
290
+ }
291
+ if (item.list) {
292
+ accum.push('[]')
293
+ }
294
+ accum.push(item.alias)
295
+ }
296
+ return true
297
+ })
298
+ return accum.reverse().slice(1).join('.')
299
+ }