mirror of
https://github.com/github/awesome-copilot.git
synced 2026-06-17 13:11:27 +00:00
chore: publish from staged
This commit is contained in:
+452
-69
@@ -674,11 +674,33 @@ function generatePluginsData(gitDates) {
|
||||
/**
|
||||
* Generate canvas extensions metadata
|
||||
*/
|
||||
function getExtensionAssetInfo(extensionDir, relPath, ref) {
|
||||
function getImageMimeType(filePath) {
|
||||
const extension = path.extname(filePath).toLowerCase();
|
||||
const mimeByExtension = {
|
||||
".png": "image/png",
|
||||
".jpg": "image/jpeg",
|
||||
".jpeg": "image/jpeg",
|
||||
".webp": "image/webp",
|
||||
".gif": "image/gif",
|
||||
};
|
||||
return mimeByExtension[extension] || "application/octet-stream";
|
||||
}
|
||||
|
||||
function resolveImageUrl(value, ref) {
|
||||
const normalized = normalizeText(value);
|
||||
if (!normalized) return null;
|
||||
if (/^https?:\/\//i.test(normalized)) {
|
||||
return normalized;
|
||||
}
|
||||
const repoPath = normalized.replace(/\\/g, "/").replace(/^\/+/, "");
|
||||
return buildRepoImageUrl(repoPath, ref);
|
||||
}
|
||||
|
||||
function getImageAssetFiles(extensionDir) {
|
||||
const assetDir = path.join(extensionDir, "assets");
|
||||
|
||||
if (!fs.existsSync(assetDir)) {
|
||||
return null;
|
||||
return [];
|
||||
}
|
||||
|
||||
const imageExtensions = new Set([
|
||||
@@ -689,7 +711,35 @@ function getExtensionAssetInfo(extensionDir, relPath, ref) {
|
||||
".gif",
|
||||
]);
|
||||
|
||||
const preferredNames = [
|
||||
return fs
|
||||
.readdirSync(assetDir)
|
||||
.filter((file) => imageExtensions.has(path.extname(file).toLowerCase()))
|
||||
.sort((a, b) => a.localeCompare(b));
|
||||
}
|
||||
|
||||
function pickAssetFile(files, preferredNames) {
|
||||
const preferredLookup = new Set(preferredNames.map((name) => name.toLowerCase()));
|
||||
for (const file of files) {
|
||||
if (preferredLookup.has(file.toLowerCase())) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return files[0] || null;
|
||||
}
|
||||
|
||||
function getExtensionAssetInfo(extensionDir, relPath, ref) {
|
||||
const files = getImageAssetFiles(extensionDir);
|
||||
|
||||
if (files.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const iconAsset = pickAssetFile(files, [
|
||||
"icon.png",
|
||||
"icon.jpg",
|
||||
"icon.jpeg",
|
||||
"icon.webp",
|
||||
"icon.gif",
|
||||
"preview.png",
|
||||
"preview.jpg",
|
||||
"preview.jpeg",
|
||||
@@ -705,34 +755,52 @@ function getExtensionAssetInfo(extensionDir, relPath, ref) {
|
||||
"image.jpeg",
|
||||
"image.webp",
|
||||
"image.gif",
|
||||
];
|
||||
]);
|
||||
const galleryAsset = pickAssetFile(files, [
|
||||
"gallery.png",
|
||||
"gallery.jpg",
|
||||
"gallery.jpeg",
|
||||
"gallery.webp",
|
||||
"gallery.gif",
|
||||
"preview.png",
|
||||
"preview.jpg",
|
||||
"preview.jpeg",
|
||||
"preview.webp",
|
||||
"preview.gif",
|
||||
"screenshot.png",
|
||||
"screenshot.jpg",
|
||||
"screenshot.jpeg",
|
||||
"screenshot.webp",
|
||||
"screenshot.gif",
|
||||
"image.png",
|
||||
"image.jpg",
|
||||
"image.jpeg",
|
||||
"image.webp",
|
||||
"image.gif",
|
||||
]);
|
||||
|
||||
for (const candidate of preferredNames) {
|
||||
const candidatePath = path.join(assetDir, candidate);
|
||||
if (fs.existsSync(candidatePath)) {
|
||||
const assetPath = `${relPath}/assets/${candidate}`;
|
||||
return {
|
||||
assetPath,
|
||||
imageUrl: buildRepoImageUrl(assetPath, ref),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const files = fs
|
||||
.readdirSync(assetDir)
|
||||
.filter((file) => imageExtensions.has(path.extname(file).toLowerCase()))
|
||||
.sort((a, b) => a.localeCompare(b));
|
||||
|
||||
if (files.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const assetFile = files[0];
|
||||
const assetPath = `${relPath}/assets/${assetFile}`;
|
||||
const iconFile = iconAsset || galleryAsset;
|
||||
const galleryFile = galleryAsset || iconAsset;
|
||||
const iconPath = iconFile ? `${relPath}/assets/${iconFile}` : null;
|
||||
const galleryPath = galleryFile ? `${relPath}/assets/${galleryFile}` : null;
|
||||
|
||||
return {
|
||||
assetPath,
|
||||
imageUrl: buildRepoImageUrl(assetPath, ref),
|
||||
screenshots: {
|
||||
icon: iconPath
|
||||
? {
|
||||
path: iconPath,
|
||||
type: getImageMimeType(iconPath),
|
||||
}
|
||||
: null,
|
||||
gallery: galleryPath
|
||||
? {
|
||||
path: galleryPath,
|
||||
type: getImageMimeType(galleryPath),
|
||||
}
|
||||
: null,
|
||||
},
|
||||
assetPath: iconPath,
|
||||
imageUrl: iconPath ? buildRepoImageUrl(iconPath, ref) : null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -744,11 +812,174 @@ function buildRepoImageUrl(assetPath, ref) {
|
||||
return `https://raw.githubusercontent.com/github/awesome-copilot/${ref}/${encodedAssetPath}`;
|
||||
}
|
||||
|
||||
function generateExtensionsData(gitDates, commitSha) {
|
||||
const extensions = [];
|
||||
function extractCanvasMetadataFromSource(source) {
|
||||
const constants = new Map();
|
||||
const constantPattern =
|
||||
/\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:"((?:[^"\\]|\\.)*)"|'((?:[^'\\]|\\.)*)'|`([^`$]*)`)\s*;/g;
|
||||
let constantMatch = constantPattern.exec(source);
|
||||
while (constantMatch) {
|
||||
const key = constantMatch[1];
|
||||
const value = constantMatch[2] ?? constantMatch[3] ?? constantMatch[4] ?? "";
|
||||
constants.set(key, value.replace(/\\n/g, "\n").trim());
|
||||
constantMatch = constantPattern.exec(source);
|
||||
}
|
||||
|
||||
function resolveExpression(expr) {
|
||||
const trimmed = normalizeText(expr);
|
||||
if (!trimmed) return null;
|
||||
if (
|
||||
(trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
||||
(trimmed.startsWith("'") && trimmed.endsWith("'"))
|
||||
) {
|
||||
return trimmed
|
||||
.slice(1, -1)
|
||||
.replace(/\\n/g, "\n")
|
||||
.replace(/\\"/g, '"')
|
||||
.replace(/\\'/g, "'");
|
||||
}
|
||||
if (trimmed.startsWith("`") && trimmed.endsWith("`") && !trimmed.includes("${")) {
|
||||
return trimmed.slice(1, -1);
|
||||
}
|
||||
return constants.get(trimmed) || null;
|
||||
}
|
||||
|
||||
function findMatchingBrace(startIndex) {
|
||||
let depth = 0;
|
||||
let inSingle = false;
|
||||
let inDouble = false;
|
||||
let inTemplate = false;
|
||||
let escaped = false;
|
||||
for (let i = startIndex; i < source.length; i++) {
|
||||
const char = source[i];
|
||||
if (escaped) {
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
if (char === "\\") {
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
if (!inDouble && !inTemplate && char === "'" && !inSingle) {
|
||||
inSingle = true;
|
||||
continue;
|
||||
}
|
||||
if (inSingle && char === "'") {
|
||||
inSingle = false;
|
||||
continue;
|
||||
}
|
||||
if (!inSingle && !inTemplate && char === '"' && !inDouble) {
|
||||
inDouble = true;
|
||||
continue;
|
||||
}
|
||||
if (inDouble && char === '"') {
|
||||
inDouble = false;
|
||||
continue;
|
||||
}
|
||||
if (!inSingle && !inDouble && char === "`" && !inTemplate) {
|
||||
inTemplate = true;
|
||||
continue;
|
||||
}
|
||||
if (inTemplate && char === "`") {
|
||||
inTemplate = false;
|
||||
continue;
|
||||
}
|
||||
if (inSingle || inDouble || inTemplate) {
|
||||
continue;
|
||||
}
|
||||
if (char === "{") depth++;
|
||||
if (char === "}") {
|
||||
depth--;
|
||||
if (depth === 0) return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function readProp(head, key) {
|
||||
const pattern = new RegExp(`\\b${key}\\s*:\\s*([^,\\n]+)`);
|
||||
const match = pattern.exec(head);
|
||||
return resolveExpression(match?.[1]);
|
||||
}
|
||||
|
||||
const canvases = [];
|
||||
let cursor = 0;
|
||||
while (cursor < source.length) {
|
||||
const createCanvasIndex = source.indexOf("createCanvas(", cursor);
|
||||
if (createCanvasIndex === -1) {
|
||||
break;
|
||||
}
|
||||
const objectStart = source.indexOf("{", createCanvasIndex);
|
||||
if (objectStart === -1) {
|
||||
break;
|
||||
}
|
||||
const objectEnd = findMatchingBrace(objectStart);
|
||||
if (objectEnd === -1) {
|
||||
break;
|
||||
}
|
||||
const objectContent = source.slice(objectStart + 1, objectEnd);
|
||||
const header = objectContent.slice(0, 1400);
|
||||
const id = readProp(header, "id");
|
||||
const displayName = readProp(header, "displayName");
|
||||
const description = readProp(header, "description");
|
||||
if (id || displayName || description) {
|
||||
canvases.push({
|
||||
id: id || null,
|
||||
displayName: displayName || null,
|
||||
description: description || null,
|
||||
});
|
||||
}
|
||||
cursor = objectEnd + 1;
|
||||
}
|
||||
|
||||
return canvases;
|
||||
}
|
||||
|
||||
function getExtensionCanvasFiles(extensionDir) {
|
||||
const queue = [extensionDir];
|
||||
const files = [];
|
||||
while (queue.length > 0) {
|
||||
const currentDir = queue.shift();
|
||||
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
const absolutePath = path.join(currentDir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
queue.push(absolutePath);
|
||||
} else if (entry.isFile() && entry.name.endsWith(".mjs")) {
|
||||
files.push(absolutePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
return files.sort((a, b) => a.localeCompare(b));
|
||||
}
|
||||
|
||||
function normalizeExternalScreenshotRole(value, ref) {
|
||||
if (!value) return null;
|
||||
if (typeof value === "string") {
|
||||
const type = getImageMimeType(value);
|
||||
return {
|
||||
path: value.replace(/\\/g, "/"),
|
||||
type,
|
||||
imageUrl: resolveImageUrl(value, ref),
|
||||
};
|
||||
}
|
||||
const pathValue = normalizeText(value.path);
|
||||
const urlValue = normalizeText(value.url);
|
||||
if (!pathValue && !urlValue) return null;
|
||||
const imagePath = pathValue ? pathValue.replace(/\\/g, "/") : null;
|
||||
const type = normalizeText(value.type) || getImageMimeType(imagePath || urlValue);
|
||||
const imageUrl = resolveImageUrl(urlValue || imagePath, ref);
|
||||
return {
|
||||
path: imagePath,
|
||||
type,
|
||||
imageUrl,
|
||||
};
|
||||
}
|
||||
|
||||
function generateCanvasManifest(gitDates, commitSha) {
|
||||
const items = [];
|
||||
|
||||
if (!fs.existsSync(EXTENSIONS_DIR)) {
|
||||
return { items: [] };
|
||||
return { items: [], filters: { keywords: [] } };
|
||||
}
|
||||
|
||||
const extensionDirs = fs
|
||||
@@ -761,32 +992,61 @@ function generateExtensionsData(gitDates, commitSha) {
|
||||
"extension.mjs"
|
||||
);
|
||||
return fs.existsSync(extensionEntryPoint);
|
||||
});
|
||||
})
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
for (const dir of extensionDirs) {
|
||||
const relPath = `extensions/${dir.name}`;
|
||||
const assetInfo = getExtensionAssetInfo(
|
||||
path.join(EXTENSIONS_DIR, dir.name),
|
||||
relPath,
|
||||
commitSha
|
||||
);
|
||||
const extensionDir = path.join(EXTENSIONS_DIR, dir.name);
|
||||
const packageJsonPath = path.join(extensionDir, "package.json");
|
||||
const packageJson = fs.existsSync(packageJsonPath)
|
||||
? JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"))
|
||||
: {};
|
||||
const keywords = Array.isArray(packageJson.keywords)
|
||||
? [...new Set(packageJson.keywords.filter((keyword) => typeof keyword === "string").map((keyword) => keyword.trim()).filter(Boolean))].sort((a, b) => a.localeCompare(b))
|
||||
: [];
|
||||
const extensionDescription = normalizeText(packageJson.description, "Canvas extension");
|
||||
const extensionName = normalizeText(packageJson.name, dir.name);
|
||||
const extensionVersion = normalizeText(packageJson.version, "1.0.0");
|
||||
const screenshots = getExtensionAssetInfo(extensionDir, relPath, commitSha);
|
||||
const canvasFiles = getExtensionCanvasFiles(extensionDir);
|
||||
const canvases = [];
|
||||
for (const canvasFile of canvasFiles) {
|
||||
const source = fs.readFileSync(canvasFile, "utf-8");
|
||||
canvases.push(...extractCanvasMetadataFromSource(source));
|
||||
}
|
||||
const canvasEntries = canvases.length > 0
|
||||
? canvases
|
||||
: [{ id: dir.name, displayName: formatDisplayName(dir.name), description: extensionDescription }];
|
||||
const installUrl = `https://github.com/github/awesome-copilot/tree/${commitSha}/${relPath.replace(
|
||||
/\\/g,
|
||||
"/"
|
||||
)}`;
|
||||
|
||||
extensions.push({
|
||||
id: dir.name,
|
||||
name: formatDisplayName(dir.name),
|
||||
description: "Canvas extension",
|
||||
path: relPath,
|
||||
ref: commitSha,
|
||||
lastUpdated: getDirectoryLastUpdated(gitDates, relPath),
|
||||
imageUrl: assetInfo?.imageUrl || null,
|
||||
assetPath: assetInfo?.assetPath || null,
|
||||
installUrl: `https://github.com/github/awesome-copilot/tree/${commitSha}/${relPath.replace(
|
||||
/\\/g,
|
||||
"/"
|
||||
)}`,
|
||||
sourceUrl: null,
|
||||
external: false,
|
||||
});
|
||||
for (const canvas of canvasEntries) {
|
||||
const canvasId = normalizeText(canvas.id, dir.name);
|
||||
const canvasName = normalizeText(canvas.displayName, formatDisplayName(canvasId));
|
||||
const canvasDescription = normalizeText(extensionDescription, canvas.description);
|
||||
items.push({
|
||||
id: canvasId,
|
||||
canvasId,
|
||||
extensionId: dir.name,
|
||||
extensionName,
|
||||
name: canvasName,
|
||||
version: extensionVersion,
|
||||
description: canvasDescription,
|
||||
path: relPath,
|
||||
ref: commitSha,
|
||||
lastUpdated: getDirectoryLastUpdated(gitDates, relPath),
|
||||
screenshots: screenshots?.screenshots || { icon: null, gallery: null },
|
||||
imageUrl: screenshots?.imageUrl || null,
|
||||
assetPath: screenshots?.assetPath || null,
|
||||
installUrl,
|
||||
sourceUrl: null,
|
||||
external: false,
|
||||
keywords,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const externalJsonPath = path.join(EXTENSIONS_DIR, "external.json");
|
||||
@@ -805,27 +1065,58 @@ function generateExtensionsData(gitDates, commitSha) {
|
||||
}
|
||||
|
||||
const id = normalizeText(ext?.id || name.toLowerCase().replace(/\s+/g, "-"));
|
||||
let imageUrl = normalizeText(ext?.imageUrl);
|
||||
let assetPath = null;
|
||||
const imagePath = normalizeText(ext?.imagePath);
|
||||
if (!imageUrl && imagePath) {
|
||||
const repoAssetPath = imagePath.replace(/\\/g, "/");
|
||||
imageUrl = buildRepoImageUrl(repoAssetPath, commitSha);
|
||||
assetPath = repoAssetPath;
|
||||
}
|
||||
const keywords = Array.isArray(ext?.keywords)
|
||||
? [...new Set(ext.keywords.filter((keyword) => typeof keyword === "string").map((keyword) => keyword.trim()).filter(Boolean))].sort((a, b) => a.localeCompare(b))
|
||||
: Array.isArray(ext?.tags)
|
||||
? [...new Set(ext.tags.filter((keyword) => typeof keyword === "string").map((keyword) => keyword.trim()).filter(Boolean))].sort((a, b) => a.localeCompare(b))
|
||||
: [];
|
||||
const iconScreenshot =
|
||||
normalizeExternalScreenshotRole(ext?.screenshots?.icon, commitSha) ||
|
||||
normalizeExternalScreenshotRole(ext?.iconPath, commitSha) ||
|
||||
normalizeExternalScreenshotRole(ext?.imagePath, commitSha) ||
|
||||
normalizeExternalScreenshotRole(ext?.iconUrl, commitSha) ||
|
||||
normalizeExternalScreenshotRole(ext?.imageUrl, commitSha);
|
||||
const galleryScreenshot =
|
||||
normalizeExternalScreenshotRole(ext?.screenshots?.gallery, commitSha) ||
|
||||
normalizeExternalScreenshotRole(ext?.galleryPath, commitSha) ||
|
||||
normalizeExternalScreenshotRole(ext?.galleryUrl, commitSha) ||
|
||||
iconScreenshot;
|
||||
const screenshots = {
|
||||
icon: iconScreenshot
|
||||
? {
|
||||
path: iconScreenshot.path,
|
||||
type: iconScreenshot.type,
|
||||
}
|
||||
: null,
|
||||
gallery: galleryScreenshot
|
||||
? {
|
||||
path: galleryScreenshot.path,
|
||||
type: galleryScreenshot.type,
|
||||
}
|
||||
: null,
|
||||
};
|
||||
const imageUrl = iconScreenshot?.imageUrl || null;
|
||||
const assetPath = iconScreenshot?.path || null;
|
||||
const canvasId = normalizeText(ext?.canvasId, id);
|
||||
|
||||
extensions.push({
|
||||
items.push({
|
||||
id,
|
||||
canvasId,
|
||||
extensionId: id,
|
||||
extensionName: name,
|
||||
name,
|
||||
version: normalizeText(ext?.version, "1.0.0"),
|
||||
description: normalizeText(ext?.description, "External canvas extension"),
|
||||
path: null,
|
||||
ref: null,
|
||||
lastUpdated: null,
|
||||
imageUrl: imageUrl || null,
|
||||
screenshots,
|
||||
imageUrl,
|
||||
assetPath,
|
||||
installUrl,
|
||||
sourceUrl: sourceUrl || null,
|
||||
external: true,
|
||||
keywords,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -834,11 +1125,98 @@ function generateExtensionsData(gitDates, commitSha) {
|
||||
}
|
||||
}
|
||||
|
||||
const sortedExtensions = extensions.sort((a, b) =>
|
||||
a.name.localeCompare(b.name)
|
||||
);
|
||||
const sortedItems = items.sort((a, b) => a.name.localeCompare(b.name));
|
||||
const keywordFilters = [...new Set(sortedItems.flatMap((item) => item.keywords || []))]
|
||||
.filter(Boolean)
|
||||
.sort((a, b) => a.localeCompare(b));
|
||||
|
||||
return { items: sortedExtensions };
|
||||
return {
|
||||
items: sortedItems,
|
||||
filters: {
|
||||
keywords: keywordFilters,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function generateExtensionsData(canvasManifestData) {
|
||||
if (!canvasManifestData || !Array.isArray(canvasManifestData.items)) {
|
||||
return { items: [], filters: { keywords: [] } };
|
||||
}
|
||||
|
||||
const items = canvasManifestData.items.map((item) => ({
|
||||
...item,
|
||||
keywords: Array.isArray(item.keywords) ? item.keywords : [],
|
||||
screenshots: item.screenshots || { icon: null, gallery: null },
|
||||
}));
|
||||
const filters = {
|
||||
keywords: [...new Set(items.flatMap((item) => item.keywords))]
|
||||
.filter(Boolean)
|
||||
.sort((a, b) => a.localeCompare(b)),
|
||||
};
|
||||
|
||||
return { items, filters };
|
||||
}
|
||||
|
||||
function writePerExtensionCanvasManifests(canvasManifestData) {
|
||||
const manifests = new Map();
|
||||
|
||||
function toExtensionRelativePath(assetPath, extensionId) {
|
||||
const normalizedPath = normalizeText(assetPath).replace(/\\/g, "/");
|
||||
if (!normalizedPath) return null;
|
||||
const prefix = `extensions/${extensionId}/`;
|
||||
return normalizedPath.startsWith(prefix)
|
||||
? normalizedPath.slice(prefix.length)
|
||||
: normalizedPath;
|
||||
}
|
||||
|
||||
function toRelativeScreenshots(screenshots, extensionId) {
|
||||
if (!screenshots) return { icon: null, gallery: null };
|
||||
const toRelativeEntry = (entry) =>
|
||||
entry
|
||||
? {
|
||||
...entry,
|
||||
path: toExtensionRelativePath(entry.path, extensionId),
|
||||
}
|
||||
: null;
|
||||
return {
|
||||
icon: toRelativeEntry(screenshots.icon),
|
||||
gallery: toRelativeEntry(screenshots.gallery),
|
||||
};
|
||||
}
|
||||
|
||||
for (const item of canvasManifestData.items || []) {
|
||||
if (!item || item.external || !item.extensionId || !item.path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We assume one canvas per extension folder.
|
||||
if (manifests.has(item.extensionId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
manifests.set(item.extensionId, {
|
||||
id: item.canvasId || item.id,
|
||||
name: item.name,
|
||||
description: item.description || "Canvas extension",
|
||||
version: item.version || "1.0.0",
|
||||
keywords: Array.isArray(item.keywords)
|
||||
? [...new Set(item.keywords)].sort((a, b) => a.localeCompare(b))
|
||||
: [],
|
||||
screenshots: toRelativeScreenshots(
|
||||
item.screenshots || { icon: null, gallery: null },
|
||||
item.extensionId
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
for (const [extensionId, manifest] of manifests.entries()) {
|
||||
const canvasManifestPath = path.join(
|
||||
EXTENSIONS_DIR,
|
||||
extensionId,
|
||||
"canvas.json"
|
||||
);
|
||||
fs.writeFileSync(canvasManifestPath, JSON.stringify(manifest, null, 2));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1181,9 +1559,12 @@ async function main() {
|
||||
`✓ Generated ${plugins.length} plugins (${pluginsData.filters.tags.length} tags)`
|
||||
);
|
||||
|
||||
const extensionsData = generateExtensionsData(gitDates, commitSha);
|
||||
const canvasManifestData = generateCanvasManifest(gitDates, commitSha);
|
||||
const extensionsData = generateExtensionsData(canvasManifestData);
|
||||
const extensions = extensionsData.items;
|
||||
console.log(`✓ Generated ${extensions.length} extensions`);
|
||||
console.log(
|
||||
`✓ Generated ${extensions.length} extensions (${extensionsData.filters.keywords.length} keywords)`
|
||||
);
|
||||
|
||||
const toolsData = generateToolsData();
|
||||
const tools = toolsData.items;
|
||||
@@ -1248,6 +1629,8 @@ async function main() {
|
||||
JSON.stringify(extensionsData, null, 2)
|
||||
);
|
||||
|
||||
writePerExtensionCanvasManifests(canvasManifestData);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(WEBSITE_DATA_DIR, "tools.json"),
|
||||
JSON.stringify(toolsData, null, 2)
|
||||
|
||||
Reference in New Issue
Block a user