Check the open source attribution list against what ships (#3058)

This commit is contained in:
Paweł Kuna authored and GitHub committed 2026-09-14 20:13:06 +02:00
1 parent ea10f0e296
commit 2129b0b881
4 files changed
+258 -85

No files matched your search

+115
View File
@@ -0,0 +1,115 @@
#!/usr/bin/env node
// Keeps shared/data/open-source.json — the attribution table on the docs page
// /ui/getting-started/references — in step with the libraries Tabler actually
// ships. The list is hand-written, so without this check a new dependency
// lands unattributed and a removed one lingers as a claim that is no longer true.
//
// Two sources say what ships:
// - core/libs.json: libraries copied to dist/libs or loaded from a CDN
// - bare imports in core/js/src/**: packages bundled into tabler.js
//
// An attribution names its library with "npm" (a package) or "lib" (a key in
// core/libs.json, for a library loaded straight from a CDN). Vendored code has
// neither, so it is listed in BUNDLED_SOURCE; a libs.json entry that is not
// open source at all is listed in NOT_OPEN_SOURCE.
// Run: pnpm run check:open-source
import { readFileSync } from 'node:fs'
import { join, dirname, relative } from 'node:path'
import { fileURLToPath } from 'node:url'
import { sync } from 'glob'
const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..')
// Attributed without a package: the source lives in this repo.
const BUNDLED_SOURCE = new Set(['Bootstrap'])
// Shipped, but nothing to attribute: a proprietary service loaded by url.
const NOT_OPEN_SOURCE = new Set(['google-maps'])
type Attribution = { name: string; npm?: string; lib?: string; url: string; description: string; license: string }
type Lib = { npm?: string }
const attributionsPath = join(repoRoot, 'shared', 'data', 'open-source.json')
const attributions = JSON.parse(readFileSync(attributionsPath, 'utf8')) as Attribution[]
const libs = JSON.parse(readFileSync(join(repoRoot, 'core', 'libs.json'), 'utf8')) as Record<string, Lib>
// A bare import names a package: `imask`, `@popperjs/core`, `plyr/dist/plyr.js`.
// Scoped packages keep two segments, everything else keeps the first.
const packageOf = (specifier: string): string => {
const parts = specifier.split('/')
return specifier.startsWith('@') ? parts.slice(0, 2).join('/') : (parts[0] ?? specifier)
}
// A library is identified by its package name, or by its libs.json key when it
// has none, so the two kinds never collide.
const shipped = new Map<string, string>()
const ship = (id: string, source: string): void => {
if (!shipped.has(id)) {
shipped.set(id, source)
}
}
for (const [key, lib] of Object.entries(libs)) {
if (NOT_OPEN_SOURCE.has(key)) {
continue
}
ship(lib.npm ? `npm:${lib.npm}` : `lib:${key}`, `core/libs.json (${key})`)
}
for (const file of sync(join(repoRoot, 'core', 'js', 'src', '**', '*.ts'))) {
const source = readFileSync(file, 'utf8')
for (const match of source.matchAll(/^\s*import\s[^'"]*from\s+['"]([^'".][^'"]*)['"]/gm)) {
const specifier = match[1] ?? ''
if (!specifier.startsWith('node:')) {
ship(`npm:${packageOf(specifier)}`, relative(repoRoot, file))
}
}
}
const errors: string[] = []
const attributed = new Map<string, Attribution>()
for (const entry of attributions) {
if (!entry.name || !entry.url || !entry.description || !entry.license) {
errors.push(`${entry.name || '(unnamed entry)'}: name, url, description and license are all required`)
continue
}
const id = entry.npm ? `npm:${entry.npm}` : entry.lib ? `lib:${entry.lib}` : null
if (!id) {
if (!BUNDLED_SOURCE.has(entry.name)) {
errors.push(`${entry.name}: add an "npm" or "lib" field, or add the name to BUNDLED_SOURCE in this script`)
}
continue
}
if (attributed.has(id)) {
errors.push(`${entry.name}: ${id} is attributed twice`)
continue
}
attributed.set(id, entry)
if (!shipped.has(id)) {
errors.push(`${entry.name}: ${id} is not shipped any more — remove the entry`)
}
}
for (const [id, source] of shipped) {
if (!attributed.has(id)) {
errors.push(`${id} ships from ${source} but has no entry in shared/data/open-source.json`)
}
}
if (errors.length > 0) {
console.error(`Found ${errors.length} attribution problem(s):\n`)
for (const error of errors.sort()) console.error(` ${error}`)
console.error('\nThe list renders on the docs page /ui/getting-started/references.')
process.exit(1)
}
console.log(`OK — ${attributions.length} attributions, ${shipped.size} shipped packages, nothing missing or stale.`)
+5
View File
@@ -0,0 +1,5 @@
---
"@tabler/docs": patch
---
Added a `check:open-source` gate and the five missing attributions, including Popper, which ships inside `tabler.js`.
+2 -1
View File
@@ -26,9 +26,10 @@
"check:tokens": "tsx .build/generate-tokens.ts check",
"check:docs-links": "tsx .build/check-docs-links.ts",
"check:css-vars": "tsx .build/check-css-vars.ts",
"check:open-source": "tsx .build/check-open-source.ts",
"check:html": "tsx .build/check-html.ts",
"check:markup-classes": "tsx .build/check-markup-classes.ts",
"lint": "pnpm run lint:md && pnpm run check:docs-links && pnpm run lint:prettier && pnpm run lint:scss && pnpm run check:css-vars && pnpm run check:tokens",
"lint": "pnpm run lint:md && pnpm run check:docs-links && pnpm run lint:prettier && pnpm run lint:scss && pnpm run check:css-vars && pnpm run check:open-source && pnpm run check:tokens",
"lint:fix": "pnpm run lint:md:fix && pnpm run lint:scss:fix && pnpm run format:prettier",
"lint:scss": "pnpm --filter @tabler/core lint",
"lint:scss:fix": "pnpm --filter @tabler/core lint:scss:fix",
+136 -84
View File
@@ -1,4 +1,11 @@
[
{
"name": "ApexCharts",
"npm": "apexcharts",
"url": "https://apexcharts.com/",
"description": "Modern charting library offering interactive and responsive charts.",
"license": "MIT"
},
{
"name": "Bootstrap",
"url": "https://getbootstrap.com/",
@@ -6,105 +13,150 @@
"license": "MIT"
},
{
"name": "IMask",
"url": "https://imask.js.org/",
"description": "Vanilla JavaScript input masking library with support for various mask types and dynamic behavior.",
"license": "MIT"
},
{
"name": "ApexCharts",
"url": "https://apexcharts.com/",
"description": "Modern charting library offering interactive and responsive charts.",
"license": "MIT"
},
{
"name": "noUiSlider",
"url": "https://refreshless.com/nouislider/",
"description": "Lightweight JavaScript range slider with multi-touch support and extensive customization options.",
"license": "MIT"
},
{
"name": "List.js",
"url": "https://listjs.com/",
"description": "Adds search, sort, and flexibility to tables, lists, and various HTML elements.",
"license": "MIT"
},
{
"name": "Masonry",
"url": "https://masonry.desandro.com/",
"description": "JavaScript grid layout library that arranges elements optimally based on available vertical space.",
"license": "MIT"
},
{
"name": "Mapbox GL JS",
"url": "https://docs.mapbox.com/mapbox-gl-js/",
"description": "JavaScript library for interactive, customizable vector maps on the web.",
"license": "BSD-3-Clause"
},
{
"name": "Litepicker",
"url": "https://github.com/wakirin/Litepicker",
"description": "Lightweight, no-dependency date range picker.",
"license": "MIT"
},
{
"name": "Tom Select",
"url": "https://tom-select.js.org/",
"description": "Dynamic and framework-agnostic <select> UI control with autocomplete and keyboard navigation.",
"license": "Apache-2.0"
},
{
"name": "jsVectorMap",
"url": "https://jvm-docs.vercel.app/",
"description": "Lightweight JavaScript library for creating interactive maps and data visualizations.",
"license": "MIT"
},
{
"name": "Fslightbox",
"url": "https://fslightbox.com/",
"description": "Vanilla JavaScript plugin for displaying images and videos in a fullscreen lightbox.",
"license": "MIT"
},
{
"name": "HugeRTE",
"url": "https://hugerte.org/",
"description": "MIT-licensed fork of TinyMCE, a web-based JavaScript HTML WYSIWYG editor control.",
"license": "MIT"
},
{
"name": "Plyr",
"url": "https://plyr.io/",
"description": "Simple, accessible, and customizable HTML5, YouTube, and Vimeo media player.",
"license": "MIT"
},
{
"name": "Dropzone",
"url": "https://www.dropzone.dev/",
"description": "Open-source library that provides drag-and-drop file uploads with image previews.",
"license": "MIT"
},
{
"name": "Star Rating.js",
"url": "https://pryley.github.io/star-rating.js/",
"description": "Lightweight JavaScript library for rendering star ratings.",
"name": "clipboard.js",
"npm": "clipboard",
"url": "https://clipboardjs.com/",
"description": "Copies text to the clipboard without Flash or a framework.",
"license": "MIT"
},
{
"name": "Coloris",
"npm": "@melloware/coloris",
"url": "https://github.com/melloware/coloris-npm",
"description": "Lightweight and elegant color picker written in vanilla JavaScript.",
"license": "MIT"
},
{
"name": "Typed.js",
"url": "https://mattboldt.com/demos/typed-js/",
"description": "JavaScript library that types out sentences in a human-like manner.",
"name": "Driver.js",
"npm": "driver.js",
"url": "https://driverjs.com/",
"description": "Highlights page elements to build product tours and hints.",
"license": "MIT"
},
{
"name": "Dropzone",
"npm": "dropzone",
"url": "https://www.dropzone.dev/",
"description": "Open-source library that provides drag-and-drop file uploads with image previews.",
"license": "MIT"
},
{
"name": "Fslightbox",
"npm": "fslightbox",
"url": "https://fslightbox.com/",
"description": "Vanilla JavaScript plugin for displaying images and videos in a fullscreen lightbox.",
"license": "MIT"
},
{
"name": "FullCalendar",
"npm": "fullcalendar",
"url": "https://fullcalendar.io/",
"description": "Full-sized drag-and-drop event calendar.",
"license": "MIT"
},
{
"name": "HugeRTE",
"npm": "hugerte",
"url": "https://hugerte.org/",
"description": "MIT-licensed fork of TinyMCE, a web-based JavaScript HTML WYSIWYG editor control.",
"license": "MIT"
},
{
"name": "IMask",
"npm": "imask",
"url": "https://imask.js.org/",
"description": "Vanilla JavaScript input masking library with support for various mask types and dynamic behavior.",
"license": "MIT"
},
{
"name": "jsVectorMap",
"npm": "jsvectormap",
"url": "https://jvm-docs.vercel.app/",
"description": "Lightweight JavaScript library for creating interactive maps and data visualizations.",
"license": "MIT"
},
{
"name": "List.js",
"npm": "list.js",
"url": "https://listjs.com/",
"description": "Adds search, sort, and flexibility to tables, lists, and various HTML elements.",
"license": "MIT"
},
{
"name": "Litepicker",
"npm": "litepicker",
"url": "https://github.com/wakirin/Litepicker",
"description": "Lightweight, no-dependency date range picker.",
"license": "MIT"
},
{
"name": "Mapbox GL JS",
"lib": "mapbox",
"url": "https://docs.mapbox.com/mapbox-gl-js/",
"description": "JavaScript library for interactive, customizable vector maps on the web.",
"license": "BSD-3-Clause"
},
{
"name": "Masonry",
"lib": "masonry",
"url": "https://masonry.desandro.com/",
"description": "JavaScript grid layout library that arranges elements optimally based on available vertical space.",
"license": "MIT"
},
{
"name": "noUiSlider",
"npm": "nouislider",
"url": "https://refreshless.com/nouislider/",
"description": "Lightweight JavaScript range slider with multi-touch support and extensive customization options.",
"license": "MIT"
},
{
"name": "Plyr",
"npm": "plyr",
"url": "https://plyr.io/",
"description": "Simple, accessible, and customizable HTML5, YouTube, and Vimeo media player.",
"license": "MIT"
},
{
"name": "Popper",
"npm": "@popperjs/core",
"url": "https://popper.js.org/",
"description": "Positioning engine for tooltips, popovers and dropdowns.",
"license": "MIT"
},
{
"name": "Signature Pad",
"npm": "signature_pad",
"url": "https://github.com/szimek/signature_pad",
"description": "JavaScript library for drawing smooth signatures.",
"license": "MIT"
},
{
"name": "SortableJS",
"npm": "sortablejs",
"url": "https://sortablejs.github.io/Sortable/",
"description": "Library for reorderable drag-and-drop lists.",
"license": "MIT"
},
{
"name": "Star Rating.js",
"npm": "star-rating.js",
"url": "https://pryley.github.io/star-rating.js/",
"description": "Lightweight JavaScript library for rendering star ratings.",
"license": "MIT"
},
{
"name": "Tom Select",
"npm": "tom-select",
"url": "https://tom-select.js.org/",
"description": "Dynamic and framework-agnostic <select> UI control with autocomplete and keyboard navigation.",
"license": "Apache-2.0"
},
{
"name": "Typed.js",
"npm": "typed.js",
"url": "https://mattboldt.com/demos/typed-js/",
"description": "JavaScript library that types out sentences in a human-like manner.",
"license": "MIT"
}
]