@reliverse/rse
Version:
@reliverse/rse is your all-in-one companion for bootstrapping and improving any kind of projects (especially web apps built with frameworks like Next.js) — whether you're kicking off something new or upgrading an existing app. It is also a little AI-power
119 lines (118 loc) • 3.63 kB
JavaScript
import path from "@reliverse/pathkit";
import { ensuredir } from "@reliverse/relifso";
import fs from "@reliverse/relifso";
import { Type } from "@sinclair/typebox";
import { cliHomeRepos, cliVersion } from "../constants.js";
export const repoInfoSchema = Type.Object({
id: Type.String(),
author: Type.String(),
name: Type.String(),
description: Type.String(),
category: Type.String(),
lastUpdated: Type.String(),
// ISO date string
localPath: Type.String(),
// GitHub repository information from ungh
github: Type.Object({
stars: Type.Number(),
forks: Type.Number(),
watchers: Type.Number(),
createdAt: Type.String(),
updatedAt: Type.String(),
pushedAt: Type.String(),
defaultBranch: Type.String()
})
});
export const reposSchema = Type.Object(
{
$schema: Type.String(),
version: Type.String(),
// CLI version when repos.json was last updated
repos: Type.Array(repoInfoSchema)
},
{ additionalProperties: false }
);
export const DEFAULT_REPOS_CONFIG = {
$schema: "./schema.json",
version: cliVersion,
repos: []
};
function convertTypeBoxToJsonSchema(schema) {
if (!schema || typeof schema !== "object") return schema;
if (schema.type === "string" && schema.enum) {
return {
type: "string",
enum: schema.enum
};
}
if (schema.anyOf || schema.allOf || schema.oneOf) {
const variants = schema.anyOf || schema.allOf || schema.oneOf;
const allLiterals = variants.every((v) => v.const !== void 0);
if (allLiterals) {
return {
type: "string",
enum: variants.map((v) => v.const)
};
}
}
if (schema.type === "object") {
const result = {
type: "object",
properties: {}
};
if (schema.required) {
result.required = schema.required;
}
if (schema.properties) {
for (const [key, value] of Object.entries(schema.properties)) {
result.properties[key] = convertTypeBoxToJsonSchema(value);
}
}
return result;
}
if (schema.type === "array") {
return {
type: "array",
items: convertTypeBoxToJsonSchema(schema.items)
};
}
if (schema.type) {
const result = { type: schema.type };
if (schema.minimum !== void 0) result.minimum = schema.minimum;
if (schema.maximum !== void 0) result.maximum = schema.maximum;
if (schema.minLength !== void 0) result.minLength = schema.minLength;
if (schema.maxLength !== void 0) result.maxLength = schema.maxLength;
if (schema.pattern !== void 0) result.pattern = schema.pattern;
if (schema.format !== void 0) result.format = schema.format;
if (schema.default !== void 0) result.default = schema.default;
return result;
}
return schema;
}
export async function generateReposJsonSchema() {
const converted = convertTypeBoxToJsonSchema(reposSchema);
const schema = {
$schema: "http://json-schema.org/draft-07/schema#",
title: "rse Repos Schema",
description: "Schema for repos.json configuration file",
type: "object",
properties: converted.properties,
required: converted.required
};
await ensuredir(cliHomeRepos);
const schemaPath = path.join(cliHomeRepos, "schema.json");
await fs.writeFile(schemaPath, JSON.stringify(schema, null, 2));
}
export async function shouldRegenerateSchema() {
const configPath = path.join(cliHomeRepos, "repos.json");
if (!await fs.pathExists(configPath)) {
return true;
}
try {
const content = await fs.readFile(configPath, "utf-8");
const config = JSON.parse(content);
return config.version !== cliVersion;
} catch {
return true;
}
}