11// @ts -check
2- const PLUGIN_QUERY = `https://www.npmjs.com/search?q=keywords%3Atypedoc-plugin keywords%3Atypedocplugin` ;
3- const THEME_QUERY = `https://www.npmjs.com/search?q=keywords%3Atypedoc-theme` ;
4-
52import * as cp from "child_process" ;
63import { promises as fs , mkdirSync } from "fs" ;
74import semver from "semver" ;
85
96const CACHE_ROOT = "tmp/site-cache" ;
107mkdirSync ( CACHE_ROOT , { recursive : true } ) ;
118
9+ // cspell: disable
1210const EXCLUDED_PLUGINS = [
1311 // Fork not intended for public use.
1412 "@zamiell/typedoc-plugin-markdown" ,
@@ -32,6 +30,7 @@ const EXCLUDED_PLUGIN_USERS = [
3230 "silei" ,
3331 "tivmof" ,
3432] ;
33+ // cspell: enable
3534
3635/** @type {(command: string) => Promise<string> } */
3736function exec ( command ) {
@@ -54,15 +53,13 @@ async function getSupportedVersions(npmPackage) {
5453/**
5554 * @typedef {object } NpmPackage
5655 * @prop {string } name
57- * @prop {{ name: string} } publisher
56+ * @prop {string[] } keywords
57+ * @prop {string } version
5858 * @prop {string } description
59- * @prop {{ ts: number; rel: string} } date
59+ * @prop {{ username: string} } publisher
60+ * @prop {string } license
61+ * @prop {string } date
6062 * @prop {NpmLinks } links
61- * @prop {string } version
62- */
63-
64- /**
65- * @typedef {NpmPackage & { peer: string} } NpmPackageWithPeer
6663 */
6764
6865/**
@@ -73,35 +70,22 @@ async function getSupportedVersions(npmPackage) {
7370 */
7471
7572/**
76- * @typedef {object } PackagesResponse
77- * @prop {number } total
78- * @prop {{ package: NpmPackage }[] } objects
73+ * @typedef {NpmPackage & { peer: string} } NpmPackageWithPeer
7974 */
8075
8176/**
8277 * @param {string } query
8378 * @returns {Promise<NpmPackage[]> }
8479 */
8580async function getAllPackages ( query ) {
86- let page = 0 ;
87- let total = 0 ;
81+ const FORCE = process . env [ "CI" ] ? " --prefer-online" : "" ;
82+
8883 /** @type {NpmPackage[] } */
89- const result = [ ] ;
90-
91- do {
92- /** @type {PackagesResponse } */
93- const data = await (
94- await fetch ( `${ query } &page=${ page ++ } ` , {
95- headers : {
96- // Ask for JSON. Hasn't changed since 2018 at least...
97- "x-spiferack" : "1" ,
98- } ,
99- } )
100- ) . json ( ) ;
101-
102- total = data . total ;
103- result . push ( ...data . objects . map ( ( x ) => x . package ) ) ;
104- } while ( result . length < total ) ;
84+ const result = JSON . parse (
85+ await exec (
86+ `npm search "${ query } " --json --long --searchlimit 1000${ FORCE } ` ,
87+ ) ,
88+ ) ;
10589
10690 return result ;
10791}
@@ -117,7 +101,7 @@ function getSupportingPlugins(typedocVersion, plugins) {
117101
118102 for ( const plugin of plugins ) {
119103 if ( EXCLUDED_PLUGINS . includes ( plugin . name ) ) continue ;
120- if ( EXCLUDED_PLUGIN_USERS . includes ( plugin . publisher . name ) ) continue ;
104+ if ( EXCLUDED_PLUGIN_USERS . includes ( plugin . publisher . username ) ) continue ;
121105
122106 let version = plugin . peer . trim ( ) ;
123107 if ( ! version ) continue ;
@@ -173,8 +157,46 @@ function getAllVersions(plugins) {
173157 return Promise . all ( plugins . map ( ( p ) => getSupportedVersions ( p . name ) ) ) ;
174158}
175159
160+ /** @param {string } date */
161+ function relativeDate ( date ) {
162+ const nowHours = Date . now ( ) / 1000 / 60 / 60 ;
163+ const dateHours = Date . parse ( date ) / 1000 / 60 / 60 ;
164+
165+ const deltaHours = nowHours - dateHours ;
166+ if ( deltaHours <= 24 ) {
167+ return "today" ;
168+ }
169+
170+ const deltaDays = deltaHours / 24 ;
171+ if ( deltaDays <= 7 ) {
172+ if ( Math . floor ( deltaDays ) == 1 ) {
173+ return "1 day ago" ;
174+ }
175+ return `${ Math . floor ( deltaDays ) } days ago` ;
176+ }
177+
178+ const deltaWeeks = Math . floor ( deltaDays / 7 ) ;
179+ if ( deltaWeeks <= 3 ) {
180+ return `${ deltaWeeks } weeks ago` ;
181+ }
182+
183+ // Close enough...
184+ const deltaMonths = Math . floor ( deltaDays / 30 ) ;
185+ if ( deltaMonths <= 12 ) {
186+ if ( deltaMonths < 2 ) {
187+ return "1 month ago" ;
188+ }
189+ return `${ deltaMonths } months ago` ;
190+ }
191+
192+ const deltaYears = Math . floor ( deltaDays / 365 ) ;
193+ if ( deltaYears < 2 ) {
194+ return "1 year ago" ;
195+ }
196+ return `${ deltaYears } years ago` ;
197+ }
198+
176199/**
177- *
178200 * @param {NpmPackageWithPeer[] } plugins
179201 * @param {string[] } checkVersions
180202 * @param {string } path
@@ -184,19 +206,31 @@ async function createInclude(plugins, checkVersions, path) {
184206 const out = [ ] ;
185207
186208 for ( const typedocVersion of checkVersions ) {
209+ const supportingPlugins = getSupportingPlugins (
210+ typedocVersion ,
211+ plugins ,
212+ ) . sort ( ( a , b ) => Date . parse ( b . date ) - Date . parse ( a . date ) ) ;
213+
214+ if ( supportingPlugins . length === 0 ) {
215+ continue ;
216+ }
217+
187218 out . push ( `## v${ typedocVersion . replace ( / \. \d + $ / , "" ) } \n` ) ;
188219
189- for ( const plugin of getSupportingPlugins ( typedocVersion , plugins ) . sort (
190- ( a , b ) => b . date . ts - a . date . ts ,
191- ) ) {
220+ for ( const plugin of supportingPlugins ) {
192221 out . push ( `<div class="box">` ) ;
193222 out . push (
194- ` <p class="title"><a href="${ plugin . links . npm } " target="_blank">${ plugin . name } </a></p>` ,
223+ ` <p class="box- title"><a href="${ plugin . links . npm } " target="_blank">${ plugin . name } </a></p>` ,
195224 ) ;
196225 out . push ( ` <p>${ miniMarkdown ( plugin . description || "" ) } </p>` ) ;
197- out . push ( ` <p>
198- <a href="https://www.npmjs.com/~${ plugin . publisher . name } " target="_blank">${ plugin . publisher . name } </a> published ${ plugin . version } • ${ plugin . date . rel }
199- </p>` ) ;
226+ out . push (
227+ ` <p>` ,
228+ ` <a href="https://www.npmjs.com/~${ plugin . publisher . username } " target="_blank">${ plugin . publisher . username } </a> •` ,
229+ ` ${ plugin . version } •` ,
230+ ` ${ relativeDate ( plugin . date ) } •` ,
231+ ` ${ plugin . license || "no license" } ` ,
232+ ` </p>` ,
233+ ) ;
200234 out . push ( `</div>\n` ) ;
201235 }
202236
@@ -239,15 +273,27 @@ function escapeHtml(html) {
239273async function main ( ) {
240274 console . log ( "Getting themes..." ) ;
241275 const themes = await getLocalCache ( "themes.json" , ( ) =>
242- getAllPackages ( THEME_QUERY ) ,
276+ getAllPackages ( "keywords:typedoc-theme" ) ,
243277 ) ;
244278
245279 console . log ( "Getting plugins..." ) ;
246- const plugins = await getLocalCache ( "plugins.json" , async ( ) =>
247- ( await getAllPackages ( PLUGIN_QUERY ) ) . filter (
248- ( pack ) => ! themes . some ( ( t ) => t . name === pack . name ) ,
249- ) ,
250- ) ;
280+ const plugins = await getLocalCache ( "plugins.json" , async ( ) => {
281+ const plugins = await getAllPackages ( "keywords:typedoc-plugin" ) ;
282+ const plugins2 = await getAllPackages ( "keywords:typedocplugin" ) ;
283+
284+ /** @type {NpmPackage[] } */
285+ const result = [ ] ;
286+ for ( const pack of [ ...plugins , ...plugins2 ] ) {
287+ if (
288+ ! result . some ( ( p ) => p . name === pack . name ) &&
289+ ! themes . some ( ( p ) => p . name === pack . name )
290+ ) {
291+ result . push ( pack ) ;
292+ }
293+ }
294+
295+ return result ;
296+ } ) ;
251297
252298 console . log ( "Getting typedoc versions..." ) ;
253299 const versions = await getLocalCache ( "versions.json" , ( ) =>
0 commit comments