├── .dockerignore
├── .gitignore
├── README.md
├── __tests__
├── utils_test.re
└── web
│ └── components
│ ├── header_test.re
│ └── jsSnippet_test.re
├── bsconfig.json
├── dockerfile
├── graphql_schema.json
├── package.json
├── snippets
├── SyntaxPatternMatchWithoutSwitch.re
├── listMap.re
├── listReduce.re
├── operator__and.re
├── operator__applicationOperator.re
├── operator__comparisonGreaterThan.re
├── operator__comparisonGreaterThanOrEqualTo.re
├── operator__comparisonLessOrEqualTo.re
├── operator__comparisonLessThan.re
├── operator__equals.re
├── operator__exponentiation.re
├── operator__floatAddition.re
├── operator__floatDivision.re
├── operator__floatMultiplication.re
├── operator__floatSubtraction.re
├── operator__integerAddition.re
├── operator__integerDivision.re
├── operator__integerMultiplication.re
├── operator__integerSubtraction.re
├── operator__listConcatination.re
├── operator__logicalAnd.re
├── operator__logicalOr.re
├── operator__logicalXor.re
├── operator__modulus.re
├── operator__notEquals.re
├── operator__pipe.re
├── operator__referenceAssignment.re
├── operator__referenceContent.re
├── operator__shiftLeft.re
├── operator__shiftRight.re
└── operator__stringConcatination.re
├── src
├── bindings
│ ├── apollo.re
│ └── apolloLinkSchema.re
├── config.re
├── index.re
├── mocks
│ └── apolloMock.re
├── server
│ ├── apolloServer.re
│ ├── graphql.re
│ └── snippet.re
├── utils.re
└── web
│ ├── apolloBrowser.re
│ ├── app.re
│ ├── browser.re
│ ├── components
│ ├── apolloContext.re
│ ├── header.re
│ ├── jsSnippet.re
│ ├── query.re
│ ├── search.re
│ ├── snippetItem.re
│ └── snippetList.re
│ ├── elements
│ ├── background.re
│ ├── card.re
│ ├── code.re
│ ├── divider.re
│ ├── h1.re
│ ├── h2.re
│ ├── h3.re
│ ├── h4.re
│ ├── loadingAnimation.re
│ ├── p.re
│ └── pageFrame.re
│ ├── template.re
│ └── theme.re
├── tasks.json
├── webpack.config.js
└── yarn.lock
/.dockerignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .merlin
3 | .bsb.lock
4 | npm-debug.log
5 | /node_modules/
6 |
7 | # Build assets
8 | /lib/*
9 | /build/*
10 | /dist/*
11 |
12 | # My pesky vim
13 | *.swp
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .merlin
3 | .bsb.lock
4 | npm-debug.log
5 | /node_modules/
6 |
7 | # Build assets
8 | /lib/*
9 | /build/*
10 | /dist/*
11 |
12 | # My pesky vim
13 | *.swp
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Basic Reason Template
2 |
3 | Hello! This project allows you to quickly get started with Reason and BuckleScript. If you wanted a more sophisticated version, try the `react` template (`bsb -theme react -init .`).
4 |
5 | # Build
6 | ```
7 | npm run build
8 | ```
9 |
10 | # Build + Watch
11 |
12 | ```
13 | npm run watch
14 | ```
15 |
16 |
17 | # Editor
18 | If you use `vscode`, Press `Windows + Shift + B` it will build automatically
19 |
--------------------------------------------------------------------------------
/__tests__/utils_test.re:
--------------------------------------------------------------------------------
1 | open Jest;
2 |
3 | open Utils;
4 |
5 | /* Just simple test incase if I accidentally change these functions */
6 | describe("ele_of_ functions", () => {
7 | open Expect;
8 | test("str", () =>
9 | ele_of_str("test") |> expect |> toEqual(ReasonReact.stringToElement("test"))
10 | );
11 | test("arr", () => {
12 | let arr = [|
|];
13 | ele_of_arr(arr) |> expect |> toEqual(ReasonReact.arrayToElement(arr));
14 | });
15 | test("list", () => {
16 | let l = [, , ];
17 | ele_of_list(l) |> expect |> toEqual(ReasonReact.arrayToElement(Array.of_list(l)));
18 | });
19 | });
20 |
21 | describe("Debounce call", () => {
22 | open Expect;
23 | let count = ref(0);
24 | beforeEachAsync(
25 | ~timeout=10,
26 | finish => {
27 | let f = () => {
28 | count := count^ + 1;
29 | finish();
30 | };
31 | let dF = Debounce.make(f);
32 | Debounce.call((), dF);
33 | Debounce.call((), dF);
34 | Debounce.call((), dF);
35 | Debounce.call((), dF);
36 | Debounce.call((), dF);
37 | ();
38 | }
39 | );
40 | test("First group of calls", () =>
41 | count^ |> expect |> toBe(1)
42 | );
43 | test("Second group of calls", () =>
44 | count^ |> expect |> toBe(2)
45 | );
46 | test("Third group of calls", () =>
47 | count^ |> expect |> toBe(3)
48 | );
49 | });
50 |
--------------------------------------------------------------------------------
/__tests__/web/components/header_test.re:
--------------------------------------------------------------------------------
1 | open Jest;
2 |
3 | Enzyme.configureEnzyme(Enzyme.react_16_adapter());
4 |
5 | describe("Header", () => {
6 | open Expect;
7 | test("component renders", () => {
8 | Enzyme.shallow() |> Enzyme.exists |> expect |> toBe(true);
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/__tests__/web/components/jsSnippet_test.re:
--------------------------------------------------------------------------------
1 | open Jest;
2 |
3 | Enzyme.configureEnzyme(Enzyme.react_16_adapter());
4 |
5 | /* Todo: I need to figure out a way to mock more behaviour in the system */
6 | describe("JsSnippet", () => {
7 | open Expect;
8 | test("renderLoading renders", () =>
9 | (JsSnippet.renderLoading())
10 | |> Enzyme.shallow
11 | |> Enzyme.exists
12 | |> expect
13 | |> toBe(true)
14 | );
15 | test("renderFailed renders", () =>
16 | (JsSnippet.renderFailed())
17 | |> Enzyme.shallow
18 | |> Enzyme.exists
19 | |> expect
20 | |> toBe(true)
21 | );
22 | test("renderLoaded renders", () =>
23 | JsSnippet.renderLoaded("test")
24 | |> Enzyme.shallow
25 | |> Enzyme.exists
26 | |> expect
27 | |> toBe(true)
28 | );
29 | test("renders with mock", () =>
30 |
31 | |> Enzyme.shallow
32 | |> Enzyme.exists
33 | |> expect
34 | |> toBe(true)
35 | );
36 | });
37 |
--------------------------------------------------------------------------------
/bsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "0.1.0",
4 | "sources": [
5 | {
6 | "dir": "src",
7 | "subdirs": true
8 | },
9 | {
10 | "dir": "__tests__",
11 | "subdirs": true,
12 | "type": "dev"
13 | },
14 | "snippets"
15 | ],
16 | "package-specs": {
17 | "module": "commonjs"
18 | },
19 | "suffix": ".bs.js",
20 | "bs-dependencies": [
21 | "reason-react-context",
22 | "bs-algolia",
23 | "bs-express",
24 | "bs-graphql",
25 | "bs-graphql-tools",
26 | "bs-apollo-server-express",
27 | "reason-react",
28 | "reason-apollo",
29 | "bs-nice",
30 | "bs-nice-components"
31 | ],
32 | "bs-dev-dependencies": ["@glennsl/bs-jest", "bs-enzyme"],
33 | "reason": {
34 | "react-jsx": 2
35 | },
36 | "ppx-flags": ["graphql_ppx/ppx"],
37 | "namespace": true,
38 | "refmt": 3
39 | }
40 |
--------------------------------------------------------------------------------
/dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:9
2 |
3 | ADD package.json /app/package.json
4 | WORKDIR /app
5 | RUN yarn install
6 |
7 | ADD . /app
8 | RUN yarn build
9 | EXPOSE 3000
10 |
11 | CMD ["yarn", "start-server"]
12 |
--------------------------------------------------------------------------------
/graphql_schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "data": {
3 | "__schema": {
4 | "queryType": {
5 | "name": "Query"
6 | },
7 | "mutationType": null,
8 | "subscriptionType": null,
9 | "types": [
10 | {
11 | "kind": "OBJECT",
12 | "name": "Query",
13 | "description": "",
14 | "fields": [
15 | {
16 | "name": "allSnippets",
17 | "description": "",
18 | "args": [
19 | {
20 | "name": "query",
21 | "description": "",
22 | "type": {
23 | "kind": "SCALAR",
24 | "name": "String",
25 | "ofType": null
26 | },
27 | "defaultValue": null
28 | }
29 | ],
30 | "type": {
31 | "kind": "NON_NULL",
32 | "name": null,
33 | "ofType": {
34 | "kind": "LIST",
35 | "name": null,
36 | "ofType": {
37 | "kind": "OBJECT",
38 | "name": "Snippet",
39 | "ofType": null
40 | }
41 | }
42 | },
43 | "isDeprecated": false,
44 | "deprecationReason": null
45 | },
46 | {
47 | "name": "snippet",
48 | "description": "",
49 | "args": [
50 | {
51 | "name": "id",
52 | "description": "",
53 | "type": {
54 | "kind": "NON_NULL",
55 | "name": null,
56 | "ofType": {
57 | "kind": "SCALAR",
58 | "name": "ID",
59 | "ofType": null
60 | }
61 | },
62 | "defaultValue": null
63 | }
64 | ],
65 | "type": {
66 | "kind": "NON_NULL",
67 | "name": null,
68 | "ofType": {
69 | "kind": "OBJECT",
70 | "name": "Snippet",
71 | "ofType": null
72 | }
73 | },
74 | "isDeprecated": false,
75 | "deprecationReason": null
76 | }
77 | ],
78 | "inputFields": null,
79 | "interfaces": [],
80 | "enumValues": null,
81 | "possibleTypes": null
82 | },
83 | {
84 | "kind": "SCALAR",
85 | "name": "String",
86 | "description":
87 | "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.",
88 | "fields": null,
89 | "inputFields": null,
90 | "interfaces": null,
91 | "enumValues": null,
92 | "possibleTypes": null
93 | },
94 | {
95 | "kind": "OBJECT",
96 | "name": "Snippet",
97 | "description": "",
98 | "fields": [
99 | {
100 | "name": "id",
101 | "description": "",
102 | "args": [],
103 | "type": {
104 | "kind": "NON_NULL",
105 | "name": null,
106 | "ofType": {
107 | "kind": "SCALAR",
108 | "name": "ID",
109 | "ofType": null
110 | }
111 | },
112 | "isDeprecated": false,
113 | "deprecationReason": null
114 | },
115 | {
116 | "name": "title",
117 | "description": "",
118 | "args": [],
119 | "type": {
120 | "kind": "NON_NULL",
121 | "name": null,
122 | "ofType": {
123 | "kind": "SCALAR",
124 | "name": "String",
125 | "ofType": null
126 | }
127 | },
128 | "isDeprecated": false,
129 | "deprecationReason": null
130 | },
131 | {
132 | "name": "content",
133 | "description": "",
134 | "args": [],
135 | "type": {
136 | "kind": "NON_NULL",
137 | "name": null,
138 | "ofType": {
139 | "kind": "SCALAR",
140 | "name": "String",
141 | "ofType": null
142 | }
143 | },
144 | "isDeprecated": false,
145 | "deprecationReason": null
146 | },
147 | {
148 | "name": "description",
149 | "description": "",
150 | "args": [],
151 | "type": {
152 | "kind": "NON_NULL",
153 | "name": null,
154 | "ofType": {
155 | "kind": "SCALAR",
156 | "name": "String",
157 | "ofType": null
158 | }
159 | },
160 | "isDeprecated": false,
161 | "deprecationReason": null
162 | },
163 | {
164 | "name": "example",
165 | "description": "",
166 | "args": [],
167 | "type": {
168 | "kind": "NON_NULL",
169 | "name": null,
170 | "ofType": {
171 | "kind": "SCALAR",
172 | "name": "String",
173 | "ofType": null
174 | }
175 | },
176 | "isDeprecated": false,
177 | "deprecationReason": null
178 | },
179 | {
180 | "name": "jsOutput",
181 | "description": "",
182 | "args": [],
183 | "type": {
184 | "kind": "NON_NULL",
185 | "name": null,
186 | "ofType": {
187 | "kind": "SCALAR",
188 | "name": "String",
189 | "ofType": null
190 | }
191 | },
192 | "isDeprecated": false,
193 | "deprecationReason": null
194 | },
195 | {
196 | "name": "section",
197 | "description": "",
198 | "args": [],
199 | "type": {
200 | "kind": "NON_NULL",
201 | "name": null,
202 | "ofType": {
203 | "kind": "SCALAR",
204 | "name": "String",
205 | "ofType": null
206 | }
207 | },
208 | "isDeprecated": false,
209 | "deprecationReason": null
210 | },
211 | {
212 | "name": "typeSpec",
213 | "description": "",
214 | "args": [],
215 | "type": {
216 | "kind": "NON_NULL",
217 | "name": null,
218 | "ofType": {
219 | "kind": "SCALAR",
220 | "name": "String",
221 | "ofType": null
222 | }
223 | },
224 | "isDeprecated": false,
225 | "deprecationReason": null
226 | }
227 | ],
228 | "inputFields": null,
229 | "interfaces": [],
230 | "enumValues": null,
231 | "possibleTypes": null
232 | },
233 | {
234 | "kind": "SCALAR",
235 | "name": "ID",
236 | "description":
237 | "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.",
238 | "fields": null,
239 | "inputFields": null,
240 | "interfaces": null,
241 | "enumValues": null,
242 | "possibleTypes": null
243 | },
244 | {
245 | "kind": "OBJECT",
246 | "name": "__Schema",
247 | "description":
248 | "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.",
249 | "fields": [
250 | {
251 | "name": "types",
252 | "description": "A list of all types supported by this server.",
253 | "args": [],
254 | "type": {
255 | "kind": "NON_NULL",
256 | "name": null,
257 | "ofType": {
258 | "kind": "LIST",
259 | "name": null,
260 | "ofType": {
261 | "kind": "NON_NULL",
262 | "name": null,
263 | "ofType": {
264 | "kind": "OBJECT",
265 | "name": "__Type",
266 | "ofType": null
267 | }
268 | }
269 | }
270 | },
271 | "isDeprecated": false,
272 | "deprecationReason": null
273 | },
274 | {
275 | "name": "queryType",
276 | "description":
277 | "The type that query operations will be rooted at.",
278 | "args": [],
279 | "type": {
280 | "kind": "NON_NULL",
281 | "name": null,
282 | "ofType": {
283 | "kind": "OBJECT",
284 | "name": "__Type",
285 | "ofType": null
286 | }
287 | },
288 | "isDeprecated": false,
289 | "deprecationReason": null
290 | },
291 | {
292 | "name": "mutationType",
293 | "description":
294 | "If this server supports mutation, the type that mutation operations will be rooted at.",
295 | "args": [],
296 | "type": {
297 | "kind": "OBJECT",
298 | "name": "__Type",
299 | "ofType": null
300 | },
301 | "isDeprecated": false,
302 | "deprecationReason": null
303 | },
304 | {
305 | "name": "subscriptionType",
306 | "description":
307 | "If this server support subscription, the type that subscription operations will be rooted at.",
308 | "args": [],
309 | "type": {
310 | "kind": "OBJECT",
311 | "name": "__Type",
312 | "ofType": null
313 | },
314 | "isDeprecated": false,
315 | "deprecationReason": null
316 | },
317 | {
318 | "name": "directives",
319 | "description":
320 | "A list of all directives supported by this server.",
321 | "args": [],
322 | "type": {
323 | "kind": "NON_NULL",
324 | "name": null,
325 | "ofType": {
326 | "kind": "LIST",
327 | "name": null,
328 | "ofType": {
329 | "kind": "NON_NULL",
330 | "name": null,
331 | "ofType": {
332 | "kind": "OBJECT",
333 | "name": "__Directive",
334 | "ofType": null
335 | }
336 | }
337 | }
338 | },
339 | "isDeprecated": false,
340 | "deprecationReason": null
341 | }
342 | ],
343 | "inputFields": null,
344 | "interfaces": [],
345 | "enumValues": null,
346 | "possibleTypes": null
347 | },
348 | {
349 | "kind": "OBJECT",
350 | "name": "__Type",
351 | "description":
352 | "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.",
353 | "fields": [
354 | {
355 | "name": "kind",
356 | "description": null,
357 | "args": [],
358 | "type": {
359 | "kind": "NON_NULL",
360 | "name": null,
361 | "ofType": {
362 | "kind": "ENUM",
363 | "name": "__TypeKind",
364 | "ofType": null
365 | }
366 | },
367 | "isDeprecated": false,
368 | "deprecationReason": null
369 | },
370 | {
371 | "name": "name",
372 | "description": null,
373 | "args": [],
374 | "type": {
375 | "kind": "SCALAR",
376 | "name": "String",
377 | "ofType": null
378 | },
379 | "isDeprecated": false,
380 | "deprecationReason": null
381 | },
382 | {
383 | "name": "description",
384 | "description": null,
385 | "args": [],
386 | "type": {
387 | "kind": "SCALAR",
388 | "name": "String",
389 | "ofType": null
390 | },
391 | "isDeprecated": false,
392 | "deprecationReason": null
393 | },
394 | {
395 | "name": "fields",
396 | "description": null,
397 | "args": [
398 | {
399 | "name": "includeDeprecated",
400 | "description": null,
401 | "type": {
402 | "kind": "SCALAR",
403 | "name": "Boolean",
404 | "ofType": null
405 | },
406 | "defaultValue": "false"
407 | }
408 | ],
409 | "type": {
410 | "kind": "LIST",
411 | "name": null,
412 | "ofType": {
413 | "kind": "NON_NULL",
414 | "name": null,
415 | "ofType": {
416 | "kind": "OBJECT",
417 | "name": "__Field",
418 | "ofType": null
419 | }
420 | }
421 | },
422 | "isDeprecated": false,
423 | "deprecationReason": null
424 | },
425 | {
426 | "name": "interfaces",
427 | "description": null,
428 | "args": [],
429 | "type": {
430 | "kind": "LIST",
431 | "name": null,
432 | "ofType": {
433 | "kind": "NON_NULL",
434 | "name": null,
435 | "ofType": {
436 | "kind": "OBJECT",
437 | "name": "__Type",
438 | "ofType": null
439 | }
440 | }
441 | },
442 | "isDeprecated": false,
443 | "deprecationReason": null
444 | },
445 | {
446 | "name": "possibleTypes",
447 | "description": null,
448 | "args": [],
449 | "type": {
450 | "kind": "LIST",
451 | "name": null,
452 | "ofType": {
453 | "kind": "NON_NULL",
454 | "name": null,
455 | "ofType": {
456 | "kind": "OBJECT",
457 | "name": "__Type",
458 | "ofType": null
459 | }
460 | }
461 | },
462 | "isDeprecated": false,
463 | "deprecationReason": null
464 | },
465 | {
466 | "name": "enumValues",
467 | "description": null,
468 | "args": [
469 | {
470 | "name": "includeDeprecated",
471 | "description": null,
472 | "type": {
473 | "kind": "SCALAR",
474 | "name": "Boolean",
475 | "ofType": null
476 | },
477 | "defaultValue": "false"
478 | }
479 | ],
480 | "type": {
481 | "kind": "LIST",
482 | "name": null,
483 | "ofType": {
484 | "kind": "NON_NULL",
485 | "name": null,
486 | "ofType": {
487 | "kind": "OBJECT",
488 | "name": "__EnumValue",
489 | "ofType": null
490 | }
491 | }
492 | },
493 | "isDeprecated": false,
494 | "deprecationReason": null
495 | },
496 | {
497 | "name": "inputFields",
498 | "description": null,
499 | "args": [],
500 | "type": {
501 | "kind": "LIST",
502 | "name": null,
503 | "ofType": {
504 | "kind": "NON_NULL",
505 | "name": null,
506 | "ofType": {
507 | "kind": "OBJECT",
508 | "name": "__InputValue",
509 | "ofType": null
510 | }
511 | }
512 | },
513 | "isDeprecated": false,
514 | "deprecationReason": null
515 | },
516 | {
517 | "name": "ofType",
518 | "description": null,
519 | "args": [],
520 | "type": {
521 | "kind": "OBJECT",
522 | "name": "__Type",
523 | "ofType": null
524 | },
525 | "isDeprecated": false,
526 | "deprecationReason": null
527 | }
528 | ],
529 | "inputFields": null,
530 | "interfaces": [],
531 | "enumValues": null,
532 | "possibleTypes": null
533 | },
534 | {
535 | "kind": "ENUM",
536 | "name": "__TypeKind",
537 | "description":
538 | "An enum describing what kind of type a given `__Type` is.",
539 | "fields": null,
540 | "inputFields": null,
541 | "interfaces": null,
542 | "enumValues": [
543 | {
544 | "name": "SCALAR",
545 | "description": "Indicates this type is a scalar.",
546 | "isDeprecated": false,
547 | "deprecationReason": null
548 | },
549 | {
550 | "name": "OBJECT",
551 | "description":
552 | "Indicates this type is an object. `fields` and `interfaces` are valid fields.",
553 | "isDeprecated": false,
554 | "deprecationReason": null
555 | },
556 | {
557 | "name": "INTERFACE",
558 | "description":
559 | "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.",
560 | "isDeprecated": false,
561 | "deprecationReason": null
562 | },
563 | {
564 | "name": "UNION",
565 | "description":
566 | "Indicates this type is a union. `possibleTypes` is a valid field.",
567 | "isDeprecated": false,
568 | "deprecationReason": null
569 | },
570 | {
571 | "name": "ENUM",
572 | "description":
573 | "Indicates this type is an enum. `enumValues` is a valid field.",
574 | "isDeprecated": false,
575 | "deprecationReason": null
576 | },
577 | {
578 | "name": "INPUT_OBJECT",
579 | "description":
580 | "Indicates this type is an input object. `inputFields` is a valid field.",
581 | "isDeprecated": false,
582 | "deprecationReason": null
583 | },
584 | {
585 | "name": "LIST",
586 | "description":
587 | "Indicates this type is a list. `ofType` is a valid field.",
588 | "isDeprecated": false,
589 | "deprecationReason": null
590 | },
591 | {
592 | "name": "NON_NULL",
593 | "description":
594 | "Indicates this type is a non-null. `ofType` is a valid field.",
595 | "isDeprecated": false,
596 | "deprecationReason": null
597 | }
598 | ],
599 | "possibleTypes": null
600 | },
601 | {
602 | "kind": "SCALAR",
603 | "name": "Boolean",
604 | "description":
605 | "The `Boolean` scalar type represents `true` or `false`.",
606 | "fields": null,
607 | "inputFields": null,
608 | "interfaces": null,
609 | "enumValues": null,
610 | "possibleTypes": null
611 | },
612 | {
613 | "kind": "OBJECT",
614 | "name": "__Field",
615 | "description":
616 | "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.",
617 | "fields": [
618 | {
619 | "name": "name",
620 | "description": null,
621 | "args": [],
622 | "type": {
623 | "kind": "NON_NULL",
624 | "name": null,
625 | "ofType": {
626 | "kind": "SCALAR",
627 | "name": "String",
628 | "ofType": null
629 | }
630 | },
631 | "isDeprecated": false,
632 | "deprecationReason": null
633 | },
634 | {
635 | "name": "description",
636 | "description": null,
637 | "args": [],
638 | "type": {
639 | "kind": "SCALAR",
640 | "name": "String",
641 | "ofType": null
642 | },
643 | "isDeprecated": false,
644 | "deprecationReason": null
645 | },
646 | {
647 | "name": "args",
648 | "description": null,
649 | "args": [],
650 | "type": {
651 | "kind": "NON_NULL",
652 | "name": null,
653 | "ofType": {
654 | "kind": "LIST",
655 | "name": null,
656 | "ofType": {
657 | "kind": "NON_NULL",
658 | "name": null,
659 | "ofType": {
660 | "kind": "OBJECT",
661 | "name": "__InputValue",
662 | "ofType": null
663 | }
664 | }
665 | }
666 | },
667 | "isDeprecated": false,
668 | "deprecationReason": null
669 | },
670 | {
671 | "name": "type",
672 | "description": null,
673 | "args": [],
674 | "type": {
675 | "kind": "NON_NULL",
676 | "name": null,
677 | "ofType": {
678 | "kind": "OBJECT",
679 | "name": "__Type",
680 | "ofType": null
681 | }
682 | },
683 | "isDeprecated": false,
684 | "deprecationReason": null
685 | },
686 | {
687 | "name": "isDeprecated",
688 | "description": null,
689 | "args": [],
690 | "type": {
691 | "kind": "NON_NULL",
692 | "name": null,
693 | "ofType": {
694 | "kind": "SCALAR",
695 | "name": "Boolean",
696 | "ofType": null
697 | }
698 | },
699 | "isDeprecated": false,
700 | "deprecationReason": null
701 | },
702 | {
703 | "name": "deprecationReason",
704 | "description": null,
705 | "args": [],
706 | "type": {
707 | "kind": "SCALAR",
708 | "name": "String",
709 | "ofType": null
710 | },
711 | "isDeprecated": false,
712 | "deprecationReason": null
713 | }
714 | ],
715 | "inputFields": null,
716 | "interfaces": [],
717 | "enumValues": null,
718 | "possibleTypes": null
719 | },
720 | {
721 | "kind": "OBJECT",
722 | "name": "__InputValue",
723 | "description":
724 | "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.",
725 | "fields": [
726 | {
727 | "name": "name",
728 | "description": null,
729 | "args": [],
730 | "type": {
731 | "kind": "NON_NULL",
732 | "name": null,
733 | "ofType": {
734 | "kind": "SCALAR",
735 | "name": "String",
736 | "ofType": null
737 | }
738 | },
739 | "isDeprecated": false,
740 | "deprecationReason": null
741 | },
742 | {
743 | "name": "description",
744 | "description": null,
745 | "args": [],
746 | "type": {
747 | "kind": "SCALAR",
748 | "name": "String",
749 | "ofType": null
750 | },
751 | "isDeprecated": false,
752 | "deprecationReason": null
753 | },
754 | {
755 | "name": "type",
756 | "description": null,
757 | "args": [],
758 | "type": {
759 | "kind": "NON_NULL",
760 | "name": null,
761 | "ofType": {
762 | "kind": "OBJECT",
763 | "name": "__Type",
764 | "ofType": null
765 | }
766 | },
767 | "isDeprecated": false,
768 | "deprecationReason": null
769 | },
770 | {
771 | "name": "defaultValue",
772 | "description":
773 | "A GraphQL-formatted string representing the default value for this input value.",
774 | "args": [],
775 | "type": {
776 | "kind": "SCALAR",
777 | "name": "String",
778 | "ofType": null
779 | },
780 | "isDeprecated": false,
781 | "deprecationReason": null
782 | }
783 | ],
784 | "inputFields": null,
785 | "interfaces": [],
786 | "enumValues": null,
787 | "possibleTypes": null
788 | },
789 | {
790 | "kind": "OBJECT",
791 | "name": "__EnumValue",
792 | "description":
793 | "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.",
794 | "fields": [
795 | {
796 | "name": "name",
797 | "description": null,
798 | "args": [],
799 | "type": {
800 | "kind": "NON_NULL",
801 | "name": null,
802 | "ofType": {
803 | "kind": "SCALAR",
804 | "name": "String",
805 | "ofType": null
806 | }
807 | },
808 | "isDeprecated": false,
809 | "deprecationReason": null
810 | },
811 | {
812 | "name": "description",
813 | "description": null,
814 | "args": [],
815 | "type": {
816 | "kind": "SCALAR",
817 | "name": "String",
818 | "ofType": null
819 | },
820 | "isDeprecated": false,
821 | "deprecationReason": null
822 | },
823 | {
824 | "name": "isDeprecated",
825 | "description": null,
826 | "args": [],
827 | "type": {
828 | "kind": "NON_NULL",
829 | "name": null,
830 | "ofType": {
831 | "kind": "SCALAR",
832 | "name": "Boolean",
833 | "ofType": null
834 | }
835 | },
836 | "isDeprecated": false,
837 | "deprecationReason": null
838 | },
839 | {
840 | "name": "deprecationReason",
841 | "description": null,
842 | "args": [],
843 | "type": {
844 | "kind": "SCALAR",
845 | "name": "String",
846 | "ofType": null
847 | },
848 | "isDeprecated": false,
849 | "deprecationReason": null
850 | }
851 | ],
852 | "inputFields": null,
853 | "interfaces": [],
854 | "enumValues": null,
855 | "possibleTypes": null
856 | },
857 | {
858 | "kind": "OBJECT",
859 | "name": "__Directive",
860 | "description":
861 | "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.",
862 | "fields": [
863 | {
864 | "name": "name",
865 | "description": null,
866 | "args": [],
867 | "type": {
868 | "kind": "NON_NULL",
869 | "name": null,
870 | "ofType": {
871 | "kind": "SCALAR",
872 | "name": "String",
873 | "ofType": null
874 | }
875 | },
876 | "isDeprecated": false,
877 | "deprecationReason": null
878 | },
879 | {
880 | "name": "description",
881 | "description": null,
882 | "args": [],
883 | "type": {
884 | "kind": "SCALAR",
885 | "name": "String",
886 | "ofType": null
887 | },
888 | "isDeprecated": false,
889 | "deprecationReason": null
890 | },
891 | {
892 | "name": "locations",
893 | "description": null,
894 | "args": [],
895 | "type": {
896 | "kind": "NON_NULL",
897 | "name": null,
898 | "ofType": {
899 | "kind": "LIST",
900 | "name": null,
901 | "ofType": {
902 | "kind": "NON_NULL",
903 | "name": null,
904 | "ofType": {
905 | "kind": "ENUM",
906 | "name": "__DirectiveLocation",
907 | "ofType": null
908 | }
909 | }
910 | }
911 | },
912 | "isDeprecated": false,
913 | "deprecationReason": null
914 | },
915 | {
916 | "name": "args",
917 | "description": null,
918 | "args": [],
919 | "type": {
920 | "kind": "NON_NULL",
921 | "name": null,
922 | "ofType": {
923 | "kind": "LIST",
924 | "name": null,
925 | "ofType": {
926 | "kind": "NON_NULL",
927 | "name": null,
928 | "ofType": {
929 | "kind": "OBJECT",
930 | "name": "__InputValue",
931 | "ofType": null
932 | }
933 | }
934 | }
935 | },
936 | "isDeprecated": false,
937 | "deprecationReason": null
938 | },
939 | {
940 | "name": "onOperation",
941 | "description": null,
942 | "args": [],
943 | "type": {
944 | "kind": "NON_NULL",
945 | "name": null,
946 | "ofType": {
947 | "kind": "SCALAR",
948 | "name": "Boolean",
949 | "ofType": null
950 | }
951 | },
952 | "isDeprecated": true,
953 | "deprecationReason": "Use `locations`."
954 | },
955 | {
956 | "name": "onFragment",
957 | "description": null,
958 | "args": [],
959 | "type": {
960 | "kind": "NON_NULL",
961 | "name": null,
962 | "ofType": {
963 | "kind": "SCALAR",
964 | "name": "Boolean",
965 | "ofType": null
966 | }
967 | },
968 | "isDeprecated": true,
969 | "deprecationReason": "Use `locations`."
970 | },
971 | {
972 | "name": "onField",
973 | "description": null,
974 | "args": [],
975 | "type": {
976 | "kind": "NON_NULL",
977 | "name": null,
978 | "ofType": {
979 | "kind": "SCALAR",
980 | "name": "Boolean",
981 | "ofType": null
982 | }
983 | },
984 | "isDeprecated": true,
985 | "deprecationReason": "Use `locations`."
986 | }
987 | ],
988 | "inputFields": null,
989 | "interfaces": [],
990 | "enumValues": null,
991 | "possibleTypes": null
992 | },
993 | {
994 | "kind": "ENUM",
995 | "name": "__DirectiveLocation",
996 | "description":
997 | "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.",
998 | "fields": null,
999 | "inputFields": null,
1000 | "interfaces": null,
1001 | "enumValues": [
1002 | {
1003 | "name": "QUERY",
1004 | "description": "Location adjacent to a query operation.",
1005 | "isDeprecated": false,
1006 | "deprecationReason": null
1007 | },
1008 | {
1009 | "name": "MUTATION",
1010 | "description": "Location adjacent to a mutation operation.",
1011 | "isDeprecated": false,
1012 | "deprecationReason": null
1013 | },
1014 | {
1015 | "name": "SUBSCRIPTION",
1016 | "description": "Location adjacent to a subscription operation.",
1017 | "isDeprecated": false,
1018 | "deprecationReason": null
1019 | },
1020 | {
1021 | "name": "FIELD",
1022 | "description": "Location adjacent to a field.",
1023 | "isDeprecated": false,
1024 | "deprecationReason": null
1025 | },
1026 | {
1027 | "name": "FRAGMENT_DEFINITION",
1028 | "description": "Location adjacent to a fragment definition.",
1029 | "isDeprecated": false,
1030 | "deprecationReason": null
1031 | },
1032 | {
1033 | "name": "FRAGMENT_SPREAD",
1034 | "description": "Location adjacent to a fragment spread.",
1035 | "isDeprecated": false,
1036 | "deprecationReason": null
1037 | },
1038 | {
1039 | "name": "INLINE_FRAGMENT",
1040 | "description": "Location adjacent to an inline fragment.",
1041 | "isDeprecated": false,
1042 | "deprecationReason": null
1043 | },
1044 | {
1045 | "name": "SCHEMA",
1046 | "description": "Location adjacent to a schema definition.",
1047 | "isDeprecated": false,
1048 | "deprecationReason": null
1049 | },
1050 | {
1051 | "name": "SCALAR",
1052 | "description": "Location adjacent to a scalar definition.",
1053 | "isDeprecated": false,
1054 | "deprecationReason": null
1055 | },
1056 | {
1057 | "name": "OBJECT",
1058 | "description": "Location adjacent to an object type definition.",
1059 | "isDeprecated": false,
1060 | "deprecationReason": null
1061 | },
1062 | {
1063 | "name": "FIELD_DEFINITION",
1064 | "description": "Location adjacent to a field definition.",
1065 | "isDeprecated": false,
1066 | "deprecationReason": null
1067 | },
1068 | {
1069 | "name": "ARGUMENT_DEFINITION",
1070 | "description": "Location adjacent to an argument definition.",
1071 | "isDeprecated": false,
1072 | "deprecationReason": null
1073 | },
1074 | {
1075 | "name": "INTERFACE",
1076 | "description": "Location adjacent to an interface definition.",
1077 | "isDeprecated": false,
1078 | "deprecationReason": null
1079 | },
1080 | {
1081 | "name": "UNION",
1082 | "description": "Location adjacent to a union definition.",
1083 | "isDeprecated": false,
1084 | "deprecationReason": null
1085 | },
1086 | {
1087 | "name": "ENUM",
1088 | "description": "Location adjacent to an enum definition.",
1089 | "isDeprecated": false,
1090 | "deprecationReason": null
1091 | },
1092 | {
1093 | "name": "ENUM_VALUE",
1094 | "description": "Location adjacent to an enum value definition.",
1095 | "isDeprecated": false,
1096 | "deprecationReason": null
1097 | },
1098 | {
1099 | "name": "INPUT_OBJECT",
1100 | "description":
1101 | "Location adjacent to an input object type definition.",
1102 | "isDeprecated": false,
1103 | "deprecationReason": null
1104 | },
1105 | {
1106 | "name": "INPUT_FIELD_DEFINITION",
1107 | "description":
1108 | "Location adjacent to an input object field definition.",
1109 | "isDeprecated": false,
1110 | "deprecationReason": null
1111 | }
1112 | ],
1113 | "possibleTypes": null
1114 | }
1115 | ],
1116 | "directives": [
1117 | {
1118 | "name": "skip",
1119 | "description":
1120 | "Directs the executor to skip this field or fragment when the `if` argument is true.",
1121 | "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"],
1122 | "args": [
1123 | {
1124 | "name": "if",
1125 | "description": "Skipped when true.",
1126 | "type": {
1127 | "kind": "NON_NULL",
1128 | "name": null,
1129 | "ofType": {
1130 | "kind": "SCALAR",
1131 | "name": "Boolean",
1132 | "ofType": null
1133 | }
1134 | },
1135 | "defaultValue": null
1136 | }
1137 | ]
1138 | },
1139 | {
1140 | "name": "include",
1141 | "description":
1142 | "Directs the executor to include this field or fragment only when the `if` argument is true.",
1143 | "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"],
1144 | "args": [
1145 | {
1146 | "name": "if",
1147 | "description": "Included when true.",
1148 | "type": {
1149 | "kind": "NON_NULL",
1150 | "name": null,
1151 | "ofType": {
1152 | "kind": "SCALAR",
1153 | "name": "Boolean",
1154 | "ofType": null
1155 | }
1156 | },
1157 | "defaultValue": null
1158 | }
1159 | ]
1160 | },
1161 | {
1162 | "name": "deprecated",
1163 | "description":
1164 | "Marks an element of a GraphQL schema as no longer supported.",
1165 | "locations": ["FIELD_DEFINITION", "ENUM_VALUE"],
1166 | "args": [
1167 | {
1168 | "name": "reason",
1169 | "description":
1170 | "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).",
1171 | "type": {
1172 | "kind": "SCALAR",
1173 | "name": "String",
1174 | "ofType": null
1175 | },
1176 | "defaultValue": "\"No longer supported\""
1177 | }
1178 | ]
1179 | }
1180 | ]
1181 | }
1182 | }
1183 | }
1184 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "0.1.0",
4 | "scripts": {
5 | "build": "bsb -make-world && webpack --mode=production",
6 | "start": "bsb -make-world -w",
7 | "start-server": "nodemon lib/js/src/index.bs.js",
8 | "start-web": "webpack --watch --mode=development",
9 | "start-reason": "bsb -make-world -w",
10 | "clean": "bsb -clean-world",
11 | "test": "jest --watch",
12 | "deploy":
13 | "now -e ALGOLIA_API_KEY=@algolia-api-key -e ALGOLIA_APPLICATION_ID=@algolia-application-id --docker"
14 | },
15 | "husky": {
16 | "hooks": {
17 | "pre-commit": "lint-staged"
18 | }
19 | },
20 | "lint-staged": {
21 | "*.{re,rei}": ["refmt --in-place", "git add"],
22 | "*.{js,json,css,md}": ["prettier --write", "git add"]
23 | },
24 | "keywords": ["BuckleScript"],
25 | "author": "",
26 | "license": "MIT",
27 | "devDependencies": {
28 | "@glennsl/bs-jest": "^0.4.1",
29 | "bs-enzyme": "^0.3.1",
30 | "bs-platform": "^2.1.0",
31 | "enzyme": "^3.3.0",
32 | "enzyme-adapter-react-16": "^1.1.1",
33 | "graphql_ppx": "^0.2.1",
34 | "husky": "^0.15.0-rc.8",
35 | "jest": "^22.3.0",
36 | "lint-staged": "^7.0.0",
37 | "nodemon": "^1.14.11",
38 | "prettier": "^1.10.2",
39 | "webpack": "^4.0.0",
40 | "webpack-cli": "^2.0.8"
41 | },
42 | "dependencies": {
43 | "algoliasearch": "^3.24.9",
44 | "apollo-cache-inmemory": "^1.1.7",
45 | "apollo-client": "^2.2.2",
46 | "apollo-link-context": "^1.0.3",
47 | "apollo-link-error": "^1.0.3",
48 | "apollo-link-http": "^1.3.2",
49 | "apollo-link-schema": "^1.0.3",
50 | "body-parser": "^1.18.2",
51 | "bs-algolia": "^0.0.1",
52 | "bs-apollo-server-express": "^0.3.1",
53 | "bs-express": "^0.0.6",
54 | "bs-graphql": "^0.3.1",
55 | "bs-graphql-tools": "^0.3.1",
56 | "bs-nice": "http://github.com/hehk/bs-nice",
57 | "bs-nice-components": "http://github.com/hehk/bs-nice-components",
58 | "express": "^4.16.2",
59 | "graphql": "^0.12.3",
60 | "graphql-tag": "^2.6.1",
61 | "graphql-tools": "^2.19.0",
62 | "lodash.debounce": "^4.0.8",
63 | "reason-apollo": "^0.6.17",
64 | "reason-react": "^0.3.1",
65 | "reason-react-context": "^0.1.0"
66 | },
67 | "jest": {
68 | "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.bs.js?$"
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/snippets/SyntaxPatternMatchWithoutSwitch.re:
--------------------------------------------------------------------------------
1 | /* @title Pattern match without switch */
2 | /* @section Syntax */
3 | /* @description Cannot believe i forgot this purty */
4 | /* @type none */
5 | /* @content */
6 | let patternMatch =
7 | fun
8 | | 0 => "zero"
9 | | 1 => "one"
10 | | _ => "way too big";
11 |
12 | let funnyAdd = x =>
13 | fun
14 | | 0 => 0
15 | | 1 => 1
16 | | n => x + n;
17 |
18 | /* @example */
19 | patternMatch(0); /* zero */
20 |
21 | patternMatch(1); /* one */
22 |
23 | patternMatch(1337); /* way too big */
24 |
--------------------------------------------------------------------------------
/snippets/listMap.re:
--------------------------------------------------------------------------------
1 | /* @title Map */
2 | /* @section List */
3 | /* @description This function does stuff */
4 | /* @type let map: ('a => 'b, list('a)) => list('b) */
5 | /* @content */
6 | let a = [1, 2, 3];
7 |
8 | let b = List.map(x => x + 1, a);
9 | /* @example */
10 |
--------------------------------------------------------------------------------
/snippets/listReduce.re:
--------------------------------------------------------------------------------
1 | /* @title Reduce */
2 | /* @section List */
3 | /* @description hope this works */
4 | /* @type let reduce: (('a, 'b) => 'a, 'a, list('b)) => 'b; */
5 | /* @content */
6 | let reduce = List.fold_left;
7 |
8 | /* @example */
9 | reduce((a, b) => a + b, 0, [1, 2, 3]); /* 6 */
10 |
--------------------------------------------------------------------------------
/snippets/operator__and.re:
--------------------------------------------------------------------------------
1 | /* @title (&&) And Operator */
2 | /* @section Operator */
3 | /* @description Standard and boolean operator. */
4 | /* @type let (&&): (bool, bool) => bool */
5 | /* @content */
6 | let a = true && false; /* false */
7 |
8 | let b = true && true; /* true */
9 |
10 | let c = false && false; /* false */
11 | /* @example */
12 |
--------------------------------------------------------------------------------
/snippets/operator__applicationOperator.re:
--------------------------------------------------------------------------------
1 | /* @title (@@) Application Operator */
2 | /* @section Operator */
3 | /* @description Takes a function and applies the next parameter to it. */
4 | /* @type let (@@): ('a => 'b, 'a) => 'b; */
5 | /* @content */
6 | let add = (a, b) => a + b;
7 |
8 | let add5 = add @@ 5; /* (5, b) => 5 + b */
9 |
10 | let a = add5 @@ 10; /* 15 */
11 | /* @example */
12 |
--------------------------------------------------------------------------------
/snippets/operator__comparisonGreaterThan.re:
--------------------------------------------------------------------------------
1 | /* @title (>) Greater Than Operator */
2 | /* @section Operator */
3 | /* @description Returns if a variable is greater than another. */
4 | /* @type let (>): ('a, 'a) => bool; */
5 | /* @content */
6 | let a = 5 > 4; /* true */
7 |
8 | let b = 2. > 3.; /* false */
9 |
10 | let x = "a" > "b"; /* false */
11 | /* @example */
12 |
--------------------------------------------------------------------------------
/snippets/operator__comparisonGreaterThanOrEqualTo.re:
--------------------------------------------------------------------------------
1 | /* @title (>=) Greater Than Or Equal to Operator */
2 | /* @section Operator */
3 | /* @description Returns if a variable is greater than or equal to another. */
4 | /* @type let (>=): ('a, 'a) => bool; */
5 | /* @content */
6 | let a = 5 >= 4; /* true */
7 |
8 | let b = 2. >= 2.; /* true */
9 |
10 | let x = "a" >= "b"; /* false */
11 | /* @example */
12 |
--------------------------------------------------------------------------------
/snippets/operator__comparisonLessOrEqualTo.re:
--------------------------------------------------------------------------------
1 | /* @title (<=) Less Than or Equal to Operator */
2 | /* @section Operator */
3 | /* @description Returns if a variable is less than or equal to another. */
4 | /* @type let (<=): ('a, 'a) => bool; */
5 | /* @content */
6 | let a = 5 <= 4; /* false */
7 |
8 | let b = 2. <= 2.; /* true */
9 |
10 | let x = "a" <= "b"; /* true */
11 | /* @example */
12 |
--------------------------------------------------------------------------------
/snippets/operator__comparisonLessThan.re:
--------------------------------------------------------------------------------
1 | /* @title (<) Less Than Operator */
2 | /* @section Operator */
3 | /* @description Returns if a variable is less than another. */
4 | /* @type let (<): ('a, 'a) => bool; */
5 | /* @content */
6 | let a = 5 < 4; /* false */
7 |
8 | let b = 2. < 3.; /* true */
9 |
10 | let x = "a" < "b"; /* true */
11 | /* @example */
12 |
--------------------------------------------------------------------------------
/snippets/operator__equals.re:
--------------------------------------------------------------------------------
1 | /* @title (===) Equals Operator */
2 | /* @section Operator */
3 | /* @description Compares if two values are equal. */
4 | /* @type let (===): ('a, 'a) => bool */
5 | /* @content */
6 | let a = 5 === 4; /* false */
7 |
8 | let b = 5 === 5; /* true */
9 | /* @example */
10 |
--------------------------------------------------------------------------------
/snippets/operator__exponentiation.re:
--------------------------------------------------------------------------------
1 | /* @title (**) Exponentiation */
2 | /* @section Operator */
3 | /* @description An operator to handle float exponentiation.*/
4 | /* @type let (**): (float, float) => float */
5 | /* @content */
6 | let a = 5. ** 5.;
7 |
8 | let b = 2. ** 0.5;
9 |
10 | /* @example */
11 | let x = 2. ** 0.3; /* 1.2311444133449163 */
12 |
--------------------------------------------------------------------------------
/snippets/operator__floatAddition.re:
--------------------------------------------------------------------------------
1 | /* @title (+.) Float Addition Operator */
2 | /* @section Operator */
3 | /* @description Handles adding two floats together. */
4 | /* @type let (+.): (float, float) => float */
5 | /* @content */
6 | let a = 5. +. 5.; /* 10. */
7 |
8 | let b = 1. +. 0.5; /* 1.5 */
9 | /* @example */
10 |
--------------------------------------------------------------------------------
/snippets/operator__floatDivision.re:
--------------------------------------------------------------------------------
1 | /* @title (/.) Float Division Operator */
2 | /* @section Operator */
3 | /* @description Handles dividing two floats together.*/
4 | /* @type let (/.): (float, float) => float */
5 | /* @content */
6 | let a = 5. /. 2.; /* 2.5 */
7 |
8 | let b = 1. /. 0.5; /* 2.0 */
9 | /* @example */
10 |
--------------------------------------------------------------------------------
/snippets/operator__floatMultiplication.re:
--------------------------------------------------------------------------------
1 | /* @title (*.) Float Multiplication */
2 | /* @section Operator */
3 | /* @description Handles mutlication of floating point numbers.*/
4 | /* @type let (*.): (float, float) => float */
5 | /* @content */
6 | let a = 5. *. 5.;
7 |
8 | let b = 2. *. 0.5;
9 |
10 | /* @example */
11 | let x = 2. *. 0.3; /* 0.6 */
12 |
--------------------------------------------------------------------------------
/snippets/operator__floatSubtraction.re:
--------------------------------------------------------------------------------
1 | /* @title (-.) Float Subtraction Operator */
2 | /* @section Operator */
3 | /* @description Handles subtracting two floats together. */
4 | /* @type let (-.): (float, float) => float */
5 | /* @content */
6 | let a = 5. -. 5.; /* 0. */
7 |
8 | let b = 1. -. 0.5; /* 0.5 */
9 | /* @example */
10 |
--------------------------------------------------------------------------------
/snippets/operator__integerAddition.re:
--------------------------------------------------------------------------------
1 | /* @title (+) Integer Addition Operator */
2 | /* @section Operator */
3 | /* @description Handles adding two integers together. */
4 | /* @type let (+): (int, int) => int */
5 | /* @content */
6 | let a = 5 + 5; /* 10 */
7 |
8 | let b = 1 + 2; /* 3 */
9 | /* @example */
10 |
--------------------------------------------------------------------------------
/snippets/operator__integerDivision.re:
--------------------------------------------------------------------------------
1 | /* @title (/) Integer Division Operator */
2 | /* @section Operator */
3 | /* @description Handles division two integers together. */
4 | /* @type let (/): (int, int) => int */
5 | /* @content */
6 | let a = 5 / 2; /* 2 */
7 |
8 | let b = 2 / 2; /* 1 */
9 | /* @example */
10 |
--------------------------------------------------------------------------------
/snippets/operator__integerMultiplication.re:
--------------------------------------------------------------------------------
1 | /* @title (*) Multiplication Operator */
2 | /* @section Operator */
3 | /* @description An operator for handling integer multiplication. */
4 | /* @type let (*): (int, int) => int */
5 | /* @content */
6 | let a = 5 * 5;
7 |
8 | let b = 1 * 2;
9 |
10 | /* @example */
11 | let x = 2 * 3; /* 6 */
12 |
--------------------------------------------------------------------------------
/snippets/operator__integerSubtraction.re:
--------------------------------------------------------------------------------
1 | /* @title (-) Integer Subtraction Operator */
2 | /* @section Operator */
3 | /* @description Handles subtracting two integers together. */
4 | /* @type let (-): (int, int) => int */
5 | /* @content */
6 | let a = 5 - 5; /* 0 */
7 |
8 | let b = 1 - 2; /* -1 */
9 | /* @example */
10 |
--------------------------------------------------------------------------------
/snippets/operator__listConcatination.re:
--------------------------------------------------------------------------------
1 | /* @title (@) List Concatination Operator */
2 | /* @section Operator */
3 | /* @description Concat two lists. */
4 | /* @type let (@): (list('a), list('a)) => list('a) */
5 | /* @content */
6 |
7 | let a = [1] @ [2]; /* [1, 2] */
8 | /* @example */
9 |
--------------------------------------------------------------------------------
/snippets/operator__logicalAnd.re:
--------------------------------------------------------------------------------
1 | /* @title (land) Logical And Operator */
2 | /* @section Operator */
3 | /* @description Bitwise logical and. */
4 | /* @type let (land): (int, int) => int */
5 | /* @content */
6 |
7 | let a = 12 land 10; /* 8 */
8 | /* @example */
9 |
--------------------------------------------------------------------------------
/snippets/operator__logicalOr.re:
--------------------------------------------------------------------------------
1 | /* @title (lor) Logical Or Operator */
2 | /* @section Operator */
3 | /* @description Bitwise logical or. */
4 | /* @type let (lor): (int, int) => int */
5 | /* @content */
6 |
7 | let a = 12 lor 10; /* 14 */
8 | /* @example */
9 |
--------------------------------------------------------------------------------
/snippets/operator__logicalXor.re:
--------------------------------------------------------------------------------
1 | /* @title (lxor) Logical Exclusive Or Operator */
2 | /* @section Operator */
3 | /* @description Bitwise logical exclusive or.*/
4 | /* @type let (lxor): (int, int) => int */
5 | /* @content */
6 |
7 | let a = 12 lxor 10; /* 6 */
8 | /* @example */
9 |
--------------------------------------------------------------------------------
/snippets/operator__modulus.re:
--------------------------------------------------------------------------------
1 | /* @title (mod) Modulus Operator */
2 | /* @section Operator */
3 | /* @description Integer remainder. */
4 | /* @type let (mod): (int, int) => int */
5 | /* @content */
6 |
7 | let a = 12 mod 10; /* 2 */
8 | /* @example */
9 |
--------------------------------------------------------------------------------
/snippets/operator__notEquals.re:
--------------------------------------------------------------------------------
1 | /* @title (!==) Not Equals Operator */
2 | /* @section Operator */
3 | /* @description Negation of the === operator. */
4 | /* @type let (!==): ('a, 'a) => bool; */
5 | /* @content */
6 | let a = 5 !== 4; /* true */
7 |
8 | let b = 5 !== 5; /* false */
9 | /* @example */
10 |
--------------------------------------------------------------------------------
/snippets/operator__pipe.re:
--------------------------------------------------------------------------------
1 | /* @title (|>) Pipe Operator */
2 | /* @section Operator */
3 | /* @description Reverse-application operator. */
4 | /* @type let (|>): ('a, 'a => 'b) => 'b; */
5 | /* @content */
6 | let add = (a, b) => a + b;
7 |
8 | let add5 = add(5);
9 |
10 | let a = 10 |> add5; /* 15 */
11 | /* @example */
12 |
--------------------------------------------------------------------------------
/snippets/operator__referenceAssignment.re:
--------------------------------------------------------------------------------
1 | /* @title (:=) Reference Assignment Operator */
2 | /* @section Operator */
3 | /* @description Changes the value stored in a reference. */
4 | /* @type let (:=): (ref('a), 'a) => unit; */
5 | /* @content */
6 | let a = ref(5);
7 |
8 | a := 4;
9 |
10 | let b = a^ == 4; /* true */
11 |
12 | /* @example */
13 | Js.log(a^);
14 |
--------------------------------------------------------------------------------
/snippets/operator__referenceContent.re:
--------------------------------------------------------------------------------
1 | /* @title (^) Reference Content Operator */
2 | /* @section Operator */
3 | /* @description returns the content of a reference. */
4 | /* @type let (^): ref('a) => 'a; */
5 | /* @content */
6 | let a = ref(5);
7 |
8 | let b = a^;
9 |
10 | /* @example */
11 | Js.log(a^);
12 |
--------------------------------------------------------------------------------
/snippets/operator__shiftLeft.re:
--------------------------------------------------------------------------------
1 | /* @title (asr) Shift Left Operator */
2 | /* @section Operator */
3 | /* @description (n lsl m) Shift n to the left by m bits. */
4 | /* @type let (asr): (int, int) => int; */
5 | /* @content */
6 |
7 | let a = 7 lsl 1; /* 14 */
8 | /* @example */
9 |
--------------------------------------------------------------------------------
/snippets/operator__shiftRight.re:
--------------------------------------------------------------------------------
1 | /* @title (asr) or (lsr) Shift Right Operator */
2 | /* @section Operator */
3 | /* @description (n asr m) or (n lsr m) Shift n to the right by m bits. */
4 | /* @type let (asr): (int, int) => int; */
5 | /* @content */
6 | let a = 7 asr 1; /* 3 */
7 |
8 | let b = 7 lsr 1; /* 3 */
9 | /* @example */
10 |
--------------------------------------------------------------------------------
/snippets/operator__stringConcatination.re:
--------------------------------------------------------------------------------
1 | /* @title (++) String Concatination Operator */
2 | /* @section Operator */
3 | /* @description Concat two strings. */
4 | /* @type let (++): (string, string) => string */
5 | /* @content */
6 |
7 | let a = "abc" ++ "def"; /* "abcdef" */
8 | /* @example */
9 |
--------------------------------------------------------------------------------
/src/bindings/apollo.re:
--------------------------------------------------------------------------------
1 | module type Client = {
2 | module type Query = {
3 | type response =
4 | | Loading
5 | | Loaded(Js.Json.t)
6 | | Failed(string);
7 | type state = {
8 | response,
9 | variables: Js.Json.t
10 | };
11 | type action =
12 | | Result(string)
13 | | Error(string);
14 | let sendQuery: (~query: 'query, ~reducer: 'reduce) => unit;
15 | let component:
16 | string =>
17 | ReasonReact.componentSpec(
18 | state,
19 | ReasonReact.stateless,
20 | ReasonReact.noRetainedProps,
21 | ReasonReact.noRetainedProps,
22 | action
23 | );
24 | let make: (~query: 'query, 'children) => ReasonReact.reactClass;
25 | };
26 | module type Mutation = {};
27 | };
28 |
29 | module type Query = {
30 | type response =
31 | | Loading
32 | | Loaded(Js.Json.t)
33 | | Failed(string);
34 | type state = {
35 | response,
36 | variables: Js.Json.t
37 | };
38 | type action =
39 | | Result(string)
40 | | Error(string);
41 | let sendQuery:
42 | (
43 | ~query: {
44 | ..
45 | "query": string,
46 | "variables": Js.Json.t
47 | },
48 | ~reduce: (unit => action, unit) => 'a
49 | ) =>
50 | unit;
51 | let component:
52 | ReasonReact.componentSpec(
53 | state,
54 | ReasonReact.stateless,
55 | ReasonReact.noRetainedProps,
56 | ReasonReact.noRetainedProps,
57 | action
58 | );
59 | let make:
60 | (
61 | ~query: {
62 | ..
63 | "query": string,
64 | "variables": Js.Json.t,
65 | "parse": 'a
66 | },
67 | (response, 'a) => ReasonReact.reactElement
68 | ) =>
69 | ReasonReact.componentSpec(
70 | state,
71 | state,
72 | ReasonReact.noRetainedProps,
73 | ReasonReact.noRetainedProps,
74 | action
75 | );
76 | };
77 |
78 | type apolloState =
79 | | None
80 | | Some((module Query));
81 |
82 | module Context =
83 | ReasonReactContext.CreateContext(
84 | {
85 | type state = apolloState;
86 | let name = "Apollo";
87 | let defaultValue = None;
88 | }
89 | );
90 |
--------------------------------------------------------------------------------
/src/bindings/apolloLinkSchema.re:
--------------------------------------------------------------------------------
1 | type schema('a) = {
2 | .
3 | "resolvers": {. "Query": 'a},
4 | "typeDefs": string
5 | };
6 |
7 | type config = {. "schema": GraphQL.Type.schema};
8 |
9 | [@bs.module "apollo-link-schema"] [@bs.new]
10 | external _make : config => ReasonApolloTypes.apolloLink = "SchemaLink";
11 |
12 | let make = _make;
13 |
--------------------------------------------------------------------------------
/src/config.re:
--------------------------------------------------------------------------------
1 | type t = {
2 | port: int,
3 | algoliaApplicationId: string,
4 | algoliaAPIKey: string
5 | };
6 |
7 | let getEnvVar = (key) =>
8 | switch (key |> Js.Dict.get(Node.Process.process##env)) {
9 | | None => ""
10 | | Some(x) => x
11 | };
12 |
13 | let env = {
14 | port: 3000,
15 | algoliaApplicationId: getEnvVar("ALGOLIA_APPLICATION_ID"),
16 | algoliaAPIKey: getEnvVar("ALGOLIA_API_KEY")
17 | };
18 |
--------------------------------------------------------------------------------
/src/index.re:
--------------------------------------------------------------------------------
1 | let app = Express.App.make();
2 |
3 | [@bs.module "body-parser"]
4 | external bodyParserJson : unit => Express.Middleware.t = "json";
5 |
6 | let graphqlMiddleware =
7 | GraphQLTools.makeExecutableSchema(Graphql.schema)
8 | |> ApolloServerExpress.createGraphQLExpressMiddleware;
9 |
10 | let graphiqlMiddleware =
11 | ApolloServerExpress.createGraphiQLExpressMiddleware("/graphql");
12 |
13 | Express.App.use(app, bodyParserJson());
14 |
15 | Express.App.useOnPath(app, graphqlMiddleware, ~path="/graphql");
16 |
17 | Express.App.useOnPath(app, graphiqlMiddleware, ~path="/graphiql");
18 |
19 | Express.App.useOnPath(
20 | app,
21 | ~path="/dist",
22 | {
23 | let options = Express.Static.defaultOptions();
24 | Express.Static.make("dist", options) |> Express.Static.asMiddleware;
25 | }
26 | );
27 |
28 | Express.App.useOnPath(
29 | app,
30 | Express.Middleware.from(
31 | {
32 | let body =
33 | ReactDOMServerRe.renderToString(
34 |
35 | );
36 | let styles = Template.generateStyles(~html=body, ());
37 | let html = Template.make(~body, ~styles, ~title="30s of Reason", ());
38 | (_req, res, _next) => Express.Response.sendString(res, html);
39 | }
40 | ),
41 | ~path="/"
42 | );
43 |
44 | let onListen = e => {
45 | let port = string_of_int(Config.env.port);
46 | let message = {j|
47 | GraphQL => localhost:$port/graphql
48 | GraphiQL => localhost:$port/graphiql
49 | Web => localhost:$port/
50 | |j};
51 | switch e {
52 | | exception (Js.Exn.Error(e)) =>
53 | Js.log(e);
54 | Node.Process.exit(1);
55 | | _ => Js.log(message)
56 | };
57 | };
58 |
59 | Express.App.listen(app, ~onListen, ());
60 |
--------------------------------------------------------------------------------
/src/mocks/apolloMock.re:
--------------------------------------------------------------------------------
1 | type dataObject = {
2 | .
3 | "__typename": string,
4 | "id": string,
5 | "key": string
6 | };
7 |
8 | let cache =
9 | ApolloInMemoryCache.createInMemoryCache(
10 | ~dataIdFromObject=(obj: dataObject) => obj##id,
11 | ()
12 | );
13 |
14 | type schema('a) = {
15 | .
16 | "resolvers": {. "Query": 'a},
17 | "typeDefs": string
18 | };
19 |
20 | [@bs.module "graphql-tools"]
21 | external addMockFunctionsToSchema :
22 | {. "schema": schema('a)} => GraphQL.Type.schema =
23 | "addMockFunctionsToSchema";
24 |
25 | [@bs.module "graphql-tools"]
26 | external makeExecutableSchema : {. "typeDefs": string} => schema(unit) =
27 | "makeExecutableSchema";
28 |
29 | let schema = {
30 | let executableSchema = makeExecutableSchema({"typeDefs": Graphql.types});
31 | addMockFunctionsToSchema({"schema": executableSchema});
32 | };
33 |
34 | let link = ApolloLinkSchema.make({"schema": schema});
35 |
36 | module Client =
37 | ReasonApollo.CreateClient(
38 | {
39 | let apolloClient =
40 | ReasonApollo.createApolloClient(
41 | ~cache,
42 | ~link,
43 | ~ssrMode=Js.Boolean.to_js_boolean(true),
44 | ()
45 | );
46 | }
47 | );
48 |
--------------------------------------------------------------------------------
/src/server/apolloServer.re:
--------------------------------------------------------------------------------
1 | type dataObject = {
2 | .
3 | "__typename": string,
4 | "id": string,
5 | "key": string
6 | };
7 |
8 | let cache =
9 | ApolloInMemoryCache.createInMemoryCache(
10 | ~dataIdFromObject=(obj: dataObject) => obj##id,
11 | ()
12 | );
13 |
14 | let link =
15 | ApolloLinkSchema.make({
16 | "schema": GraphQLTools.makeExecutableSchema(Graphql.schema)
17 | });
18 |
19 | module Client =
20 | ReasonApollo.CreateClient(
21 | {
22 | let apolloClient =
23 | ReasonApollo.createApolloClient(~cache, ~link, ~ssrMode=Js.true_, ());
24 | }
25 | );
26 |
--------------------------------------------------------------------------------
/src/server/graphql.re:
--------------------------------------------------------------------------------
1 | let types = Snippet.graphQLType;
2 |
3 | let query = {|
4 | type Query {
5 | allSnippets(query: String): [Snippet]!
6 | snippet(id: ID!): Snippet!
7 | }
8 | |};
9 |
10 | let resolvers = {
11 | let snippet = Snippet.Handler.make();
12 | {"Query": Js.Obj.empty() |> Js.Obj.assign(snippet.queries)};
13 | };
14 |
15 | let schema = {"typeDefs": types ++ query, "resolvers": resolvers};
16 |
--------------------------------------------------------------------------------
/src/server/snippet.re:
--------------------------------------------------------------------------------
1 | type t = {
2 | .
3 | "id": string,
4 | "title": string,
5 | "content": string,
6 | "description": string,
7 | "example": string,
8 | "jsOutput": string,
9 | "objectID": string,
10 | "section": string,
11 | "typeSpec": string
12 | };
13 |
14 | let graphQLType = {|
15 | type Snippet {
16 | id: ID! @unique
17 | title: String!
18 | content: String!
19 | description: String!
20 | example: String!
21 | jsOutput: String!
22 | section: String!
23 | typeSpec: String!
24 | }
25 | |};
26 |
27 | module Scraper = {
28 | let workingReDir = "./snippets/";
29 | let workingJsDir = "./lib/js/snippets/";
30 | let listSnippetNames = () =>
31 | Node.Fs.readdirSync(workingReDir)
32 | |> Array.map(name => String.sub(name, 0, String.length(name) - 3));
33 | let loadSnippetRawRe = name =>
34 | Node.Fs.readFileAsUtf8Sync(workingReDir ++ name ++ ".re");
35 | let loadSnippetJsOutput = name =>
36 | Node.Fs.readFileAsUtf8Sync(workingJsDir ++ name ++ ".bs.js");
37 | let createSnippet = (~id, ~rawRe, ~jsOutput, ~name, ()) => {
38 | let pattern =
39 | Js.Re.fromString(
40 | "(\\/\\* @title )([\\s\\S]*)(\\*\\/[\\s\\S]*)"
41 | ++ "(\\/\\* @section )([\\s\\S]*)(\\*\\/[\\s\\S]*)"
42 | ++ "(\\/\\* @description )([\\s\\S]*)(\\*\\/[\\s\\S]*)"
43 | ++ "(\\/\\* @type )([\\s\\S]*)(\\*\\/[\\s\\S]*)"
44 | ++ "(\\/\\* @content \\*\\/)([\\s\\S]*)"
45 | ++ "(\\/\\* @example \\*\\/)([\\s\\S]*)"
46 | );
47 | /* God i hate regex in Reason */
48 | let segments =
49 | switch (Js.Re.exec(rawRe, pattern)) {
50 | | None => [||]
51 | | Some(result) =>
52 | result
53 | |> Js.Re.captures
54 | |> Array.map(Js.Nullable.to_opt)
55 | |> Array.map(segment =>
56 | switch segment {
57 | | None => ""
58 | | Some(x) => x
59 | }
60 | )
61 | };
62 | switch segments {
63 | | [|
64 | _all,
65 | _titleHeader,
66 | title,
67 | _titleEnd,
68 | _sectionHeader,
69 | section,
70 | _sectionEnd,
71 | _descHeader,
72 | description,
73 | _descEnd,
74 | _typeHeader,
75 | typeSpec,
76 | _typeEnd,
77 | _contentHeader,
78 | content,
79 | _exampleHeader,
80 | example
81 | |] => {
82 | "id": id,
83 | "title": String.trim(title),
84 | "description": String.trim(description),
85 | "typeSpec": String.trim(typeSpec),
86 | "section": String.trim(section),
87 | "content": String.trim(content),
88 | "example": String.trim(example),
89 | "jsOutput": jsOutput,
90 | "objectID": name
91 | }
92 | | _ => {
93 | "id": "",
94 | "description": "",
95 | "title": "",
96 | "content": "",
97 | "example": "",
98 | "jsOutput": "",
99 | "section": "",
100 | "typeSpec": "",
101 | "objectID": name
102 | }
103 | };
104 | };
105 | let loadSnippets = () =>
106 | listSnippetNames()
107 | |> Array.mapi((i, name) =>
108 | createSnippet(
109 | ~id={j|$(i)-$(name)|j},
110 | ~rawRe=loadSnippetRawRe(name),
111 | ~jsOutput=loadSnippetJsOutput(name),
112 | ~name,
113 | ()
114 | )
115 | )
116 | |> Array.to_list
117 | |> List.filter(snippet => snippet##id === "" ? false : true)
118 | |> Array.of_list;
119 | };
120 |
121 | module Store = {
122 | let algoliaClient =
123 | Algolia.Client.make(
124 | ~applicationId=Config.env.algoliaApplicationId,
125 | ~apiKey=Config.env.algoliaAPIKey,
126 | ()
127 | );
128 | let algoliaIndex = Algolia.Index.make("30s-snippets", algoliaClient);
129 | let local = Scraper.loadSnippets();
130 | Algolia.Index.addObjects(local, algoliaIndex);
131 | let getByQuery = query =>
132 | algoliaIndex
133 | |> Algolia.Index.search({"query": query})
134 | |> Js.Promise.then_(x => Js.Promise.resolve(x##hits));
135 | let getById = id =>
136 | local
137 | |> Array.to_list
138 | |> List.filter(snippet => snippet##id == id)
139 | |> List.hd;
140 | };
141 |
142 | module Handler = {
143 | type graphQLContext;
144 | type resolvers('root) = {
145 | queries: {
146 | .
147 | "allSnippets":
148 | (
149 | Js.Nullable.t('root),
150 | {. "query": Js.Nullable.t(string)},
151 | Js.t(graphQLContext)
152 | ) =>
153 | Js.Promise.t(array(t)),
154 | "snippet":
155 | (Js.Nullable.t('root), {. "id": string}, Js.t(graphQLContext)) => t
156 | }
157 | };
158 | let make = () => {
159 | queries: {
160 | "allSnippets": (_root, input, _context) =>
161 | switch (Js.Nullable.to_opt(input##query)) {
162 | | Some(query) => Store.getByQuery(query)
163 | | None => Js.Promise.resolve([||])
164 | },
165 | "snippet": (_root, input, _context) => Store.getById(input##id)
166 | }
167 | };
168 | };
169 |
--------------------------------------------------------------------------------
/src/utils.re:
--------------------------------------------------------------------------------
1 | let ele_of_str = ReasonReact.stringToElement;
2 |
3 | let ele_of_arr = ReasonReact.arrayToElement;
4 |
5 | let ele_of_list = l => l |> Array.of_list |> ele_of_arr;
6 |
7 | type debounceOptions = {
8 | .
9 | "leading": bool,
10 | "maxWait": int,
11 | "trailing": bool
12 | };
13 |
14 | module Debounce = {
15 | [@bs.module]
16 | external _make :
17 | ('fArgs => 'fOutput, int, debounceOptions) => [@bs] ('fArgs => 'fOutput) =
18 | "lodash.debounce";
19 | let make = (~wait=0, ~options=Js.Obj.empty(), f) => _make(f, wait, options);
20 | let call = (input, f) => [@bs] f(input);
21 | };
22 |
--------------------------------------------------------------------------------
/src/web/apolloBrowser.re:
--------------------------------------------------------------------------------
1 | type dataObject = {
2 | .
3 | "__typename": string,
4 | "id": string,
5 | "key": string
6 | };
7 |
8 | let cache = ApolloInMemoryCache.createInMemoryCache(~dataIdFromObject=(obj: dataObject) => obj##id, ());
9 |
10 | let link = ApolloLinks.createHttpLink(~uri="/graphql", ());
11 |
12 | module Client =
13 | ReasonApollo.CreateClient(
14 | {
15 | let apolloClient = ReasonApollo.createApolloClient(~cache, ~link, ());
16 | }
17 | );
18 |
--------------------------------------------------------------------------------
/src/web/app.re:
--------------------------------------------------------------------------------
1 | type state = {search: string};
2 |
3 | type actions =
4 | | ChangeSearch(string);
5 |
6 | let changeSearch = send => {
7 | open Utils.Debounce;
8 | let update = make(newValue => send(ChangeSearch(newValue)), ~wait=250);
9 | newValue => update |> call(newValue);
10 | };
11 |
12 | let reducer = (action, _state) =>
13 | switch action {
14 | | ChangeSearch(newValue) => ReasonReact.Update({search: newValue})
15 | };
16 |
17 | let initialState = () => {search: ""};
18 |
19 | let component = ReasonReact.reducerComponent("App");
20 |
21 | let make = (~query, _children) => {
22 | ...component,
23 | initialState,
24 | reducer,
25 | render: ({state, send}) =>
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | };
36 |
--------------------------------------------------------------------------------
/src/web/browser.re:
--------------------------------------------------------------------------------
1 | [@bs.val] [@bs.module "react-dom"] external hydrate : (ReasonReact.reactElement, Dom.element) => unit = "hydrate";
2 |
3 | [@bs.val] [@bs.return nullable] external _getElementById : string => option(Dom.element) = "document.getElementById";
4 |
5 | let hydrateToElementWithId = (reactElement, id) =>
6 | switch (_getElementById(id)) {
7 | | None =>
8 | raise(Invalid_argument("ReactDOMRE.renderToElementWithId : no element of id " ++ (id ++ " found in the HTML.")))
9 | | Some(element) => hydrate(reactElement, element)
10 | };
11 |
12 | hydrateToElementWithId(, "react-root");
13 |
--------------------------------------------------------------------------------
/src/web/components/apolloContext.re:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/web/components/header.re:
--------------------------------------------------------------------------------
1 | open Nice;
2 |
3 | open Utils;
4 |
5 | open Theme;
6 |
7 | let component = ReasonReact.statelessComponent("Header");
8 |
9 | module Wrapper = (
10 | val NiceComponents.header(
11 | ~debugName="HeaderWrapper",
12 | [|
13 | BackgroundColor(Colors.red),
14 | Color(Colors.white),
15 | Padding(Spacing.large),
16 | Raw("font-size", Font.Size.large)
17 | |]
18 | )
19 | );
20 |
21 | module Logo = (
22 | val NiceComponents.div(
23 | ~debugName="HeaderLogo",
24 | [|Color(Colors.white), Raw("display", "inline"), FontWeight(Bold)|]
25 | )
26 | );
27 |
28 | module Nav = (
29 | val NiceComponents.ol(
30 | ~debugName="HeaderNav",
31 | [|
32 | Raw("list-style", "none"),
33 | Raw("float", "right"),
34 | Padding(Spacing.none),
35 | Margin(Spacing.none)
36 | |]
37 | )
38 | );
39 |
40 | module NavItem = (
41 | val NiceComponents.li(
42 | ~debugName="HeaderNavItem",
43 | [|Raw("float", "right"), MarginLeft(Spacing.large)|]
44 | )
45 | );
46 |
47 | module NavLink = (
48 | val NiceComponents.a(
49 | ~debugName="HeaderNavLink",
50 | [|Raw("color", "inherit"), TextDecorationLine(None_)|]
51 | )
52 | );
53 |
54 | let make = _children => {
55 | ...component,
56 | render: _self =>
57 |
58 |
59 |
60 | (ele_of_str("30s of Reason"))
61 |
62 |
72 |
73 |
74 | };
75 |
--------------------------------------------------------------------------------
/src/web/components/jsSnippet.re:
--------------------------------------------------------------------------------
1 | open Utils;
2 |
3 | module JsSnippetQuery = [%graphql
4 | {|
5 | query getJsSnippet($id: ID!) {
6 | snippet(id: $id) {
7 | jsOutput
8 | }
9 | }
10 | |}
11 | ];
12 |
13 | let component = ReasonReact.statelessComponent("JsSnippet");
14 |
15 | let title = "JavaScript Output";
16 |
17 | let renderLoading = () =>
18 |
19 |
20 | ;
21 |
22 | let renderFailed = () => ele_of_str("failed");
23 |
24 | let renderLoaded = text =>
;
25 |
26 | let make = (~id, _children) => {
27 | ...component,
28 | render: _self => {
29 | let query = JsSnippetQuery.make(~id, ());
30 |
34 | switch response {
35 | | Loading => renderLoading()
36 | | Failed(_error) => renderFailed()
37 | | Loaded(result) => renderLoaded(parse(result)##snippet##jsOutput)
38 | }
39 | )
40 | />;
41 | }
42 | };
43 |
--------------------------------------------------------------------------------
/src/web/components/query.re:
--------------------------------------------------------------------------------
1 | open Utils;
2 |
3 | /* Currently has to be done because the response type is internal to the Query module */
4 | type response =
5 | | Loading
6 | | Loaded(Js.Json.t)
7 | | Failed(string);
8 |
9 | let component = ReasonReact.statelessComponent("Query");
10 |
11 | let make = (~query, ~render, _children) => {
12 | ...component,
13 | render: _self =>
14 |
15 | ...(
16 | client =>
17 | switch client {
18 | | None => ele_of_str("No Client")
19 | | Some(apolloQuery) =>
20 | module ReasonApolloQuery = (val apolloQuery);
21 |
22 | ...(
23 | (response, parse) =>
24 | switch response {
25 | | Loading => render(Loading, parse)
26 | | Loaded(x) => render(Loaded(x), parse)
27 | | Failed(x) => render(Failed(x), parse)
28 | }
29 | )
30 | ;
31 | }
32 | )
33 |
34 | };
35 |
--------------------------------------------------------------------------------
/src/web/components/search.re:
--------------------------------------------------------------------------------
1 | open Theme;
2 |
3 | module Wrapper = (val NiceComponents.div([|Position(Relative)|]));
4 |
5 | module SearchIcon = (
6 | val NiceComponents.div([|
7 | Position(Absolute),
8 | Top(Percent(50.)),
9 | Raw("transform", "translateY(-50%)"),
10 | PaddingLeft(Spacing.normal)
11 | |])
12 | );
13 |
14 | module Input = (
15 | val NiceComponents.input(
16 | ~debugName="SearchInput",
17 | [|
18 | Raw("outline", "none"),
19 | Raw("border", "none"),
20 | Raw("box-sizing", "border-box"),
21 | BorderRadius(Frame.borderRadius),
22 | Display(Block),
23 | Width(Percent(100.)),
24 | Raw("box-shadow", Frame.Shadow.normal),
25 | Padding(Spacing.normal),
26 | PaddingLeft(Rem(3.)),
27 | MarginTop(Spacing.normal),
28 | Raw("font-size", Font.Size.normal),
29 | Raw("transition", Animation.Transition.normal),
30 | Select(":focus", [|Raw("box-shadow", Frame.Shadow.red)|])
31 | |]
32 | )
33 | );
34 |
35 | type state = {value: string};
36 |
37 | type action =
38 | | ChangeValue(string);
39 |
40 | let component = ReasonReact.reducerComponent("Search");
41 |
42 | let reducer = (action, _state) =>
43 | switch action {
44 | | ChangeValue(newValue) => ReasonReact.Update({value: newValue})
45 | };
46 |
47 | let make = (~initialValue="", ~onChange=_newValue => (), _children) => {
48 | ...component,
49 | initialState: () => {value: initialValue},
50 | reducer,
51 | render: ({send, state}) =>
52 |
53 |
54 | {
58 | let value = e##target##value;
59 | send(ChangeValue(value));
60 | onChange(value);
61 | }
62 | }
63 | />
64 |
65 | };
66 |
--------------------------------------------------------------------------------
/src/web/components/snippetItem.re:
--------------------------------------------------------------------------------
1 | open Utils;
2 |
3 | open Theme;
4 |
5 | module Toggle = (
6 | val NiceComponents.span(
7 | ~debugName="SnippetToggle",
8 | [|
9 | Raw("float", "right"),
10 | Color(Colors.red),
11 | Raw("transition", Animation.Transition.normal),
12 | Padding(Spacing.small),
13 | BorderRadius(Frame.borderRadius),
14 | Select(
15 | ":hover",
16 | [|
17 | BackgroundColor(Colors.red),
18 | Color(Colors.white),
19 | Raw("box-shadow", Frame.Shadow.red)
20 | |]
21 | )
22 | |]
23 | )
24 | );
25 |
26 | type state = {jsOutput: bool};
27 |
28 | let initialState = () => {jsOutput: false};
29 |
30 | type action =
31 | | ToggleJsOutput;
32 |
33 | let reducer = (action, state) =>
34 | switch action {
35 | | ToggleJsOutput => ReasonReact.Update({jsOutput: ! state.jsOutput})
36 | };
37 |
38 | let component = ReasonReact.reducerComponent("Snippet");
39 |
40 | let make = (~id, ~title, ~description, ~content, ~typeSpec, _children) => {
41 | ...component,
42 | initialState,
43 | reducer,
44 | render: ({state: {jsOutput}, send}) =>
45 |
46 | send(ToggleJsOutput)}>
47 | (jsOutput ? ele_of_str("Hide JS") : ele_of_str("Show JS"))
48 |
49 | (ele_of_str(title))
50 | (ele_of_str(description))
51 |
52 |
53 | (jsOutput ? : ele_of_str(""))
54 |
55 | };
56 |
57 | module Loading = {
58 | let component = ReasonReact.statelessComponent("SnippetLoading");
59 | let make = _children => {
60 | ...component,
61 | render: _self =>
62 |
63 |
64 | (ele_of_str("..."))
65 |
66 |
67 |
68 | };
69 | };
70 |
--------------------------------------------------------------------------------
/src/web/components/snippetList.re:
--------------------------------------------------------------------------------
1 | open Utils;
2 |
3 | module SnippetQuery = [%graphql
4 | {|
5 | query getAllSnippets($filter: String!) {
6 | allSnippets(query: $filter) {
7 | content,
8 | title,
9 | description,
10 | id,
11 | section,
12 | typeSpec
13 | }
14 | }
15 | |}
16 | ];
17 |
18 | let rec createSections = (~sections=[], snippets) =>
19 | switch snippets {
20 | | [] => List.rev(sections)
21 | | [hd, ..._] =>
22 | let (newSection, tl) =
23 | List.partition(x => x##section === hd##section, snippets);
24 | createSections(tl, ~sections=[newSection, ...sections]);
25 | };
26 |
27 | let rec filterOutVariant = (acc, l) =>
28 | switch l {
29 | | [] => List.rev(acc)
30 | | [hd, ...tl] =>
31 | switch hd {
32 | | None => filterOutVariant(acc, tl)
33 | | Some(x) => filterOutVariant([x, ...acc], tl)
34 | }
35 | };
36 |
37 | let renderSections = snippets =>
38 | snippets
39 | |> List.map(
40 | fun
41 | | [] => []
42 | | [hd, ..._] as section => {
43 | let sectionName = hd##section;
44 | [
45 |
46 | (ele_of_str(sectionName))
47 |
,
48 | ...section
49 | |> List.map(x =>
50 |
58 | )
59 | ];
60 | }
61 | )
62 | |> List.flatten;
63 |
64 | let component = ReasonReact.statelessComponent("SnippetList");
65 |
66 | let renderLoading = () =>
67 | [
68 | (ele_of_str("Loading"))
,
69 | ,
70 |
71 | ]
72 | |> ele_of_list;
73 |
74 | let renderFailed = () => ele_of_str("error");
75 |
76 | let renderLoaded = snippets =>
77 | snippets
78 | |> Array.to_list
79 | |> filterOutVariant([])
80 | |> createSections
81 | |> renderSections
82 | |> ele_of_list;
83 |
84 | let make = (~filter="", _children) => {
85 | ...component,
86 | render: _self => {
87 | let snippetQuery = SnippetQuery.make(~filter, ());
88 |
89 |
93 | switch response {
94 | | Loading => renderLoading()
95 | | Failed(_error) => renderFailed()
96 | | Loaded(result) => renderLoaded(parse(result)##allSnippets)
97 | }
98 | )
99 | />
100 | ;
101 | }
102 | };
103 |
--------------------------------------------------------------------------------
/src/web/elements/background.re:
--------------------------------------------------------------------------------
1 | include (
2 | val NiceComponents.div(
3 | ~debugName="Background",
4 | [|MinHeight(Vh(100.)), FontFamily("Karla, sans-serif"), BackgroundColor(Theme.Colors.secondary), Height(Percent(100.))|]
5 | )
6 | );
7 |
--------------------------------------------------------------------------------
/src/web/elements/card.re:
--------------------------------------------------------------------------------
1 | open Theme;
2 |
3 | include (
4 | val NiceComponents.div(
5 | ~debugName="Card",
6 | [|
7 | Raw("box-shadow", Frame.Shadow.normal),
8 | BackgroundColor(White),
9 | BorderRadius(Frame.borderRadius),
10 | Margin(Spacing.none),
11 | MarginTop(Spacing.normal),
12 | MarginBottom(Spacing.normal),
13 | Padding(Spacing.normal),
14 | PaddingBottom(Px(1)),
15 | |]
16 | )
17 | );
18 |
--------------------------------------------------------------------------------
/src/web/elements/code.re:
--------------------------------------------------------------------------------
1 | open Utils;
2 |
3 | open Theme;
4 |
5 | module Wrapper = (
6 | val NiceComponents.code(
7 | ~debugName="Code",
8 | [|
9 | Display(Block),
10 | Padding(Spacing.normal),
11 | PaddingTop(Spacing.none),
12 | BorderRadius(Frame.borderRadius),
13 | MarginBottom(Spacing.normal),
14 | BackgroundColor(Colors.black),
15 | Color(Colors.gray),
16 | Raw("box-shadow", Frame.Shadow.normal),
17 | Raw("font-size", "1rem"),
18 | LineHeight(1.5)
19 | |]
20 | )
21 | );
22 |
23 | module Line = (
24 | val NiceComponents.div(~debugName="Line", [|Raw("white-space", "pre")|])
25 | );
26 |
27 | module LineNumber = (
28 | val NiceComponents.span(
29 | ~debugName="LineNumber",
30 | [|
31 | MinWidth(Rem(2.)),
32 | Display(InlineBlock),
33 | Raw("user-select", "none"),
34 | Color(Colors.darkGray)
35 | |]
36 | )
37 | );
38 |
39 | module Language = (
40 | val NiceComponents.span(
41 | ~debugName="Language",
42 | [|Raw("float", "right"), Color(Colors.red)|]
43 | )
44 | );
45 |
46 | module Header = (
47 | val NiceComponents.div(
48 | ~debugName="CodeHeader",
49 | [|
50 | MarginBottom(Spacing.small),
51 | PaddingBottom(Spacing.small),
52 | PaddingTop(Spacing.small),
53 | Raw("border-bottom", "solid 1px gray")
54 | |]
55 | )
56 | );
57 |
58 | let component = ReasonReact.statelessComponent("Code");
59 |
60 | let make = (~text, ~language="re", ~title="Sample ReasonML", _children) => {
61 | ...component,
62 | render: _self =>
63 |
64 |
65 | (ele_of_str(title))
66 | (ele_of_str(language))
67 |
68 | (
69 | ele_of_arr(
70 | text
71 | |> Js.String.split("\n")
72 | |> Array.mapi((i, line) =>
73 |
74 | (ele_of_str(string_of_int(i)))
75 | (ele_of_str(line))
76 |
77 | )
78 | )
79 | )
80 |
81 | };
82 |
--------------------------------------------------------------------------------
/src/web/elements/divider.re:
--------------------------------------------------------------------------------
1 | open Theme;
2 |
3 | include (
4 | val NiceComponents.div(~debugName="divider", [|Height(Px(1)), BackgroundColor(Colors.red), Margin(Spacing.normal)|])
5 | );
6 |
--------------------------------------------------------------------------------
/src/web/elements/h1.re:
--------------------------------------------------------------------------------
1 | open Theme;
2 |
3 | include (
4 | val NiceComponents.h1(
5 | ~debugName="H1",
6 | [|
7 | Raw("font-size", Font.Size.huge),
8 | MarginBottom(Spacing.normal),
9 | MarginTop(Spacing.large),
10 | Color(Colors.red)
11 | |]
12 | )
13 | );
14 |
--------------------------------------------------------------------------------
/src/web/elements/h2.re:
--------------------------------------------------------------------------------
1 | open Theme;
2 |
3 | include (
4 | val NiceComponents.h2(
5 | ~debugName="H2",
6 | [|
7 | Raw("font-size", Font.Size.large),
8 | Margin(Spacing.none),
9 | MarginBottom(Spacing.normal),
10 | MarginTop(Spacing.large),
11 | Color(Colors.red)
12 | |]
13 | )
14 | );
15 |
--------------------------------------------------------------------------------
/src/web/elements/h3.re:
--------------------------------------------------------------------------------
1 | open Theme;
2 |
3 | include (
4 | val NiceComponents.h3(~debugName="H3", [|Raw("font-size", Font.Size.normal), Margin(Px(0)), MarginBottom(Rem(1.))|])
5 | );
6 |
--------------------------------------------------------------------------------
/src/web/elements/h4.re:
--------------------------------------------------------------------------------
1 | open Theme;
2 |
3 | include (
4 | val NiceComponents.h4(~debugName="H4", [|Raw("font-size", Font.Size.small), Margin(Px(0)), MarginBottom(Rem(1.))|])
5 | );
6 |
--------------------------------------------------------------------------------
/src/web/elements/loadingAnimation.re:
--------------------------------------------------------------------------------
1 | include (
2 | val NiceComponents.div(
3 | ~debugName="LoadingTransition",
4 | [|Raw("animation", "loadingAnimation 3s infinite ease")|]
5 | )
6 | );
7 |
--------------------------------------------------------------------------------
/src/web/elements/p.re:
--------------------------------------------------------------------------------
1 | open Theme;
2 |
3 | include (
4 | val NiceComponents.p(
5 | ~debugName="P",
6 | [|Margin(Spacing.none), MarginBottom(Spacing.normal)|]
7 | )
8 | );
9 |
--------------------------------------------------------------------------------
/src/web/elements/pageFrame.re:
--------------------------------------------------------------------------------
1 | include (
2 | val NiceComponents.div(
3 | ~debugName="PageFrame",
4 | [|MaxWidth(Px(960)), Raw("margin", "auto")|]
5 | )
6 | );
7 |
--------------------------------------------------------------------------------
/src/web/template.re:
--------------------------------------------------------------------------------
1 | let globalStyles = "body { margin: 0; padding: 0;} @keyframes loadingAnimation { 0%, 100% { opacity: 0.25;} 50% {opacity:\n0.5;}}";
2 |
3 | let make = (~body, ~styles, ~title, ()) => {j|
4 |
5 |
6 |
7 | $title
8 |
9 | $styles
10 |
11 |
12 |
13 | $body
14 |
15 |
16 |
17 |
18 |
19 | |j};
20 |
21 | let generateStyles = (~html="", ()) => {
22 | let css = NiceComponents.getStyles(html);
23 | {j||j};
24 | };
25 |
--------------------------------------------------------------------------------
/src/web/theme.re:
--------------------------------------------------------------------------------
1 | open Nice;
2 |
3 | module Colors = {
4 | let red = Hex("db4d3f");
5 | let lightRed = Hex("F2826E");
6 | let secondary = Hex("f8faff");
7 | let white = White;
8 | let black = Hex("282C34");
9 | let gray = Hex("ABB2BF");
10 | let darkGray = Hex("5C6370");
11 | };
12 |
13 | module Font = {
14 | let family = "Karla, sans-serif";
15 | module Size = {
16 | let huge = "2rem";
17 | let large = "1.5rem";
18 | let normal = "1.25rem";
19 | let small = "1rem";
20 | };
21 | };
22 |
23 | module Spacing = {
24 | let normal = Rem(1.);
25 | let small = Rem(0.5);
26 | let none = Rem(0.);
27 | let large = Rem(2.0);
28 | };
29 |
30 | module Frame = {
31 | let borderRadius = Rem(0.3);
32 | module Shadow = {
33 | let normal = "0 10px 40px 0 rgba(62,57,107,0.07), 0 2px 9px 0 rgba(62,57,107,0.06)";
34 | let darker = "0 10px 40px 0 rgba(62,57,107,0.20), 0 2px 9px 0 rgba(62,57,107,0.20)";
35 | let red = "0 10px 40px 0 rgba(219,77,63,0.37), 0 2px 9px 0 rgba(219,77,63,0.36);";
36 | };
37 |
38 | };
39 |
40 | module Animation = {
41 | module Transition = {
42 | let normal = "0.25s ease";
43 | };
44 | };
45 |
--------------------------------------------------------------------------------
/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.1.0",
3 | "command": "npm",
4 | "options": {
5 | "cwd": "${workspaceRoot}"
6 | },
7 | "isShellCommand": true,
8 | "args": [
9 | "run",
10 | "watch"
11 | ],
12 | "showOutput": "always",
13 | "isBackground": true,
14 | "problemMatcher": {
15 | "fileLocation": "absolute",
16 | "owner": "ocaml",
17 | "watching": {
18 | "activeOnStart": false,
19 | "beginsPattern": ">>>> Start compiling",
20 | "endsPattern": ">>>> Finish compiling"
21 | },
22 | "pattern": [
23 | {
24 | "regexp": "^File \"(.*)\", line (\\d+)(?:, characters (\\d+)-(\\d+))?:$",
25 | "file": 1,
26 | "line": 2,
27 | "column": 3,
28 | "endColumn": 4
29 | },
30 | {
31 | "regexp": "^(?:(?:Parse\\s+)?(Warning|[Ee]rror)(?:\\s+\\d+)?:)?\\s+(.*)$",
32 | "severity": 1,
33 | "message": 2,
34 | "loop": true
35 | }
36 | ]
37 | }
38 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require("webpack");
2 | const path = require("path");
3 | const UglifyWebpackPlugin = require("uglifyjs-webpack-plugin");
4 |
5 | const dir = p => path.resolve(__dirname, p);
6 | module.exports = {
7 | entry: "./lib/js/src/web/browser.bs.js",
8 | output: {
9 | path: dir("./dist"),
10 | publicPath: "/",
11 | filename: "bundle.js"
12 | },
13 | module: {
14 | rules: [
15 | {
16 | test: /\.js$/,
17 | exclude: /node_modules/
18 | }
19 | ]
20 | },
21 | resolve: {
22 | extensions: [".js", ".bs.js"]
23 | }
24 | };
25 |
--------------------------------------------------------------------------------