Add dynamic indexes
This commit is contained in:
2
.github/config/codeql.yml
vendored
2
.github/config/codeql.yml
vendored
@@ -1,5 +1,3 @@
|
|||||||
name: CodeQL config
|
name: CodeQL config
|
||||||
queries:
|
queries:
|
||||||
- uses: security-and-quality
|
- uses: security-and-quality
|
||||||
paths-ignore:
|
|
||||||
- action/dist
|
|
||||||
@@ -92,12 +92,11 @@ It should be avoided when possible as it increases drastically the size of gener
|
|||||||
|
|
||||||
* `action.yml` contains GitHub action descriptor
|
* `action.yml` contains GitHub action descriptor
|
||||||
* `action/index.mjs` contains GitHub action source code
|
* `action/index.mjs` contains GitHub action source code
|
||||||
* `action/dist/index.js` contains compiled the GitHub action code (auto-generated)
|
|
||||||
|
|
||||||
#### Others
|
#### Others
|
||||||
|
|
||||||
* `tests/metrics.mjs` contains tests
|
* `tests/metrics.mjs` contains tests
|
||||||
* `utils/build.mjs` contains a tool used to rebuild plugins and template indexes and GitHub action
|
* `utils/build.mjs` contains a tool used to rebuild plugins and template indexes
|
||||||
|
|
||||||
### 📦 Used packages
|
### 📦 Used packages
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Load configuration
|
//Load configuration
|
||||||
const conf = await setup({log:false})
|
const {conf, Plugins, Templates} = await setup({log:false})
|
||||||
console.log(`Configuration │ loaded`)
|
console.log(`Configuration │ loaded`)
|
||||||
console.log(`Version │ ${conf.package.version}`)
|
console.log(`Version │ ${conf.package.version}`)
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@
|
|||||||
q = {...query, ...q, base:false, ...base, ...config, repositories, template}
|
q = {...query, ...q, base:false, ...base, ...config, repositories, template}
|
||||||
|
|
||||||
//Render metrics
|
//Render metrics
|
||||||
const rendered = await metrics({login:user, q, dflags}, {graphql, rest, plugins, conf, die})
|
const rendered = await metrics({login:user, q, dflags}, {graphql, rest, plugins, conf, die}, {Plugins, Templates})
|
||||||
console.log(`Render │ complete`)
|
console.log(`Render │ complete`)
|
||||||
|
|
||||||
//Verify svg
|
//Verify svg
|
||||||
|
|||||||
@@ -7,14 +7,13 @@
|
|||||||
import compression from "compression"
|
import compression from "compression"
|
||||||
import setup from "./setup.mjs"
|
import setup from "./setup.mjs"
|
||||||
import metrics from "./metrics.mjs"
|
import metrics from "./metrics.mjs"
|
||||||
import Templates from "./templates/index.mjs"
|
|
||||||
import util from "util"
|
import util from "util"
|
||||||
|
|
||||||
/** App */
|
/** App */
|
||||||
export default async function () {
|
export default async function () {
|
||||||
|
|
||||||
//Load configuration settings
|
//Load configuration settings
|
||||||
const conf = await setup()
|
const {conf, Plugins, Templates} = await setup()
|
||||||
const {token, maxusers = 0, restricted = [], debug = false, cached = 30*60*1000, port = 3000, ratelimiter = null, plugins = null} = conf.settings
|
const {token, maxusers = 0, restricted = [], debug = false, cached = 30*60*1000, port = 3000, ratelimiter = null, plugins = null} = conf.settings
|
||||||
|
|
||||||
//Load octokits
|
//Load octokits
|
||||||
@@ -109,7 +108,7 @@
|
|||||||
try {
|
try {
|
||||||
//Render
|
//Render
|
||||||
console.debug(`metrics/app/${login} > ${util.inspect(req.query, {depth:Infinity, maxStringLength:256})}`)
|
console.debug(`metrics/app/${login} > ${util.inspect(req.query, {depth:Infinity, maxStringLength:256})}`)
|
||||||
const rendered = await metrics({login, q:parse(req.query)}, {graphql, rest, plugins, conf})
|
const rendered = await metrics({login, q:parse(req.query)}, {graphql, rest, plugins, conf}, {Plugins, Templates})
|
||||||
//Cache
|
//Cache
|
||||||
if ((!debug)&&(cached)&&(login !== "placeholder"))
|
if ((!debug)&&(cached)&&(login !== "placeholder"))
|
||||||
cache.put(login, rendered, cached)
|
cache.put(login, rendered, cached)
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
import SVGO from "svgo"
|
import SVGO from "svgo"
|
||||||
import imgb64 from "image-to-base64"
|
import imgb64 from "image-to-base64"
|
||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
import Plugins from "./plugins/index.mjs"
|
|
||||||
import Templates from "./templates/index.mjs"
|
|
||||||
import puppeteer from "puppeteer"
|
import puppeteer from "puppeteer"
|
||||||
import url from "url"
|
import url from "url"
|
||||||
import processes from "child_process"
|
import processes from "child_process"
|
||||||
@@ -14,7 +12,7 @@
|
|||||||
import util from "util"
|
import util from "util"
|
||||||
|
|
||||||
//Setup
|
//Setup
|
||||||
export default async function metrics({login, q, dflags = []}, {graphql, rest, plugins, conf, die = false}) {
|
export default async function metrics({login, q, dflags = []}, {graphql, rest, plugins, conf, die = false}, {Plugins, Templates}) {
|
||||||
//Compute rendering
|
//Compute rendering
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
/* This file is generated automatically with "npm run build" */
|
|
||||||
|
|
||||||
//Imports
|
|
||||||
import followup from "./followup/index.mjs"
|
|
||||||
import gists from "./gists/index.mjs"
|
|
||||||
import habits from "./habits/index.mjs"
|
|
||||||
import isocalendar from "./isocalendar/index.mjs"
|
|
||||||
import languages from "./languages/index.mjs"
|
|
||||||
import lines from "./lines/index.mjs"
|
|
||||||
import music from "./music/index.mjs"
|
|
||||||
import pagespeed from "./pagespeed/index.mjs"
|
|
||||||
import posts from "./posts/index.mjs"
|
|
||||||
import projects from "./projects/index.mjs"
|
|
||||||
import topics from "./topics/index.mjs"
|
|
||||||
import traffic from "./traffic/index.mjs"
|
|
||||||
import tweets from "./tweets/index.mjs"
|
|
||||||
|
|
||||||
//Exports
|
|
||||||
export default {
|
|
||||||
followup,
|
|
||||||
gists,
|
|
||||||
habits,
|
|
||||||
isocalendar,
|
|
||||||
languages,
|
|
||||||
lines,
|
|
||||||
music,
|
|
||||||
pagespeed,
|
|
||||||
posts,
|
|
||||||
projects,
|
|
||||||
topics,
|
|
||||||
traffic,
|
|
||||||
tweets,
|
|
||||||
}
|
|
||||||
@@ -2,27 +2,38 @@
|
|||||||
import fs from "fs"
|
import fs from "fs"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import util from "util"
|
import util from "util"
|
||||||
|
import url from "url"
|
||||||
|
const Templates = {}
|
||||||
|
const Plugins = {}
|
||||||
|
|
||||||
/** Setup */
|
/** Setup */
|
||||||
export default async function ({log = true} = {}) {
|
export default async function ({log = true} = {}) {
|
||||||
|
|
||||||
|
//Paths
|
||||||
|
const __metrics = path.join(path.dirname(url.fileURLToPath(import.meta.url)), "..")
|
||||||
|
const __templates = path.join(__metrics, "src/templates")
|
||||||
|
const __plugins = path.join(__metrics, "src/plugins")
|
||||||
|
const __queries = path.join(__metrics, "src/queries")
|
||||||
|
const __package = path.join(__metrics, "package.json")
|
||||||
|
const __settings = path.join(__metrics, "settings.json")
|
||||||
|
const __statics = path.join(__metrics, "src/html")
|
||||||
|
const __modules = path.join(__metrics, "node_modules")
|
||||||
|
|
||||||
//Init
|
//Init
|
||||||
const logger = log ? console.debug : () => null
|
const logger = log ? console.debug : () => null
|
||||||
logger(`metrics/setup > setup`)
|
logger(`metrics/setup > setup`)
|
||||||
const templates = "src/templates"
|
|
||||||
const queries = "src/queries"
|
|
||||||
const conf = {
|
const conf = {
|
||||||
templates:{},
|
templates:{},
|
||||||
queries:{},
|
queries:{},
|
||||||
settings:{},
|
settings:{},
|
||||||
statics:path.resolve("src/html"),
|
statics:__statics,
|
||||||
node_modules:path.resolve("node_modules"),
|
node_modules:__modules,
|
||||||
}
|
}
|
||||||
|
|
||||||
//Load settings
|
//Load settings
|
||||||
logger(`metrics/setup > load settings.json`)
|
logger(`metrics/setup > load settings.json`)
|
||||||
if (fs.existsSync(path.resolve("settings.json"))) {
|
if (fs.existsSync(__settings)) {
|
||||||
conf.settings = JSON.parse(`${await fs.promises.readFile(path.resolve("settings.json"))}`)
|
conf.settings = JSON.parse(`${await fs.promises.readFile(__settings)}`)
|
||||||
logger(`metrics/setup > load settings.json > success`)
|
logger(`metrics/setup > load settings.json > success`)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -37,22 +48,20 @@
|
|||||||
|
|
||||||
//Load package settings
|
//Load package settings
|
||||||
logger(`metrics/setup > load package.json`)
|
logger(`metrics/setup > load package.json`)
|
||||||
conf.package = JSON.parse(`${await fs.promises.readFile(path.resolve("package.json"))}`)
|
conf.package = JSON.parse(`${await fs.promises.readFile(__package)}`)
|
||||||
logger(`metrics/setup > load package.json > success`)
|
logger(`metrics/setup > load package.json > success`)
|
||||||
|
|
||||||
//Load templates
|
//Load templates
|
||||||
for (const name of await fs.promises.readdir(templates)) {
|
for (const name of await fs.promises.readdir(__templates)) {
|
||||||
//Cache templates
|
//Cache templates file
|
||||||
if (/.*[.]mjs$/.test(name))
|
if (!(await fs.promises.lstat(path.join(__templates, name))).isDirectory())
|
||||||
continue
|
continue
|
||||||
logger(`metrics/setup > load template [${name}]`)
|
logger(`metrics/setup > load template [${name}]`)
|
||||||
const files = [
|
const files = ["image.svg", "style.css", "fonts.css"].map(file => path.join(__templates, (fs.existsSync(path.join(__templates, name, file)) ? name : "classic"), file))
|
||||||
`${templates}/${name}/image.svg`,
|
|
||||||
`${templates}/${name}/style.css`,
|
|
||||||
`${templates}/${name}/fonts.css`,
|
|
||||||
].map(file => fs.existsSync(path.resolve(file)) ? file : file.replace(`${templates}/${name}/`, `${templates}/classic/`)).map(file => path.resolve(file))
|
|
||||||
const [image, style, fonts] = await Promise.all(files.map(async file => `${await fs.promises.readFile(file)}`))
|
const [image, style, fonts] = await Promise.all(files.map(async file => `${await fs.promises.readFile(file)}`))
|
||||||
conf.templates[name] = {image, style, fonts}
|
conf.templates[name] = {image, style, fonts}
|
||||||
|
//Cache templates scripts
|
||||||
|
Templates[name] = (await import(url.pathToFileURL(path.join(__templates, name, "template.mjs")).href)).default
|
||||||
logger(`metrics/setup > load template [${name}] > success`)
|
logger(`metrics/setup > load template [${name}] > success`)
|
||||||
//Debug
|
//Debug
|
||||||
if (conf.settings.debug) {
|
if (conf.settings.debug) {
|
||||||
@@ -67,19 +76,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Load plugins
|
||||||
|
for (const name of await fs.promises.readdir(__plugins)) {
|
||||||
|
//Cache plugins scripts
|
||||||
|
logger(`metrics/setup > load plugin [${name}]`)
|
||||||
|
Plugins[name] = (await import(url.pathToFileURL(path.join(__plugins, name, "index.mjs")).href)).default
|
||||||
|
logger(`metrics/setup > load plugin [${name}] > success`)
|
||||||
|
}
|
||||||
|
|
||||||
//Load queries
|
//Load queries
|
||||||
for (const query of await fs.promises.readdir(queries)) {
|
for (const query of await fs.promises.readdir(__queries)) {
|
||||||
//Cache queries
|
//Cache queries
|
||||||
const name = query.replace(/[.]graphql$/, "")
|
const name = query.replace(/[.]graphql$/, "")
|
||||||
logger(`metrics/setup > load query [${name}]`)
|
logger(`metrics/setup > load query [${name}]`)
|
||||||
conf.queries[`_${name}`] = `${await fs.promises.readFile(path.resolve(`${queries}/${query}`))}`
|
conf.queries[`_${name}`] = `${await fs.promises.readFile(path.join(__queries, query))}`
|
||||||
logger(`metrics/setup > load query [${name}] > success`)
|
logger(`metrics/setup > load query [${name}] > success`)
|
||||||
//Debug
|
//Debug
|
||||||
if (conf.settings.debug) {
|
if (conf.settings.debug) {
|
||||||
Object.defineProperty(conf.queries, `_${name}`, {
|
Object.defineProperty(conf.queries, `_${name}`, {
|
||||||
get() {
|
get() {
|
||||||
logger(`metrics/setup > reload query [${name}]`)
|
logger(`metrics/setup > reload query [${name}]`)
|
||||||
const raw = `${fs.readFileSync(path.resolve(`${queries}/${query}`))}`
|
const raw = `${fs.readFileSync(path.join(__queries, query))}`
|
||||||
logger(`metrics/setup > reload query [${name}] > success`)
|
logger(`metrics/setup > reload query [${name}] > success`)
|
||||||
return raw
|
return raw
|
||||||
}
|
}
|
||||||
@@ -97,6 +114,6 @@
|
|||||||
|
|
||||||
//Conf
|
//Conf
|
||||||
logger(`metrics/setup > setup > success`)
|
logger(`metrics/setup > setup > success`)
|
||||||
return conf
|
return {Templates, Plugins, conf}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -20,11 +20,16 @@
|
|||||||
|
|
||||||
//Plugins
|
//Plugins
|
||||||
for (const name of Object.keys(imports.plugins)) {
|
for (const name of Object.keys(imports.plugins)) {
|
||||||
|
if (!plugins[name].enabled) {
|
||||||
|
console.log("skipping "+name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
pending.push((async () => {
|
pending.push((async () => {
|
||||||
try {
|
try {
|
||||||
console.debug(`metrics/compute/${login}/plugins > ${name} > started`)
|
console.debug(`metrics/compute/${login}/plugins > ${name} > started`)
|
||||||
data.plugins[name] = await imports.plugins[name]({login, q, imports, data, computed, rest, graphql, queries}, plugins[name])
|
data.plugins[name] = await imports.plugins[name]({login, q, imports, data, computed, rest, graphql, queries}, plugins[name])
|
||||||
console.debug(`metrics/compute/${login}/plugins > ${name} > completed (${data.plugins[name] !== null ? "success" : "skipped"})`)
|
console.debug(`metrics/compute/${login}/plugins > ${name} > completed`)
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.debug(`metrics/compute/${login}/plugins > ${name} > completed (error)`)
|
console.debug(`metrics/compute/${login}/plugins > ${name} > completed (error)`)
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
/* This file is generated automatically with "npm run build" */
|
|
||||||
|
|
||||||
//Imports
|
|
||||||
import classic from "./classic/template.mjs"
|
|
||||||
import repository from "./repository/template.mjs"
|
|
||||||
import terminal from "./terminal/template.mjs"
|
|
||||||
|
|
||||||
//Exports
|
|
||||||
export default {
|
|
||||||
classic,
|
|
||||||
repository,
|
|
||||||
terminal,
|
|
||||||
}
|
|
||||||
@@ -2,9 +2,10 @@
|
|||||||
const processes = require("child_process")
|
const processes = require("child_process")
|
||||||
const yaml = require("js-yaml")
|
const yaml = require("js-yaml")
|
||||||
const fs = require("fs")
|
const fs = require("fs")
|
||||||
|
const path = require("path")
|
||||||
|
|
||||||
//Github action
|
//Github action
|
||||||
const action = yaml.safeLoad(fs.readFileSync("action.yml", "utf8"))
|
const action = yaml.safeLoad(fs.readFileSync(path.join(__dirname, "../action.yml"), "utf8"))
|
||||||
action.defaults = Object.fromEntries(Object.entries(action.inputs).map(([key, {default:value}]) => [key, /^(yes|no)$/.test(value) ? value === "yes" : value]))
|
action.defaults = Object.fromEntries(Object.entries(action.inputs).map(([key, {default:value}]) => [key, /^(yes|no)$/.test(value) ? value === "yes" : value]))
|
||||||
action.input = vars => Object.fromEntries([...Object.entries(action.defaults), ...Object.entries(vars)].map(([key, value]) => [`INPUT_${key.toLocaleUpperCase()}`, value]))
|
action.input = vars => Object.fromEntries([...Object.entries(action.defaults), ...Object.entries(vars)].map(([key, value]) => [`INPUT_${key.toLocaleUpperCase()}`, value]))
|
||||||
action.run = async (vars) => await new Promise((solve, reject) => {
|
action.run = async (vars) => await new Promise((solve, reject) => {
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
//Imports
|
|
||||||
import fs from "fs"
|
|
||||||
import path from "path"
|
|
||||||
import url from "url"
|
|
||||||
import colors from "colors"
|
|
||||||
|
|
||||||
//Initialization
|
|
||||||
const __dirname = path.join(path.dirname(url.fileURLToPath(import.meta.url)), "..")
|
|
||||||
const __src = path.join(__dirname, "src")
|
|
||||||
const __plugins = path.join(__src, "plugins")
|
|
||||||
const __templates = path.join(__src, "templates")
|
|
||||||
process.on("unhandledRejection", error => { throw error })
|
|
||||||
colors.enable()
|
|
||||||
|
|
||||||
/** Build function */
|
|
||||||
export default async function build({actions = ["build"]} = {}) {
|
|
||||||
//Initialization
|
|
||||||
const errors = []
|
|
||||||
|
|
||||||
//Indexes
|
|
||||||
for (const {name, source, entry} of [{name:"plugins", source:__plugins, entry:"index.mjs"}, {name:"templates", source:__templates, entry:"template.mjs"}]) {
|
|
||||||
|
|
||||||
//Build
|
|
||||||
const files = (await fs.promises.readdir(source)).filter(name => !/.*[.]mjs$/.test(name)).sort()
|
|
||||||
const code = [
|
|
||||||
`/* This file is generated automatically with "npm run build" */`,
|
|
||||||
``,
|
|
||||||
`//Imports`,
|
|
||||||
...files.map(name => ` import ${name} from "./${name}/${entry}"`),
|
|
||||||
``,
|
|
||||||
`//Exports`,
|
|
||||||
` export default {`,
|
|
||||||
...files.map(name => ` ${name},`),
|
|
||||||
` }`
|
|
||||||
].join("\n")
|
|
||||||
console.log(`Generated index for ${name}`.grey)
|
|
||||||
|
|
||||||
//Save build
|
|
||||||
if (actions.includes("build")) {
|
|
||||||
fs.promises.writeFile(path.join(source, "index.mjs"), code)
|
|
||||||
console.log(`Generated index for ${name} saved to ${path.join(source, "index.mjs")}`.green)
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check build
|
|
||||||
if (actions.includes("check")) {
|
|
||||||
const status = `${await fs.promises.readFile(path.join(source, "index.mjs"))}` === code
|
|
||||||
if (status)
|
|
||||||
console.log(`Index ${name} is up-to-date`.grey)
|
|
||||||
else {
|
|
||||||
console.log(`Index ${name} is outdated`.red)
|
|
||||||
errors.push(`Index ${name} is outdated, run "npm run build" to fix it`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//Throw on errors
|
|
||||||
if (errors.length)
|
|
||||||
throw new Error(`${errors.length} errors occured :\n${errors.map(error => ` - ${error}`).join("\n")}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
//Main
|
|
||||||
if (/build.mjs/.test(process.argv[1])) {
|
|
||||||
//Build
|
|
||||||
await build()
|
|
||||||
console.log("Build success !".green)
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user