Skip to content
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
18 changes: 18 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "krad",
"version": "0.0.0",
"private": true,
"type": "module",
"workspaces": [
"packages/*"
],
"bin": {
"krad": "./tools/krad.js"
},
"scripts": {
"test": "node --test"
},
"engines": {
"node": ">=22"
}
}
13 changes: 13 additions & 0 deletions packages/krad-clang/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { defineComponent } from "../krad-utils/index.js";

export const component = defineComponent({
name: "krad-clang",
source: {
directory: "cheerp-compiler",
focus: ["llvm/include/llvm/Cheerp", "llvm/lib/CheerpUtils", "llvm/lib/CheerpWriter", "clang/test/Cheerp"],
license: "Apache-2.0 WITH LLVM-exception",
licenseFile: "LICENSE.TXT",
repository: "https://github.com/leaningtech/cheerp-compiler",
revision: "0596bd128750d43569d17d56e443a95066d3461f",
},
});
7 changes: 7 additions & 0 deletions packages/krad-clang/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "krad-clang",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": "./index.js"
}
14 changes: 14 additions & 0 deletions packages/krad-libs/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { defineComponent } from "../krad-utils/index.js";

export const component = defineComponent({
name: "krad-libs",
dependencies: ["krad-clang", "krad-utils", "krad-musl"],
source: {
directory: "cheerp-libs",
focus: ["system", "stdlibs", "wasm"],
license: "Apache-2.0 WITH LLVM-exception",
licenseFile: "LICENSE.TXT",
repository: "https://github.com/leaningtech/cheerp-libs",
revision: "a578cfaa28bde51f1ae8b17980e6bf7727333be7",
},
});
7 changes: 7 additions & 0 deletions packages/krad-libs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "krad-libs",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": "./index.js"
}
14 changes: 14 additions & 0 deletions packages/krad-musl/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { defineComponent } from "../krad-utils/index.js";

export const component = defineComponent({
name: "krad-musl",
dependencies: ["krad-clang", "krad-utils"],
source: {
directory: "cheerp-musl",
focus: ["arch", "include", "src", "tools"],
license: "MIT",
licenseFile: "COPYRIGHT",
repository: "https://github.com/leaningtech/cheerp-musl",
revision: "dd07ec8e7c52f8dc4351bf9b329df3b1d190470a",
},
});
7 changes: 7 additions & 0 deletions packages/krad-musl/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "krad-musl",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": "./index.js"
}
76 changes: 76 additions & 0 deletions packages/krad-utils/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const namePattern = /^krad-[a-z][a-z0-9-]*$/;
const revisionPattern = /^[a-f0-9]{40}$/;
const pathPattern = /^[A-Za-z0-9._+-]+(?:\/[A-Za-z0-9._+-]+)*$/;

const path = (value, field) => {
if (typeof value !== "string" || !pathPattern.test(value) || value.split("/").some((part) => part === "." || part === "..")) {
throw new TypeError(`${field} must be a relative path`);
}
return value;
};

export const defineComponent = ({ name, dependencies = [], source }) => {
if (!namePattern.test(name)) throw new TypeError("invalid component name");
if (!Array.isArray(dependencies) || dependencies.some((dependency) => !namePattern.test(dependency))) {
throw new TypeError(`${name} has invalid dependencies`);
}
if (new Set(dependencies).size !== dependencies.length || dependencies.includes(name)) {
throw new TypeError(`${name} has duplicate or self dependencies`);
}
if (!source || typeof source !== "object") throw new TypeError(`${name} requires a source`);
const repository = new URL(source.repository);
if (repository.protocol !== "https:") throw new TypeError(`${name} repository must use HTTPS`);
if (!revisionPattern.test(source.revision)) throw new TypeError(`${name} requires a full Git revision`);
if (typeof source.license !== "string" || !source.license) throw new TypeError(`${name} requires a source license`);
if (!Array.isArray(source.focus ?? [])) throw new TypeError(`${name} focus must be an array`);
return Object.freeze({
name,
dependencies: Object.freeze([...dependencies]),
source: Object.freeze({
directory: path(source.directory, `${name} source directory`),
focus: Object.freeze((source.focus ?? []).map((entry) => path(entry, `${name} focus`))),
license: source.license,
licenseFile: path(source.licenseFile, `${name} license file`),
repository: repository.href.replace(/\/$/, ""),
revision: source.revision,
}),
});
};

export const orderComponents = (components) => {
if (!Array.isArray(components)) throw new TypeError("components must be an array");
const byName = new Map();
for (const component of components) {
if (!component?.name || byName.has(component.name)) throw new TypeError("component names must be unique");
byName.set(component.name, component);
}
const state = new Map();
const ordered = [];
const visit = (component, chain = []) => {
if (state.get(component.name) === 2) return;
if (state.get(component.name) === 1) throw new Error(`component cycle: ${[...chain, component.name].join(" -> ")}`);
state.set(component.name, 1);
for (const dependency of component.dependencies) {
const required = byName.get(dependency);
if (!required) throw new Error(`${component.name} requires missing ${dependency}`);
visit(required, [...chain, component.name]);
}
state.set(component.name, 2);
ordered.push(component);
};
for (const component of components) visit(component);
return Object.freeze(ordered);
};

export const component = defineComponent({
name: "krad-utils",
dependencies: ["krad-clang"],
source: {
directory: "cheerp-utils",
focus: ["scripts", "tools"],
license: "Apache-2.0 WITH LLVM-exception",
licenseFile: "LICENSE.TXT",
repository: "https://github.com/leaningtech/cheerp-utils",
revision: "4b95822b860d215d669374be98c1bc4425040e08",
},
});
7 changes: 7 additions & 0 deletions packages/krad-utils/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "krad-utils",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": "./index.js"
}