@@ -24,6 +24,7 @@ function usage() {
2424Usage:
2525 ./scripts/lnk LONG_URL [SLUG]
2626 ./scripts/lnk --splat LONG_URL_WITH_:splat SLUG
27+ ./scripts/lnk list [SLUG]
2728
2829Schedules:
2930 ./scripts/lnk schedule add SLUG TARGET --label LABEL --days mon,tue --from HH:MM --to HH:MM [--timezone TZ]
@@ -37,6 +38,7 @@ Block policies:
3738 ./scripts/lnk block allow DOMAIN --reason TEXT
3839
3940Options:
41+ --format FORMAT table | json for list output
4042 --state STATE permanent | ephemeral | expired | disabled | maintenance | deactivated
4143 --title TEXT Human-readable title
4244 --description TEXT Human-readable description
6668 Successful write operations run npm run check, then commit and push automatically.
6769
6870Examples:
71+ ./scripts/lnk list
72+ ./scripts/lnk list social/x
6973 ./scripts/lnk https://github.com/vanityURLs github
7074 ./scripts/lnk https://x.com/vanityURLs social/x
7175 ./scripts/lnk https://www.linkedin.com/company/example social/linkedin
@@ -101,6 +105,7 @@ function run(command, args) {
101105
102106function parseArgs ( argv ) {
103107 const options = {
108+ format : "table" ,
104109 state : "permanent" ,
105110 splat : false ,
106111 title : "" ,
@@ -117,6 +122,9 @@ function parseArgs(argv) {
117122
118123 if ( arg === "--help" || arg === "-h" ) {
119124 options . help = true ;
125+ } else if ( arg === "--format" ) {
126+ options . format = readOptionValue ( argv , index , arg ) ;
127+ index += 1 ;
120128 } else if ( arg === "--splat" ) {
121129 options . splat = true ;
122130 } else if ( arg === "--state" ) {
@@ -232,6 +240,70 @@ function readJson(filePath, fallback) {
232240 return JSON . parse ( fs . readFileSync ( filePath , "utf8" ) ) ;
233241}
234242
243+ function ensureRegistry ( ) {
244+ const registryPath = "build/v8s.json" ;
245+ if ( ! fs . existsSync ( registryPath ) ) {
246+ run ( "npm" , [ "run" , "build" ] ) ;
247+ }
248+
249+ return readJson ( registryPath , { links : [ ] } ) ;
250+ }
251+
252+ function listLinks ( requestedSlug , options ) {
253+ const registry = ensureRegistry ( ) ;
254+ const slug = requestedSlug ? normalizeSlug ( requestedSlug ) : "" ;
255+ const links = ( registry . links || [ ] )
256+ . filter ( ( link ) => ! slug || link . slug === slug )
257+ . sort ( ( a , b ) => a . slug . localeCompare ( b . slug ) ) ;
258+
259+ if ( options . format === "json" ) {
260+ console . log ( JSON . stringify ( links , null , 2 ) ) ;
261+ return ;
262+ }
263+
264+ if ( options . format !== "table" ) {
265+ throw new Error ( "--format must be table or json" ) ;
266+ }
267+
268+ if ( ! links . length ) {
269+ console . log ( slug ? `No link found for ${ slug } ` : "No links configured" ) ;
270+ return ;
271+ }
272+
273+ printTable ( links . map ( ( link ) => {
274+ return [
275+ link . slug ,
276+ link . state || "permanent" ,
277+ link . owner || "" ,
278+ link . title || "" ,
279+ link . target || ""
280+ ] ;
281+ } ) , [ "Slug" , "State" , "Owner" , "Title" , "Target" ] ) ;
282+ }
283+
284+ function printTable ( rows , headers ) {
285+ const widths = headers . map ( ( header , index ) => {
286+ return Math . min ( 40 , Math . max ( header . length , ...rows . map ( ( row ) => String ( row [ index ] || "" ) . length ) ) ) ;
287+ } ) ;
288+
289+ console . log ( headers . map ( ( header , index ) => padCell ( header , widths [ index ] ) ) . join ( " " ) ) ;
290+ console . log ( widths . map ( ( width ) => "-" . repeat ( width ) ) . join ( " " ) ) ;
291+
292+ for ( const row of rows ) {
293+ console . log ( row . map ( ( cell , index ) => padCell ( truncateCell ( cell , widths [ index ] ) , widths [ index ] ) ) . join ( " " ) ) ;
294+ }
295+ }
296+
297+ function truncateCell ( value , width ) {
298+ const text = String ( value || "" ) ;
299+ if ( text . length <= width ) return text ;
300+ return `${ text . slice ( 0 , Math . max ( 0 , width - 1 ) ) } …` ;
301+ }
302+
303+ function padCell ( value , width ) {
304+ return String ( value || "" ) . padEnd ( width , " " ) ;
305+ }
306+
235307function writeJson ( filePath , value ) {
236308 fs . mkdirSync ( dirname ( filePath ) , {
237309 recursive : true
@@ -452,6 +524,11 @@ function main() {
452524 return ;
453525 }
454526
527+ if ( positionals [ 0 ] === "list" ) {
528+ listLinks ( positionals [ 1 ] || "" , options ) ;
529+ return ;
530+ }
531+
455532 const target = positionals [ 0 ] || "" ;
456533 let slug = positionals [ 1 ] || "" ;
457534
0 commit comments