11import express from 'express' ;
2- import Promise from 'bluebird' ;
32import fs from 'fs-extra' ;
4- import path from 'path' ;
5- import { NotFoundError } from '/common/error' ;
6- import { GitHubApi } from '/apis' ;
7- import { createKey , execute , listDirectories , listFiles } from '/common/util' ;
3+ import { execute } from '/common/util' ;
84import webhook from '/common/webhook' ;
5+ import hierarchy from '/common/hierarchy' ;
6+ import { NotFoundError } from '../common/error' ;
97
108const router = express . Router ( ) ;
119
12- const repoPath = path . resolve ( __dirname , '..' , 'public' , 'algorithms' ) ;
13- const getPath = ( ...args ) => path . resolve ( repoPath , ...args ) ;
14-
15- const cacheFile = ( categoryName , algorithmName , fileName ) => {
16- const filePath = getPath ( categoryName , algorithmName , fileName ) ;
17- const content = fs . readFileSync ( filePath , 'utf-8' ) ;
18- return {
19- name : fileName ,
20- path : filePath ,
21- content,
22- contributors : [ ] ,
23- toJSON : ( ) => fileName ,
24- } ;
25- } ;
26-
27- const cacheAlgorithm = ( categoryName , algorithmName ) => {
28- const algorithmKey = createKey ( algorithmName ) ;
29- const algorithmPath = getPath ( categoryName , algorithmName ) ;
30- const files = listFiles ( algorithmPath ) . map ( fileName => cacheFile ( categoryName , algorithmName , fileName ) ) ;
31- return {
32- key : algorithmKey ,
33- name : algorithmName ,
34- files,
35- } ;
36- } ;
37-
38- const cacheCategory = categoryName => {
39- const categoryKey = createKey ( categoryName ) ;
40- const categoryPath = getPath ( categoryName ) ;
41- const algorithms = listDirectories ( categoryPath ) . map ( algorithmName => cacheAlgorithm ( categoryName , algorithmName ) ) ;
42- return {
43- key : categoryKey ,
44- name : categoryName ,
45- algorithms,
46- } ;
47- } ;
48-
49- const cacheCommitAuthors = ( page = 1 , commitAuthors = { } ) => {
50- const per_page = 100 ;
51- return GitHubApi . listCommits ( 'algorithm-visualizer' , 'algorithms' , {
52- per_page,
53- page,
54- } ) . then ( commits => {
55- commits . forEach ( ( { sha, commit, author } ) => {
56- if ( ! author ) return ;
57- const { login, avatar_url } = author ;
58- commitAuthors [ sha ] = { login, avatar_url } ;
59- } ) ;
60- if ( commits . length < per_page ) {
61- return commitAuthors ;
62- } else {
63- return cacheCommitAuthors ( page + 1 , commitAuthors ) ;
64- }
65- } ) ;
66- } ;
67-
68- const cacheContributors = ( files , commitAuthors ) => Promise . each ( files , file => {
69- return execute ( `git --no-pager log --follow --no-merges --format="%H" "${ file . path } "` , getPath ( ) , { stdout : null } )
70- . then ( stdout => {
71- const output = stdout . toString ( ) . replace ( / \n $ / , '' ) ;
72- const shas = output . split ( '\n' ) . reverse ( ) ;
73- const contributors = [ ] ;
74- for ( const sha of shas ) {
75- const author = commitAuthors [ sha ] ;
76- if ( author && ! contributors . find ( contributor => contributor . login === author . login ) ) {
77- contributors . push ( author ) ;
78- }
79- }
80- file . contributors = contributors ;
81- } ) ;
82- } ) ;
83-
84- const cacheCategories = ( ) => {
85- const categories = listDirectories ( getPath ( ) ) . map ( cacheCategory ) ;
86-
87- const files = [ ] ;
88- categories . forEach ( category => category . algorithms . forEach ( algorithm => files . push ( ...algorithm . files ) ) ) ;
89- cacheCommitAuthors ( ) . then ( commitAuthors => cacheContributors ( files , commitAuthors ) ) ;
90-
91- return categories ;
92- } ;
93-
94- let categories = [ ] ;
9510const downloadCategories = ( ) => (
96- fs . pathExistsSync ( repoPath ) ?
97- execute ( `git fetch && git reset --hard origin/master` , repoPath ) :
98- execute ( `git clone https://github.com/algorithm-visualizer/algorithms.git ${ repoPath } ` , __dirname )
99- ) . then ( ( ) => categories = cacheCategories ( ) ) ;
11+ fs . pathExistsSync ( hierarchy . path ) ?
12+ execute ( `git fetch && git reset --hard origin/master` , hierarchy . path ) :
13+ execute ( `git clone https://github.com/algorithm-visualizer/algorithms.git ${ hierarchy . path } ` , __dirname )
14+ ) . then ( ( ) => hierarchy . refresh ( ) ) ;
10015
10116downloadCategories ( ) . catch ( console . error ) ;
10217
@@ -110,30 +25,23 @@ webhook.on('algorithms', event => {
11025
11126router . route ( '/' )
11227 . get ( ( req , res , next ) => {
113- res . json ( { categories } ) ;
28+ res . json ( hierarchy ) ;
11429 } ) ;
11530
11631router . route ( '/:categoryKey/:algorithmKey' )
11732 . get ( ( req , res , next ) => {
11833 const { categoryKey, algorithmKey } = req . params ;
119-
120- const category = categories . find ( category => category . key === categoryKey ) ;
121- if ( ! category ) return next ( new NotFoundError ( ) ) ;
122- const algorithm = category . algorithms . find ( algorithm => algorithm . key === algorithmKey ) ;
34+ const algorithm = hierarchy . find ( categoryKey , algorithmKey ) ;
12335 if ( ! algorithm ) return next ( new NotFoundError ( ) ) ;
124-
125- const categoryName = category . name ;
126- const algorithmName = algorithm . name ;
127- const files = algorithm . files . map ( ( { name, content, contributors } ) => ( { name, content, contributors } ) ) ;
128- res . json ( { algorithm : { categoryKey, categoryName, algorithmKey, algorithmName, files } } ) ;
36+ res . json ( { algorithm } ) ;
12937 } ) ;
13038
13139router . route ( '/sitemap.txt' )
13240 . get ( ( req , res , next ) => {
13341 const urls = [ ] ;
134- categories . forEach ( category => category . algorithms . forEach ( algorithm => {
42+ hierarchy . iterate ( ( category , algorithm ) => {
13543 urls . push ( `https://algorithm-visualizer.org/${ category . key } /${ algorithm . key } ` ) ;
136- } ) ) ;
44+ } ) ;
13745 res . set ( 'Content-Type' , 'text/plain' ) ;
13846 res . send ( urls . join ( '\n' ) ) ;
13947 } ) ;
0 commit comments