Skip to content

Commit 6b5ae7f

Browse files
committed
Demo using Cloudflare Pages Functions
1 parent 42c4a66 commit 6b5ae7f

File tree

3 files changed

+205
-0
lines changed

3 files changed

+205
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
let urlResources = [
2+
{
3+
"name": "ReScript Test Framework",
4+
"description": "The most minimalistic testing library you will find for testing ReScript code",
5+
"keywords": ["testing", "minimal", "experimental"],
6+
"urlHref": "https://github.com/rescript-lang/rescript-project-template/blob/test/tests/Tests.res",
7+
"official": true
8+
},
9+
{
10+
"name": "genType",
11+
"description": "Better interop with JS & TS in ReScript",
12+
"keywords": ["rescript", "typescript"],
13+
"urlHref": "https://github.com/reason-association/genType",
14+
"official": true
15+
}
16+
]
17+
18+
export async function onRequestGET(context) {
19+
const packages = await fetchNpmPackages()
20+
return Response.json({
21+
...packages,
22+
urlResources,
23+
})
24+
}
25+
26+
async function fetchNpmPackages() {
27+
let baseUrl = "https://registry.npmjs.org/-/v1/search?text=keywords:rescript&size=250&maintenance=1.0&popularity=0.5&quality=0.9"
28+
29+
let [data1, data2, data3] = await Promise.all3([
30+
fetch(baseUrl)
31+
.then(res => res.json())
32+
.then(data => parsePkgs(data)),
33+
fetch(baseUrl + "&from=250")
34+
.then(res => res.json())
35+
.then(data => parsePkgs(data)),
36+
fetch(baseUrl + "&from=500")
37+
.then(res => res.json())
38+
.then(data => parsePkgs(data)),
39+
])
40+
41+
let unmaintained = []
42+
43+
function shouldAllow(pkg) {
44+
// These are packages that we do not want to filter out when loading searching from NPM.
45+
let packageAllowList = []
46+
47+
if (packageAllowList.includes(pkg)) {
48+
return true
49+
}
50+
51+
if (pkg.name.includes("reason")) {
52+
return false
53+
}
54+
55+
if (pkg.maintenanceScore < 0.3) {
56+
unmaintained.push(pkg)
57+
return false
58+
}
59+
60+
return true
61+
}
62+
63+
let packages = []
64+
for (let pkg of data1) if (shouldAllow(pkg)) packages.push(pkg)
65+
for (let pkg of data2) if (shouldAllow(pkg)) packages.push(pkg)
66+
for (let pkg of data3) if (shouldAllow(pkg)) packages.push(pkg)
67+
68+
return {
69+
packages,
70+
unmaintained,
71+
}
72+
}
73+
74+
function parsePkgs(data) {
75+
return data["objects"].map(item => {
76+
let pkg = item["package"]
77+
return {
78+
name: pkg["name"],
79+
version: pkg["version"],
80+
keywords: uniqueKeywords(filterKeywords(pkg["keywords"])),
81+
description: pkg["description"] ?? "",
82+
repositoryHref: pkg["links"]?.["repository"] ?? null,
83+
npmHref: pkg["links"]["npm"],
84+
searchScore: item["searchScore"],
85+
maintenanceScore: item["score"]["detail"]["maintenance"],
86+
}
87+
})
88+
}
89+
90+
function filterKeywords(keywords) {
91+
return keywords.filter(kw => {
92+
let k = kw.toLowerCase()
93+
return !(
94+
k === "reasonml" ||
95+
k === "reason" ||
96+
k === "ocaml" ||
97+
k === "bucklescript" ||
98+
k === "rescript"
99+
)
100+
})
101+
}
102+
103+
function uniqueKeywords(keywords) {
104+
return [...new Set(keywords)]
105+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/** This is the list of community content we want to generate. */
2+
/** If you have content you would like to add, please open up a PR adding the link to this list and then run `npm run generate-resources` */
3+
let urls = [
4+
// 2025
5+
"https://dev.to/dzakh/javascript-schema-library-from-the-future-5420",
6+
"https://www.youtube.com/watch?v=yKl2fSdnw7w",
7+
"https://github.com/rescript-lang/awesome-rescript", // regardless of age this seems like it should always be near the top
8+
// 2024
9+
"https://www.youtube.com/watch?v=MC-dbM-GEuw",
10+
"https://dev.to/jderochervlk/rescript-has-come-a-long-way-maybe-its-time-to-switch-from-typescript-29he",
11+
"https://www.youtube.com/watch?v=f0gDMjuaCZo",
12+
"https://www.geldata.com/blog/rescript-and-edgedb",
13+
"https://www.youtube.com/watch?v=37FY6a-zY20",
14+
// 2023
15+
"https://dev.to/cometkim/when-and-where-to-use-rescript-the-rescript-happy-path-47ni",
16+
// 2022
17+
"https://www.greyblake.com/blog/from-typescript-to-rescript/",
18+
"https://dev.to/zth/getting-rid-of-your-dead-code-in-rescript-3mba",
19+
"https://www.youtube.com/watch?v=KDL-kRgilkQ",
20+
"https://dev.to/srikanthkyatham/rescript-react-error-boundary-usage-3b05",
21+
// "https://www.daggala.com/belt_vs_js_array_in_rescript/" I think we should exclude this one since it's related to API we are deprecating
22+
// 2021
23+
"https://fullsteak.dev/posts/fullstack-rescript-architecture-overview",
24+
"https://scalac.io/blog/rescript-for-react-development/",
25+
"https://yangdanny97.github.io/blog/2021/07/09/Migrating-to-Rescript",
26+
"https://alexfedoseev.com/blog/post/responsive-images-and-cumulative-layout-shift",
27+
"https://dev.to/ryyppy/rescript-records-nextjs-undefined-and-getstaticprops-4890",
28+
]
29+
30+
export async function onRequestGET(context) {
31+
const resources = [];
32+
33+
for (let url of urls) {
34+
let resource = await fetchUrlResource(url)
35+
if (resource) {
36+
resources.push(resource)
37+
}
38+
}
39+
40+
return Response.json(resources)
41+
}
42+
43+
function makeCollector() {
44+
let state = {
45+
url: null,
46+
title: null,
47+
description: null,
48+
image: null,
49+
}
50+
return {
51+
get state() {
52+
return { ...state };
53+
},
54+
element(element) {
55+
let property = element.getAttribute('property')
56+
let content = element.getAttribute('content')
57+
let [_og, namespace, key] = property.split(':')
58+
switch (namespace) {
59+
case 'url':
60+
state.url = content
61+
return
62+
case 'title':
63+
state.title = content
64+
return
65+
case 'description':
66+
state.description = content
67+
return
68+
case 'image': {
69+
if (!key || key === 'url') {
70+
state.image = content
71+
}
72+
}
73+
}
74+
// FIXME: should flush
75+
}
76+
}
77+
}
78+
79+
async function fetchUrlResource(url) {
80+
let response = await fetch(url)
81+
if (!response.ok) {
82+
return null
83+
}
84+
85+
let collector = makeCollector()
86+
let stream = new HTMLRewriter()
87+
.on('meta[property^=og][content]', collector)
88+
.transform(response)
89+
90+
for await (let _chunk of stream) {
91+
// noop
92+
// FIXME: no need to iterate full content, just the first few hundreds killobytes enough
93+
}
94+
95+
return collector.state
96+
}

wrangler.jsonc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "rescript-lang-org",
3+
"pages_build_output_dir": "out"
4+
}

0 commit comments

Comments
 (0)