Files
drawlogo/scripts/tmp-query-iconify-candidates.js
T

73 lines
3.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 临时调研:Iconify 官方集合 vs 本地已收录,找出未收录且许可证合规的候选源
* 输出:未收录集合清单(id / 图标数 / license / 是否合规 / 收录价值初判)
*/
'use strict';
const https = require('https');
const fs = require('fs');
const path = require('path');
const ROOT = process.cwd();
const SOURCES = require(path.join(ROOT, 'js', 'data', 'icon-sources.js'));
// 本地已收录的 iconify prefix(npm: '@iconify-json/xxx' 的 xxx)
const localPrefixes = new Set();
for (const s of SOURCES) {
const m = String(s.npm || '').match(/@iconify-json\/([\w-]+)/);
if (m) localPrefixes.add(m[1]);
// 有些源 id 即 prefix
localPrefixes.add(s.id);
}
function fetch(url, redirects) {
return new Promise((resolve, reject) => {
const req = https.get(url, { timeout: 60000 }, (res) => {
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
const next = res.headers.location;
if (next.startsWith('/')) return resolve(fetch('https://api.iconify.design' + next, (redirects || 0) + 1));
return resolve(fetch(next, (redirects || 0) + 1));
}
if (res.statusCode !== 200) { reject(new Error('HTTP ' + res.statusCode)); res.resume(); return; }
const chunks = [];
res.on('data', (c) => chunks.push(c));
res.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
});
req.on('error', reject);
req.setTimeout(60000, () => { req.destroy(new Error('timeout')); });
});
}
(async () => {
console.log('拉取 Iconify 官方集合列表…');
const raw = await fetch('https://api.iconify.design/collections');
const json = JSON.parse(raw);
const all = Object.entries(json.collections || json);
console.log('顶层键:', Object.keys(json).slice(0, 10).join(', '));
// 许可证过滤:排除 BY-SA / BY-NC / BY-ND / GPL / -NC-(兼容空格分隔形式)
const badRe = /by[\s-]?sa|by[\s-]?nc|by[\s-]?nd|gpl|nc-|cc[\s-]?by[\s-]?nc/i;
const missing = [];
for (const [prefix, info] of all) {
if (localPrefixes.has(prefix)) continue;
const license = info.license ? info.license.title : 'unknown';
const bad = badRe.test(license);
missing.push({ prefix, total: info.total, license, bad, author: info.author && info.author.name });
}
// 未收录 + 合规(或 license unknown 单独列出)
const good = missing.filter(m => !m.bad);
const bad = missing.filter(m => m.bad);
good.sort((a, b) => b.total - a.total);
bad.sort((a, b) => b.total - a.total);
console.log(`\n=== 官方集合总数: ${all.length} | 本地已收录 iconify prefix: ${localPrefixes.size} ===`);
console.log(`\n=== 未收录 + 许可证合规(${good.length} 个)===\n`);
for (const m of good) {
console.log(` ${m.prefix.padEnd(28)} ${String(m.total).padStart(6)} ${m.license.padEnd(28)} ${m.author || ''}`);
}
console.log(`\n=== 未收录 + 许可证不合规(${bad.length} 个,仅供参考)===\n`);
for (const m of bad.slice(0, 60)) {
console.log(` ${m.prefix.padEnd(28)} ${String(m.total).padStart(6)} ${m.license.padEnd(28)} ${m.author || ''}`);
}
})().catch((e) => { console.error('❌', e.message); process.exit(1); });