@nordcraft/core 1.0.0

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 (119) hide show
  1. package/README.md +5 -0
  2. package/dist/api/LegacyToddleApi.d.ts +34 -0
  3. package/dist/api/LegacyToddleApi.js +178 -0
  4. package/dist/api/LegacyToddleApi.js.map +1 -0
  5. package/dist/api/ToddleApiV2.d.ts +77 -0
  6. package/dist/api/ToddleApiV2.js +271 -0
  7. package/dist/api/ToddleApiV2.js.map +1 -0
  8. package/dist/api/api.d.ts +49 -0
  9. package/dist/api/api.js +276 -0
  10. package/dist/api/api.js.map +1 -0
  11. package/dist/api/apiTypes.d.ts +125 -0
  12. package/dist/api/apiTypes.js +11 -0
  13. package/dist/api/apiTypes.js.map +1 -0
  14. package/dist/api/headers.d.ts +10 -0
  15. package/dist/api/headers.js +36 -0
  16. package/dist/api/headers.js.map +1 -0
  17. package/dist/api/template.d.ts +5 -0
  18. package/dist/api/template.js +7 -0
  19. package/dist/api/template.js.map +1 -0
  20. package/dist/component/ToddleComponent.d.ts +45 -0
  21. package/dist/component/ToddleComponent.js +373 -0
  22. package/dist/component/ToddleComponent.js.map +1 -0
  23. package/dist/component/actionUtils.d.ts +2 -0
  24. package/dist/component/actionUtils.js +56 -0
  25. package/dist/component/actionUtils.js.map +1 -0
  26. package/dist/component/component.types.d.ts +313 -0
  27. package/dist/component/component.types.js +9 -0
  28. package/dist/component/component.types.js.map +1 -0
  29. package/dist/component/isPageComponent.d.ts +2 -0
  30. package/dist/component/isPageComponent.js +3 -0
  31. package/dist/component/isPageComponent.js.map +1 -0
  32. package/dist/formula/ToddleFormula.d.ts +15 -0
  33. package/dist/formula/ToddleFormula.js +20 -0
  34. package/dist/formula/ToddleFormula.js.map +1 -0
  35. package/dist/formula/formula.d.ts +103 -0
  36. package/dist/formula/formula.js +186 -0
  37. package/dist/formula/formula.js.map +1 -0
  38. package/dist/formula/formulaTypes.d.ts +30 -0
  39. package/dist/formula/formulaTypes.js +2 -0
  40. package/dist/formula/formulaTypes.js.map +1 -0
  41. package/dist/formula/formulaUtils.d.ts +18 -0
  42. package/dist/formula/formulaUtils.js +240 -0
  43. package/dist/formula/formulaUtils.js.map +1 -0
  44. package/dist/styling/className.d.ts +2 -0
  45. package/dist/styling/className.js +52 -0
  46. package/dist/styling/className.js.map +1 -0
  47. package/dist/styling/style.css.d.ts +5 -0
  48. package/dist/styling/style.css.js +242 -0
  49. package/dist/styling/style.css.js.map +1 -0
  50. package/dist/styling/theme.const.d.ts +3 -0
  51. package/dist/styling/theme.const.js +381 -0
  52. package/dist/styling/theme.const.js.map +1 -0
  53. package/dist/styling/theme.d.ts +72 -0
  54. package/dist/styling/theme.js +200 -0
  55. package/dist/styling/theme.js.map +1 -0
  56. package/dist/styling/variantSelector.d.ts +123 -0
  57. package/dist/styling/variantSelector.js +25 -0
  58. package/dist/styling/variantSelector.js.map +1 -0
  59. package/dist/types.d.ts +97 -0
  60. package/dist/types.js +2 -0
  61. package/dist/types.js.map +1 -0
  62. package/dist/utils/collections.d.ts +21 -0
  63. package/dist/utils/collections.js +75 -0
  64. package/dist/utils/collections.js.map +1 -0
  65. package/dist/utils/customElements.d.ts +6 -0
  66. package/dist/utils/customElements.js +15 -0
  67. package/dist/utils/customElements.js.map +1 -0
  68. package/dist/utils/hash.d.ts +1 -0
  69. package/dist/utils/hash.js +17 -0
  70. package/dist/utils/hash.js.map +1 -0
  71. package/dist/utils/json.d.ts +5 -0
  72. package/dist/utils/json.js +16 -0
  73. package/dist/utils/json.js.map +1 -0
  74. package/dist/utils/sha1.d.ts +2 -0
  75. package/dist/utils/sha1.js +13 -0
  76. package/dist/utils/sha1.js.map +1 -0
  77. package/dist/utils/url.d.ts +5 -0
  78. package/dist/utils/url.js +27 -0
  79. package/dist/utils/url.js.map +1 -0
  80. package/dist/utils/util.d.ts +3 -0
  81. package/dist/utils/util.js +4 -0
  82. package/dist/utils/util.js.map +1 -0
  83. package/package.json +18 -0
  84. package/src/api/LegacyToddleApi.ts +205 -0
  85. package/src/api/ToddleApiV2.ts +331 -0
  86. package/src/api/api.test.ts +319 -0
  87. package/src/api/api.ts +414 -0
  88. package/src/api/apiTypes.ts +145 -0
  89. package/src/api/headers.ts +41 -0
  90. package/src/api/template.ts +10 -0
  91. package/src/component/ToddleComponent.actionReferences.test.ts +75 -0
  92. package/src/component/ToddleComponent.formulasInComponent.test.ts +234 -0
  93. package/src/component/ToddleComponent.ts +470 -0
  94. package/src/component/actionUtils.ts +61 -0
  95. package/src/component/component.types.ts +362 -0
  96. package/src/component/isPageComponent.ts +6 -0
  97. package/src/formula/ToddleFormula.ts +30 -0
  98. package/src/formula/formula.ts +355 -0
  99. package/src/formula/formulaTypes.ts +45 -0
  100. package/src/formula/formulaUtils.ts +287 -0
  101. package/src/styling/className.test.ts +19 -0
  102. package/src/styling/className.ts +73 -0
  103. package/src/styling/style.css.ts +309 -0
  104. package/src/styling/theme.const.ts +390 -0
  105. package/src/styling/theme.ts +339 -0
  106. package/src/styling/variantSelector.ts +168 -0
  107. package/src/types.ts +158 -0
  108. package/src/utils/collections.test.ts +57 -0
  109. package/src/utils/collections.ts +122 -0
  110. package/src/utils/customElements.test.ts +40 -0
  111. package/src/utils/customElements.ts +16 -0
  112. package/src/utils/hash.test.ts +32 -0
  113. package/src/utils/hash.ts +18 -0
  114. package/src/utils/json.ts +18 -0
  115. package/src/utils/sha1.test.ts +50 -0
  116. package/src/utils/sha1.ts +17 -0
  117. package/src/utils/url.test.ts +17 -0
  118. package/src/utils/url.ts +33 -0
  119. package/src/utils/util.ts +8 -0
@@ -0,0 +1,319 @@
1
+ import { describe, expect, it, test } from '@jest/globals'
2
+ import { valueFormula } from '../formula/formulaUtils'
3
+ import {
4
+ createApiRequest,
5
+ getRequestHeaders,
6
+ getRequestPath,
7
+ getRequestQueryParams,
8
+ getUrl,
9
+ } from './api'
10
+ import type { ApiRequest } from './apiTypes'
11
+ import { ApiMethod } from './apiTypes'
12
+
13
+ describe('getApiPath()', () => {
14
+ test('it returns a valid url path string', () => {
15
+ expect(getRequestPath({}, undefined as any)).toBe('')
16
+ expect(
17
+ getRequestPath(
18
+ {
19
+ first: { formula: valueFormula('hello'), index: 0 },
20
+ second: { formula: valueFormula('world'), index: 1 },
21
+ },
22
+ undefined as any,
23
+ ),
24
+ ).toBe('hello/world')
25
+ })
26
+ })
27
+ describe('getQueryParams()', () => {
28
+ test('it returns a valid url path string', () => {
29
+ const emptyParams = getRequestQueryParams({}, undefined as any)
30
+ expect(emptyParams.size).toBe(0)
31
+ const params = getRequestQueryParams(
32
+ {
33
+ q: {
34
+ formula: valueFormula('hello'),
35
+ enabled: valueFormula(true),
36
+ },
37
+ filter: {
38
+ formula: valueFormula('world'),
39
+ enabled: valueFormula(true),
40
+ },
41
+ unused: {
42
+ formula: valueFormula('test'),
43
+ enabled: valueFormula(false),
44
+ },
45
+ },
46
+ undefined as any,
47
+ )
48
+ expect(params.get('q')).toBe('hello')
49
+ expect(params.get('filter')).toBe('world')
50
+ expect(params.get('unused')).toBeNull()
51
+ expect(params.size).toBe(2)
52
+ })
53
+ test('it stringifies arrays', () => {
54
+ const params = getRequestQueryParams(
55
+ {
56
+ q: {
57
+ formula: valueFormula(['hello', 'world']),
58
+ enabled: valueFormula(true),
59
+ },
60
+ },
61
+ undefined as any,
62
+ )
63
+ expect(params.getAll('q')).toEqual(['hello', 'world'])
64
+ expect(params.size).toBe(2)
65
+ })
66
+ test('it stringifies objects', () => {
67
+ const params = getRequestQueryParams(
68
+ {
69
+ q: {
70
+ formula: valueFormula({ a: 'hello', b: { c: 'world', d: [] } }),
71
+ enabled: valueFormula(true),
72
+ },
73
+ },
74
+ undefined as any,
75
+ )
76
+ expect(params.get('q[a]')).toEqual('hello')
77
+ expect(params.get('q[b][c]')).toEqual('world')
78
+ expect(params.get('q[b][d]')).toEqual('')
79
+ expect(params.size).toBe(3)
80
+ })
81
+ })
82
+ describe('getUrl()', () => {
83
+ test('it returns a valid url for null url', () => {
84
+ const url = getUrl(
85
+ {
86
+ url: valueFormula(null),
87
+ path: {
88
+ a: { formula: valueFormula('hello'), index: 0 },
89
+ b: { formula: valueFormula('world'), index: 1 },
90
+ },
91
+ queryParams: {
92
+ q: {
93
+ formula: valueFormula('test'),
94
+ },
95
+ },
96
+ },
97
+ undefined as any,
98
+ 'https://example.com',
99
+ )
100
+ expect(url.href).toBe('https://example.com/hello/world?q=test')
101
+ })
102
+ test('it returns a valid url for url with included path params', () => {
103
+ const url = getUrl(
104
+ {
105
+ url: valueFormula('https://example.com/test/path'),
106
+ path: {
107
+ a: { formula: valueFormula('hello'), index: 0 },
108
+ b: { formula: valueFormula('world'), index: 1 },
109
+ },
110
+ queryParams: {
111
+ q: {
112
+ formula: valueFormula('test'),
113
+ },
114
+ },
115
+ },
116
+ undefined as any,
117
+ 'https://example.com',
118
+ )
119
+ expect(url.href).toBe('https://example.com/test/path/hello/world?q=test')
120
+ })
121
+ test('it ignores trailing slashes in urls', () => {
122
+ const url = getUrl(
123
+ {
124
+ url: valueFormula('https://example.com/test/path/'),
125
+ path: {
126
+ a: { formula: valueFormula('hello'), index: 0 },
127
+ b: { formula: valueFormula('world'), index: 1 },
128
+ },
129
+ },
130
+ undefined as any,
131
+ 'https://example.com',
132
+ )
133
+ expect(url.href).toBe('https://example.com/test/path/hello/world')
134
+ })
135
+ test('numbers are accepted as path parameters in url definition', () => {
136
+ const url = getUrl(
137
+ {
138
+ url: valueFormula(88),
139
+ path: {
140
+ a: { formula: valueFormula('hello'), index: 0 },
141
+ b: { formula: valueFormula('world'), index: 1 },
142
+ },
143
+ },
144
+ undefined as any,
145
+ 'https://example.com',
146
+ )
147
+ expect(url.href).toBe('https://example.com/88/hello/world')
148
+ })
149
+ test('supports relative urls', () => {
150
+ const url = getUrl(
151
+ {
152
+ url: valueFormula('/test/path/'),
153
+ path: {
154
+ a: { formula: valueFormula('hello'), index: 0 },
155
+ b: { formula: valueFormula('world'), index: 1 },
156
+ },
157
+ },
158
+ undefined as any,
159
+ 'https://mysite.com',
160
+ )
161
+ expect(url.href).toBe('https://mysite.com/test/path/hello/world')
162
+ })
163
+ })
164
+ test('supports query parameters in url declaration', () => {
165
+ const url = getUrl(
166
+ {
167
+ url: valueFormula('/test/path/?q=test&hello=world'),
168
+ path: {
169
+ a: { formula: valueFormula('hello'), index: 0 },
170
+ b: { formula: valueFormula('world'), index: 1 },
171
+ },
172
+ queryParams: {
173
+ search: {
174
+ formula: valueFormula('test'),
175
+ },
176
+ },
177
+ },
178
+ undefined as any,
179
+ 'https://mysite.com',
180
+ )
181
+ expect(url.href).toBe(
182
+ 'https://mysite.com/test/path/hello/world?q=test&hello=world&search=test',
183
+ )
184
+ })
185
+ describe('getApiHeaders()', () => {
186
+ test('it returns valid headers', () => {
187
+ const emptyParams = getRequestHeaders({
188
+ apiHeaders: {},
189
+ formulaContext: undefined as any,
190
+ defaultHeaders: undefined,
191
+ })
192
+ expect(emptyParams.entries.length).toBe(0)
193
+ const headers = getRequestHeaders({
194
+ apiHeaders: {
195
+ q: { formula: valueFormula('hello') },
196
+ filter: { formula: valueFormula('world') },
197
+ },
198
+ formulaContext: undefined as any,
199
+ defaultHeaders: undefined,
200
+ })
201
+ expect(headers.get('q')).toBe('hello')
202
+ expect(headers.get('filter')).toBe('world')
203
+ expect([...headers.entries()].length).toBe(2)
204
+ const headersWithDefaults = getRequestHeaders({
205
+ apiHeaders: {
206
+ q: { formula: valueFormula('hello') },
207
+ filter: { formula: valueFormula('world') },
208
+ },
209
+ formulaContext: undefined as any,
210
+ defaultHeaders: new Headers([['accept-encoding', 'gzip']]),
211
+ })
212
+ expect(headersWithDefaults.get('q')).toBe('hello')
213
+ expect(headersWithDefaults.get('filter')).toBe('world')
214
+ expect(headersWithDefaults.get('accept-encoding')).toBe('gzip')
215
+ expect([...headersWithDefaults.entries()].length).toBe(3)
216
+ })
217
+ test('it ignores disabled headers', () => {
218
+ const headers = getRequestHeaders({
219
+ apiHeaders: {
220
+ q: { formula: valueFormula('hello') },
221
+ test: {
222
+ formula: valueFormula('hidden'),
223
+ enabled: valueFormula(false),
224
+ },
225
+ filter: { formula: valueFormula('world') },
226
+ },
227
+ formulaContext: undefined as any,
228
+ defaultHeaders: undefined,
229
+ })
230
+ expect(headers.get('q')).toBe('hello')
231
+ expect(headers.get('filter')).toBe('world')
232
+ expect(headers.get('test')).toBe(null)
233
+ expect([...headers.entries()].length).toBe(2)
234
+ })
235
+ })
236
+ describe('createApiRequest', () => {
237
+ const baseUrl = 'https://example.com'
238
+ it('creates a GET request with minimal arguments', () => {
239
+ const apiRequest: ApiRequest = {
240
+ name: 'Test API',
241
+ type: 'http',
242
+ path: {},
243
+ queryParams: {},
244
+ method: ApiMethod.GET,
245
+ url: valueFormula('service'),
246
+ version: 2,
247
+ inputs: {},
248
+ server: {
249
+ proxy: null,
250
+ ssr: {
251
+ enabled: { formula: valueFormula(true) },
252
+ },
253
+ },
254
+ client: {
255
+ parserMode: 'auto',
256
+ },
257
+ }
258
+
259
+ const { url, requestSettings } = createApiRequest({
260
+ api: apiRequest,
261
+ formulaContext: undefined as any,
262
+ baseUrl,
263
+ defaultHeaders: undefined,
264
+ })
265
+ const request = new Request(url, requestSettings)
266
+ expect(request.method).toBe('GET')
267
+ expect(request.url).toBe('https://example.com/service')
268
+ })
269
+
270
+ it('creates a POST request with all arguments', () => {
271
+ const apiRequest: ApiRequest = {
272
+ name: 'Test API',
273
+ type: 'http',
274
+ version: 2,
275
+ inputs: {},
276
+ path: {
277
+ first: { formula: valueFormula('hello'), index: 0 },
278
+ second: { formula: valueFormula('world'), index: 1 },
279
+ },
280
+ queryParams: {
281
+ q: {
282
+ formula: valueFormula('hello'),
283
+ enabled: valueFormula(true),
284
+ },
285
+ filter: {
286
+ formula: valueFormula('world'),
287
+ enabled: valueFormula(true),
288
+ },
289
+ unused: {
290
+ formula: valueFormula('test'),
291
+ enabled: valueFormula(false),
292
+ },
293
+ },
294
+ method: ApiMethod.POST,
295
+ url: valueFormula('service'),
296
+ headers: {
297
+ 'Content-Type': {
298
+ formula: valueFormula('application/json'),
299
+ },
300
+ },
301
+ body: valueFormula('{"key":"value"}'),
302
+ }
303
+
304
+ const { url, requestSettings } = createApiRequest({
305
+ api: apiRequest,
306
+ formulaContext: undefined as any,
307
+ baseUrl,
308
+ defaultHeaders: undefined,
309
+ })
310
+ const request = new Request(url, requestSettings)
311
+ expect(request.method).toBe('POST')
312
+ expect(request.url).toBe(
313
+ 'https://example.com/service/hello/world?q=hello&filter=world',
314
+ )
315
+ expect(request.headers.get('Content-Type')).toBe('application/json')
316
+ })
317
+
318
+ // TODO: Add tests for the http body
319
+ })