diff --git a/README.md b/README.md index 36d15630678..64b0cd1ada5 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,21 @@ specific language governing permissions and limitations under the License. --> +# Superset + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/license/apache-2-0) +[![Latest Release on Github](https://img.shields.io/github/v/release/apache/superset?sort=semver)](https://github.com/apache/superset/releases/latest) +[![Build Status](https://github.com/apache/superset/actions/workflows/superset-python-unittest.yml/badge.svg)](https://github.com/apache/superset/actions) +[![PyPI version](https://badge.fury.io/py/apache_superset.svg)](https://badge.fury.io/py/apache_superset) +[![PyPI](https://img.shields.io/pypi/pyversions/apache_superset.svg?maxAge=2592000)](https://pypi.python.org/pypi/apache_superset) +[![GitHub Stars](https://img.shields.io/github/stars/apache/superset?style=social)](https://github.com/apache/superset/stargazers) +[![Contributors](https://img.shields.io/github/contributors/apache/superset)](https://github.com/apache/superset/graphs/contributors) +[![Last Commit](https://img.shields.io/github/last-commit/apache/superset)](https://github.com/apache/superset/commits/master) +[![Open Issues](https://img.shields.io/github/issues/apache/superset)](https://github.com/apache/superset/issues) +[![Open PRs](https://img.shields.io/github/issues-pr/apache/superset)](https://github.com/apache/superset/pulls) +[![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](http://bit.ly/join-superset-slack) +[![Documentation](https://img.shields.io/badge/docs-apache.org-blue.svg)](https://superset.apache.org) + parsed.hostname.includes(domain))) { + return true; + } + // Check if it matches a badge path pattern + return BADGE_PATH_PATTERNS.some((pattern) => pattern.test(url)); + } catch { + return false; + } +} + +/** + * Download a badge and return the local path + */ +async function downloadBadge(url, staticDir) { + // Check cache first + if (badgeCache.has(url)) { + return badgeCache.get(url); + } + + const badgesDir = path.join(staticDir, 'badges'); + + // Ensure badges directory exists + if (!badgesDirCreated) { + fs.mkdirSync(badgesDir, { recursive: true }); + badgesDirCreated = true; + } + + const filename = getBadgeFilename(url); + const localPath = path.join(badgesDir, filename); + const webPath = `/badges/${filename}`; + + // Check if already downloaded in a previous build + if (fs.existsSync(localPath)) { + badgeCache.set(url, webPath); + return webPath; + } + + console.log(`[remark-localize-badges] Downloading: ${url}`); + + try { + const response = await fetch(url, { + headers: { + // Some services need a user agent + 'User-Agent': 'Mozilla/5.0 (compatible; DocusaurusBuild/1.0)', + Accept: 'image/svg+xml,image/*,*/*', + }, + // Follow redirects + redirect: 'follow', + }); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const contentType = response.headers.get('content-type') || ''; + const content = await response.text(); + + // Validate it's actually an SVG or image + if ( + !contentType.includes('svg') && + !contentType.includes('image') && + !content.trim().startsWith(' { + if (isBadgeUrl(node.url)) { + promises.push( + downloadBadge(node.url, staticDir).then((localPath) => { + node.url = localPath; + }), + ); + } + }); + + // Also handle HTML img tags in raw HTML or JSX + visit(tree, ['html', 'jsx'], (node) => { + if (!node.value) return; + + // Find img src attributes pointing to badge URLs + const imgRegex = /]+src=["']([^"']+)["'][^>]*>/gi; + let match; + + while ((match = imgRegex.exec(node.value)) !== null) { + const url = match[1]; + if (isBadgeUrl(url)) { + promises.push( + downloadBadge(url, staticDir).then((localPath) => { + node.value = node.value.replace(url, localPath); + }), + ); + } + } + }); + + // Also handle markdown link images: [![alt](img-url)](link-url) + visit(tree, 'link', (node) => { + if (node.children) { + node.children.forEach((child) => { + if (child.type === 'image' && isBadgeUrl(child.url)) { + promises.push( + downloadBadge(child.url, staticDir).then((localPath) => { + child.url = localPath; + }), + ); + } + }); + } + }); + + // Wait for all downloads to complete + await Promise.all(promises); + }; +}