Skip to content

Demo using Cloudflare Pages Functions #1022

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions public/functions/api/packages_url_resources.json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
let urlResources = [
{
"name": "ReScript Test Framework",
"description": "The most minimalistic testing library you will find for testing ReScript code",
"keywords": ["testing", "minimal", "experimental"],
"urlHref": "https://github.com/rescript-lang/rescript-project-template/blob/test/tests/Tests.res",
"official": true
},
{
"name": "genType",
"description": "Better interop with JS & TS in ReScript",
"keywords": ["rescript", "typescript"],
"urlHref": "https://github.com/reason-association/genType",
"official": true
}
]

export async function onRequestGET(context) {
const packages = await fetchNpmPackages()
return Response.json({
...packages,
urlResources,
})
}

async function fetchNpmPackages() {
let baseUrl = "https://registry.npmjs.org/-/v1/search?text=keywords:rescript&size=250&maintenance=1.0&popularity=0.5&quality=0.9"

let [data1, data2, data3] = await Promise.all3([
fetch(baseUrl)
.then(res => res.json())
.then(data => parsePkgs(data)),
fetch(baseUrl + "&from=250")
.then(res => res.json())
.then(data => parsePkgs(data)),
fetch(baseUrl + "&from=500")
.then(res => res.json())
.then(data => parsePkgs(data)),
])

let unmaintained = []

function shouldAllow(pkg) {
// These are packages that we do not want to filter out when loading searching from NPM.
let packageAllowList = []

if (packageAllowList.includes(pkg)) {
return true
}

if (pkg.name.includes("reason")) {
return false
}

if (pkg.maintenanceScore < 0.3) {
unmaintained.push(pkg)
return false
}

return true
}

let packages = []
for (let pkg of data1) if (shouldAllow(pkg)) packages.push(pkg)
for (let pkg of data2) if (shouldAllow(pkg)) packages.push(pkg)
for (let pkg of data3) if (shouldAllow(pkg)) packages.push(pkg)

return {
packages,
unmaintained,
}
}

function parsePkgs(data) {
return data["objects"].map(item => {
let pkg = item["package"]
return {
name: pkg["name"],
version: pkg["version"],
keywords: uniqueKeywords(filterKeywords(pkg["keywords"])),
description: pkg["description"] ?? "",
repositoryHref: pkg["links"]?.["repository"] ?? null,
npmHref: pkg["links"]["npm"],
searchScore: item["searchScore"],
maintenanceScore: item["score"]["detail"]["maintenance"],
}
})
}

function filterKeywords(keywords) {
return keywords.filter(kw => {
let k = kw.toLowerCase()
return !(
k === "reasonml" ||
k === "reason" ||
k === "ocaml" ||
k === "bucklescript" ||
k === "rescript"
)
})
}

function uniqueKeywords(keywords) {
return [...new Set(keywords)]
}
96 changes: 96 additions & 0 deletions public/functions/api/resources.json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/** This is the list of community content we want to generate. */
/** 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` */
let urls = [
// 2025
"https://dev.to/dzakh/javascript-schema-library-from-the-future-5420",
"https://www.youtube.com/watch?v=yKl2fSdnw7w",
"https://github.com/rescript-lang/awesome-rescript", // regardless of age this seems like it should always be near the top
// 2024
"https://www.youtube.com/watch?v=MC-dbM-GEuw",
"https://dev.to/jderochervlk/rescript-has-come-a-long-way-maybe-its-time-to-switch-from-typescript-29he",
"https://www.youtube.com/watch?v=f0gDMjuaCZo",
"https://www.geldata.com/blog/rescript-and-edgedb",
"https://www.youtube.com/watch?v=37FY6a-zY20",
// 2023
"https://dev.to/cometkim/when-and-where-to-use-rescript-the-rescript-happy-path-47ni",
// 2022
"https://www.greyblake.com/blog/from-typescript-to-rescript/",
"https://dev.to/zth/getting-rid-of-your-dead-code-in-rescript-3mba",
"https://www.youtube.com/watch?v=KDL-kRgilkQ",
"https://dev.to/srikanthkyatham/rescript-react-error-boundary-usage-3b05",
// "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
// 2021
"https://fullsteak.dev/posts/fullstack-rescript-architecture-overview",
"https://scalac.io/blog/rescript-for-react-development/",
"https://yangdanny97.github.io/blog/2021/07/09/Migrating-to-Rescript",
"https://alexfedoseev.com/blog/post/responsive-images-and-cumulative-layout-shift",
"https://dev.to/ryyppy/rescript-records-nextjs-undefined-and-getstaticprops-4890",
]

export async function onRequestGET(context) {
const resources = [];

for (let url of urls) {
let resource = await fetchUrlResource(url)
if (resource) {
resources.push(resource)
}
}

return Response.json(resources)
}

function makeCollector() {
let state = {
url: null,
title: null,
description: null,
image: null,
}
return {
get state() {
return { ...state };
},
element(element) {
let property = element.getAttribute('property')
let content = element.getAttribute('content')
let [_og, namespace, key] = property.split(':')
switch (namespace) {
case 'url':
state.url = content
return
case 'title':
state.title = content
return
case 'description':
state.description = content
return
case 'image': {
if (!key || key === 'url') {
state.image = content
}
}
}
// FIXME: should flush
}
}
}

async function fetchUrlResource(url) {
let response = await fetch(url)
if (!response.ok) {
return null
}

let collector = makeCollector()
let stream = new HTMLRewriter()
.on('meta[property^=og][content]', collector)
.transform(response)

for await (let _chunk of stream) {
// noop
// FIXME: no need to iterate full content, just the first few hundreds killobytes enough
}

return collector.state
}
4 changes: 4 additions & 0 deletions wrangler.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "rescript-lang-org",
"pages_build_output_dir": "out"
}