mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 05:06:55 +04:00
Check the open source attribution list against what ships (#3058)
This commit is contained in:
1 parent
ea10f0e296
commit
2129b0b881
4 files changed
+258
-85
No files matched your search
@@ -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.`)
|
||||
@@ -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
@@ -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
@@ -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"
|
||||
}
|
||||
]
|
||||
Reference in new issue
Block a user