Skip to content
Merged
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
69 changes: 69 additions & 0 deletions .github/workflows/map-artifact.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: map-artifact

on:
push:
branches: [main]
tags: ["v*"]
pull_request:
workflow_dispatch:

permissions:
contents: write

jobs:
build-map-artifact:
name: Build compiled JSON-IR map artifact
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Checkout interscript-ts
run: git clone --depth=1 --branch main https://github.com/interscript/interscript-ts.git ../interscript-ts
- uses: actions/setup-node@v7
with:
node-version: "22"
- name: Install + build TS converter
run: |
cd ../interscript-ts
npm ci
npm run build
- name: Build map artifact directory
run: npx -y tsx scripts/build-json-ir-artifact.mjs ../interscript-ts dist/interscript-maps-ir
- name: Validate artifact shape
run: |
test -f dist/interscript-maps-ir/manifest.json
test -f dist/interscript-maps-ir/SHA256SUMS
test "$(find dist/interscript-maps-ir/maps -name '*.json' | wc -l | tr -d ' ')" = "289"
node - <<'NODE'
import { createHash } from 'node:crypto'
import { readFileSync } from 'node:fs'
for (const line of readFileSync('dist/interscript-maps-ir/SHA256SUMS', 'utf8').trim().split('\n')) {
const [expected, path] = line.split(/ /)
const actual = createHash('sha256').update(readFileSync(`dist/interscript-maps-ir/${path}`)).digest('hex')
if (actual !== expected) throw new Error(`${path}: sha256 mismatch`)
}
NODE
- name: Pack artifact
run: |
version="$([ "${GITHUB_REF_TYPE}" = "tag" ] && echo "${GITHUB_REF_NAME#v}" || echo "${GITHUB_SHA::12}")"
mkdir -p dist/release
tar -C dist/interscript-maps-ir -czf "dist/release/interscript-maps-ir-${version}.tar.gz" .
node - <<'NODE'
import { createHash } from 'node:crypto'
import { readFileSync, writeFileSync } from 'node:fs'
const version = process.env.GITHUB_REF_TYPE === "tag"
? process.env.GITHUB_REF_NAME.replace(/^v/, '')
: process.env.GITHUB_SHA.slice(0, 12)
const name = `interscript-maps-ir-${version}.tar.gz`
const sha = createHash('sha256').update(readFileSync(`dist/release/${name}`)).digest('hex')
writeFileSync(`dist/release/${name}.sha256`, `${sha} ${name}\n`)
NODE
- name: Upload workflow artifact
uses: actions/upload-artifact@v4
with:
name: interscript-maps-ir
path: dist/release/
- name: Attach artifact to GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
env:
GH_TOKEN: ${{ github.token }}
run: gh release upload "$GITHUB_REF_NAME" dist/release/* --clobber
76 changes: 76 additions & 0 deletions scripts/build-json-ir-artifact.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env node
// Build the deployable JSON-IR map artifact from this repository's .isc corpus.
//
// Usage:
// node scripts/build-json-ir-artifact.mjs <interscript-ts-dir> <out-dir>
//
// Output directory layout:
// manifest.json
// SHA256SUMS
// maps/<system>.json

import { createHash } from "node:crypto"
import { mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs"
import { basename, join, relative, resolve } from "node:path"
import { pathToFileURL } from "node:url"

const [tsDir, outDir] = process.argv.slice(2)
if (!tsDir || !outDir) {
console.error("usage: build-json-ir-artifact.mjs <interscript-ts-dir> <out-dir>")
process.exit(2)
}

const repoRoot = resolve(import.meta.dirname, "..")
const mapsDir = join(repoRoot, "maps")
const outputRoot = resolve(outDir)
const outputMaps = join(outputRoot, "maps")

const { parseIsc } = await import(pathToFileURL(resolve(tsDir, "src/isc/parser.ts")))
const { iscToCompiledMap } = await import(pathToFileURL(resolve(tsDir, "src/isc/converter.ts")))

rmSync(outputRoot, { recursive: true, force: true })
mkdirSync(outputMaps, { recursive: true })

const files = readdirSync(mapsDir)
.filter((file) => file.endsWith(".isc"))
.sort()

const systems = []
for (const file of files) {
const code = basename(file, ".isc")
const source = readFileSync(join(mapsDir, file), "utf8")
const doc = parseIsc(source, file)
const compiled = iscToCompiledMap(doc)
writeFileSync(join(outputMaps, `${code}.json`), `${JSON.stringify(compiled)}\n`)
systems.push(code)
}

const manifest = {
schema: "interscript.maps.ir.v1",
source: "interscript/maps",
generatedAt: new Date().toISOString(),
count: systems.length,
systems,
}
writeFileSync(join(outputRoot, "manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`)

const artifactFiles = []
function walk(dir) {
for (const name of readdirSync(dir).sort()) {
const path = join(dir, name)
if (statSync(path).isDirectory()) walk(path)
else artifactFiles.push(path)
}
}
walk(outputRoot)

const checksums = artifactFiles
.filter((path) => basename(path) !== "SHA256SUMS")
.map((path) => {
const sha = createHash("sha256").update(readFileSync(path)).digest("hex")
return `${sha} ${relative(outputRoot, path)}`
})
.join("\n")
writeFileSync(join(outputRoot, "SHA256SUMS"), `${checksums}\n`)

console.log(`compiled ${systems.length} maps to ${outputRoot}`)
Loading