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
260 changes: 130 additions & 130 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,184 +3,184 @@ const path = require("path");
const matter = require("gray-matter");
const { execSync } = require("child_process");

/**
* Convert git remote URL to HTTP URL
*/
function convertGitToHttpUrl(gitUrl) {
if (gitUrl.startsWith("[email protected]:")) {
return gitUrl.replace("[email protected]:", "https://github.com/");
}
return gitUrl;
}

/**
* Get GitHub remote URLs in HTTP and SSH format
*/
function getGithubRemoteUrls(filePath) {
function getGitHubRemoteUrl() {
try {
const remoteUrl = execSync("git config --get remote.origin.url").toString().trim().replace(/https?:\/\/.*?@github\.com\//, "https://github.com/");
const httpUrl = convertGitToHttpUrl(remoteUrl).replace(
/\.git$/,
`/tree/main/modules${filePath.replace(path.resolve(__dirname, 'modules'), '').replace(/\/README\.md$/, '')}`
);
return {
ssh: remoteUrl,
https: httpUrl
};
const remoteUrl = execSync("git config --get remote.origin.url")
.toString()
.trim()
.replace(/https?:\/\/.*?@github\.com\//, "https://github.com/");
return remoteUrl.replace(/\.git$/, "");
} catch (error) {
console.error("Error getting GitHub remote URL:", error.message);
return null;
}
}

/**
* Recursively find all README.md files in “buildingblock” folders, excluding .github
*/
function findReadmes(dir) {
let results = [];
const files = fs.readdirSync(dir, { withFileTypes: true });
function getBuildingBlockFolderUrl(filePath) {
const remoteUrl = getGitHubRemoteUrl();
if (!remoteUrl) return null;

for (const file of files) {
const fullPath = path.join(dir, file.name);
const relativePath = filePath
.replace(path.resolve(__dirname, "modules"), "")
.replace(/\/README\.md$/, "");
return `${remoteUrl}/tree/main/modules${relativePath}`;
}

function findReadmes(dir){
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((file) => {
const fullPath = path.join(dir, file.name);
if (file.isDirectory()) {
if (file.name === ".github") continue;
results = results.concat(findReadmes(fullPath));
} else if (file.name === "README.md" && dir.includes("buildingblock")) {
results.push(fullPath);
return file.name === ".github" ? [] : findReadmes(fullPath);
}
}

return results;
return file.name === "README.md" && dir.includes("buildingblock")
? [fullPath]
: [];
});
}

/**
* Path to platform logo image, excluding .github
*/
function findPlatformLogos() {
const platformLogos = {};
const modulesDir = path.resolve(__dirname, 'modules');
const assetsDir = path.resolve(__dirname, 'website/public/assets/logos');
const dirs = fs.readdirSync(modulesDir, { withFileTypes: true })
.filter(dirent => dirent.isDirectory() && dirent.name !== ".github");

dirs.forEach((dir) => {
const platformDir = path.join(modulesDir, dir.name);
const files = fs.readdirSync(platformDir);

files.forEach((file) => {
if (file.endsWith(".png") || file.endsWith(".svg")) {
const sourcePath = path.join(platformDir, file);
const destinationPath = path.join(assetsDir, `${dir.name}${path.extname(file)}`);

fs.mkdirSync(assetsDir, { recursive: true });

fs.copyFileSync(sourcePath, destinationPath);

platformLogos[dir.name] = destinationPath.replace(path.resolve(__dirname, 'website/public'), "").replace(/^\/+/g, "");
}
function copyFilesToAssets(
sourceDir,
destinationDir,
fileFilter
){
const copiedFiles = {};

fs.readdirSync(sourceDir, { withFileTypes: true })
.filter((dirent) => dirent.isDirectory() && dirent.name !== ".github")
.forEach((dir) => {
const platformDir = path.join(sourceDir, dir.name);
fs.readdirSync(platformDir)
.filter(fileFilter)
.forEach((file) => {
const sourcePath = path.join(platformDir, file);
const destinationPath = path.join(
destinationDir,
`${dir.name}${path.extname(file)}`
);

fs.mkdirSync(destinationDir, { recursive: true });
fs.copyFileSync(sourcePath, destinationPath);

copiedFiles[dir.name] = destinationPath
.replace(path.resolve(__dirname, "website/public"), "")
.replace(/^\/+/g, "");
});
});
});

return platformLogos;
return copiedFiles;
}

/**
* Path to buildingblock logo image in the same directory as README.md
*/
function findBuildingBlockLogo(buildingBlockDir) {
const logoFiles = [];
const assetsDir = path.resolve(__dirname, 'website/public/assets/building-block-logos');
const files = fs.readdirSync(buildingBlockDir);
function copyPlatformLogosToAssets() {
const modulesDir = path.resolve(__dirname, "modules");
const assetsDir = path.resolve(__dirname, "website/public/assets/logos");
return copyFilesToAssets(modulesDir, assetsDir, (file) =>
file.endsWith(".png") || file.endsWith(".svg")
);
}

files.forEach((file) => {
if (file.endsWith(".png") || file.endsWith(".svg")) {
const { id, platform } = getIdAndPlatform(buildingBlockDir);
const sourcePath = path.join(buildingBlockDir, file);
const destinationPath = path.join(assetsDir, `${id}${path.extname(file)}`);
function copyBuildingBlockLogoToAssets(buildingBlockDir) {
const assetsDir = path.resolve(
__dirname,
"website/public/assets/building-block-logos"
);

fs.mkdirSync(assetsDir, { recursive: true });
fs.copyFileSync(sourcePath, destinationPath);
const logoFile = fs
.readdirSync(buildingBlockDir)
.find((file) => file.endsWith(".png"));

logoFiles.push(destinationPath.replace(path.resolve(__dirname, 'website/public'), "").replace(/^\/+/g, ""));
}
});
if (!logoFile) return null;

return logoFiles.length > 0 ? logoFiles[0] : null;
const { id } = getIdAndPlatform(buildingBlockDir);
const sourcePath = path.join(buildingBlockDir, logoFile);
const destinationPath = path.join(assetsDir, `${id}${path.extname(logoFile)}`);

fs.mkdirSync(assetsDir, { recursive: true });
fs.copyFileSync(sourcePath, destinationPath);

return destinationPath
.replace(path.resolve(__dirname, "website/public"), "")
.replace(/^\/+/g, "");
}

/**
* Parse README.md and extract relevant data
*/
function parseReadme(filePath) {
const buildingBlockDir = path.dirname(filePath);
const content = fs.readFileSync(filePath, "utf-8");
const { data, content: body } = matter(content);
const { id, platform } = getIdAndPlatform(buildingBlockDir);
const howToMatch = body.match(/## How to Use([\s\S]*?)(##|$)/);
const resourcesMatch = body.match(/## Resources([\s\S]*)/);
const inputsMatch = body.match(/## Inputs([\s\S]*?)## Outputs/);
const outputsMatch = body.match(/## Outputs([\s\S]*)/);

const extractSection = (regex) =>
body.match(regex)?.[1]?.trim() || null;

const parseTable = (match) =>
match
? match[1]
.split("\n")
.filter((line) => line.startsWith("| <a name"))
.map((line) => line.split("|").map((s) => s.trim()))
.map(([name, description, type, _default, required]) => ({
name: name.replace(/<a name=".*?_(.*?)".*?>/, "$1"),
description,
type,
required: required === "yes",
}))
.split("\n")
.filter((line) => line.startsWith("| <a name"))
.map((line) => line.split("|").map((s) => s.trim()))
.map(([name, description, type, _default, required]) => ({
name: name.replace(/<a name=".*?_(.*?)".*?>/, "$1"),
description,
type,
required: required === "yes",
}))
: [];

const githubUrls = getGithubRemoteUrls(filePath);
console.log(`🔗 GitHub remote URLs: ${JSON.stringify(githubUrls)}`);
console.log(`🔗 File path: ${filePath}`);
const buildingBlockUrl = getBuildingBlockFolderUrl(filePath);
const buildingBlockLogoPath = copyBuildingBlockLogoToAssets(buildingBlockDir);

const buildingBlockLogoPath = findBuildingBlockLogo(buildingBlockDir);
const backplaneDir = path.join(buildingBlockDir, "../backplane");
const backplaneUrl =
fs.existsSync(backplaneDir) && fs.statSync(backplaneDir).isDirectory()
? getBuildingBlockFolderUrl(backplaneDir)
: null;

return {
id: id,
id,
platformType: platform,
logo: buildingBlockLogoPath,
githubUrls,
buildingBlockUrl,
backplaneUrl,
...data,
howToUse: howToMatch ? howToMatch[1].trim() : null,
resources: parseTable(resourcesMatch),
inputs: parseTable(inputsMatch),
outputs: parseTable(outputsMatch),
howToUse: extractSection(/## How to Use([\s\S]*?)(##|$)/),
resources: parseTable(body.match(/## Resources([\s\S]*)/)),
inputs: parseTable(body.match(/## Inputs([\s\S]*?)## Outputs/)),
outputs: parseTable(body.match(/## Outputs([\s\S]*)/))
};
}

/**
* This returns the id and platform type from the file path.
*
* @param filePath The buildingblock directory
*/
function getIdAndPlatform(filePath) {
const relativePath = filePath.replace(process.cwd(), "").replace(/\\/g, "/");
const relativePath = filePath
.replace(process.cwd(), "")
.replace(/\\/g, "/");
const pathParts = relativePath.split(path.sep).filter(Boolean);
// pathParts = [modules, <platform>, <module-name>, buildingblock]
const id = pathParts.slice(1, pathParts.length - 1).join("-");
const platform = pathParts.length > 1 ? pathParts[1] : "unknown";
const platform = pathParts[1] || "unknown";

return { id, platform };
}

const repoRoot = path.resolve(__dirname, 'modules');
const platformLogos = findPlatformLogos();
const readmeFiles = findReadmes(repoRoot);
const jsonData = readmeFiles.map((file) => parseReadme(file));

const templatesData = {
templates: jsonData,
};

fs.writeFileSync("website/public/assets/templates.json", JSON.stringify(templatesData, null, 2));
console.log(`✅ Successfully processed ${readmeFiles.length} README.md files. Output saved to templates.json`);
// Main execution
function main() {
const repoRoot = path.resolve(__dirname, "modules");

const platformLogos = copyPlatformLogosToAssets();
fs.writeFileSync(
"website/public/assets/platform-logos.json",
JSON.stringify(platformLogos, null, 2)
);
console.log(
`✅ Successfully processed ${Object.entries(platformLogos).length} platform logos. Output saved to platform-logos.json`
);

const readmeFiles = findReadmes(repoRoot);
const jsonData = readmeFiles.map(parseReadme);
fs.writeFileSync(
"website/public/assets/templates.json",
JSON.stringify({ templates: jsonData }, null, 2)
);
console.log(
`✅ Successfully processed ${readmeFiles.length} README.md files. Output saved to templates.json`
);
}

fs.writeFileSync("website/public/assets/platform-logos.json", JSON.stringify(platformLogos, null, 2));
console.log(`✅ Successfully processed ${Object.entries(platformLogos).length} platform logos. Output saved to platform-logos.json`);
main();
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading