Skip to content

Commit 37d68c0

Browse files
authored
Feat(contentFolder): add support for multi-level folders (#290)
* feat(contentfolder): support multi-level folders for contentFolder * test(update): update test for new files * chore(config): remove **
1 parent da3c1f8 commit 37d68c0

12 files changed

Lines changed: 119 additions & 27 deletions

File tree

blog/2014/2/12/asdf.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
3+
title: 'My testing page'
4+
author: 'Sander Elias'
5+
'publish date': 2019-11-27T00:00:00.000Z
6+
published: true
7+
description: 'This is the second demo page in this sample.'
8+
slugs:
9+
10+
- **_UNPUBLISHED_**k6gdpy1m_BTpYcQqBTb1b1O2PhZMouEEVowWCj2f9
11+
---# Page 2
12+
13+
## its a wild world after all
14+
15+
```typescript
16+
console.log('amazing');
17+
```
18+
19+
Related information [page-3](/blog/page-3)
20+
21+
[site-map](/home)

blog/page-5.md

Whitespace-only changes.

blog/test/testing.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
3+
title: 'My asdf page'
4+
author: 'Sander Elias'
5+
'publish date': 2019-11-27T00:00:00.000Z
6+
published: true
7+
description: 'This is the second demo page in this sample.'
8+
slugs:
9+
10+
- **_UNPUBLISHED_**k6gdpy1j_O72ihU7pHaGazECXHBnXR7v3nPchK3PX
11+
---# Page 2
12+
13+
## its a wild world after all
14+
15+
```typescript
16+
console.log('amazing');
17+
```
18+
19+
Related information [page-3](/blog/page-3)
20+
21+
[site-map](/home)

blog/testing-empty.md

Whitespace-only changes.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"scully:r": "node ./dist/scully/scully serve",
1313
"scully:precommit": "npm run scully:compile:all && rm -rf ./dist/static && node ./dist/scully/scully && npm run test",
1414
"scully:compile:all": "ng build @scullyio/ng-lib && ng build --prod && npm run scully:dev:compile",
15-
"generate": "tsc -p ./scully/tsconfig.scully.json && node ./scully/bin",
15+
"generate": "tsc -p ./scully/tsconfig.scully.json && node ./dist/scully/scully",
1616
"scully:dev:watch": "tsc -w -p ./scully/tsconfig.scully.json",
1717
"scully:dev:compile": "tsc -p ./scully/tsconfig.scully.json",
1818
"scully:dev:run": "nodemon ./dist/scully/scully.js --ext js",

projects/sampleBlog/src/app/blog/blog-routing.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ const routes: Routes = [
99
path: ':slug',
1010
component: BlogComponent,
1111
},
12+
{
13+
path: '**',
14+
component: BlogComponent,
15+
},
1216
];
1317

1418
@NgModule({

schematics/scully/src/files/markdown-module/__name@dasherize__-routing.module.ts.template

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ const routes: Routes = [
77
{
88
path: ':<%= camelize(slug) %>',
99
component: <%= classify(name) %>Component,
10+
},
11+
{
12+
path: '**',
13+
component: <%= classify(name) %>Component,
1014
}
1115
];
1216

scully.sampleBlog.config.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,12 @@ exports.config = {
7171
folder: './blog',
7272
},
7373
},
74-
'/**': {
75-
type: 'ignored',
74+
'/blog/:slug': {
75+
type: 'contentFolder',
76+
// postRenderers: ['toc'],
77+
slug: {
78+
folder: './blog',
79+
},
7680
},
7781
},
7882
guessParserOptions: {

scully/routerPlugins/contentFolderPlugin.ts

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import {readdir} from 'fs';
2-
import {basename, extname, join} from 'path';
1+
import {readdir, lstatSync, readFileSync} from 'fs';
2+
import {basename, extname, join, sep} from 'path';
33
import {registerPlugin} from '../pluginManagement/pluginRepository';
44
import {readFileAndCheckPrePublishSlug} from '../renderPlugins/content-render-utils/readFileAndCheckPrePublishSlug';
55
import {scullyConfig} from '../utils/config';
66
import {RouteTypeContentFolder} from '../utils/interfacesandenums';
7-
import {log, yellow} from '../utils/log';
7+
import {log, logWarn, yellow} from '../utils/log';
88
import {HandledRoute} from './addOptionalRoutesPlugin';
99

1010
export async function contentFolderPlugin(
@@ -22,32 +22,68 @@ export async function contentFolderPlugin(
2222
const baseRoute = angularRoute.split(':' + param)[0];
2323
const path = join(scullyConfig.homeFolder, paramConfig.folder);
2424
log(`Finding files in folder "${yellow(path)}"`);
25+
return await checkSourceIsDirectoryAndRun(path, baseRoute, conf);
26+
}
27+
28+
async function checkSourceIsDirectoryAndRun(path, baseRoute, conf) {
2529
const files = await new Promise<string[]>(resolve => readdir(path, (err, data) => resolve(data)));
2630
const handledRoutes: HandledRoute[] = [];
2731
for (const sourceFile of files) {
2832
const ext = extname(sourceFile);
2933
const templateFile = join(path, sourceFile);
30-
const base = basename(sourceFile, ext);
31-
const routify = frag => `${baseRoute}${slugify(frag)}`;
32-
const {meta, prePublished} = await readFileAndCheckPrePublishSlug(templateFile);
33-
const handledRoute: HandledRoute = {
34-
route: routify(meta.slug || base),
35-
type: conf.type,
36-
templateFile,
37-
data: {...meta, sourceFile},
38-
};
39-
handledRoutes.push(handledRoute);
40-
if (!prePublished && Array.isArray(meta.slugs)) {
41-
/** also add routes for all available slugs */
42-
meta.slugs
43-
.filter(slug => typeof slug === 'string')
44-
.map(routify)
45-
.forEach(route => handledRoutes.push({...handledRoute, route}));
34+
if (lstatSync(templateFile).isDirectory()) {
35+
handledRoutes.push(...(await checkSourceIsDirectoryAndRun(templateFile, baseRoute, conf)));
36+
} else {
37+
if (checkIfEmpty(templateFile)) {
38+
logWarn(`The file ${templateFile} is empty, scully will ignore.`);
39+
} else {
40+
handledRoutes.push(...(await addHandleRoutes(sourceFile, baseRoute, templateFile, conf, ext)));
41+
}
4642
}
4743
}
4844
return handledRoutes;
4945
}
5046

47+
function checkIfEmpty(templateFile: string) {
48+
try {
49+
const file = readFileSync(templateFile).toString();
50+
return file.length === 0 ? true : false;
51+
} catch (e) {
52+
return false;
53+
}
54+
}
55+
56+
async function addHandleRoutes(sourceFile, baseRoute, templateFile, conf, ext) {
57+
const handledRoutes = [];
58+
const base = basename(sourceFile, ext);
59+
// if a subfolder we need add a route for this folder
60+
let routify = frag => `${baseRoute}${slugify(frag)}`;
61+
// replace \ for / for windows
62+
const newTemplateFile = templateFile.split('\\').join('/');
63+
if (!newTemplateFile.endsWith(`${baseRoute}${sourceFile}`)) {
64+
const position = newTemplateFile.search(baseRoute);
65+
const br = newTemplateFile.substr(position).replace(sourceFile, '');
66+
routify = frag => `${br}${slugify(frag)}`;
67+
}
68+
// is a folder we need iterate the content in the folder
69+
const {meta, prePublished} = await readFileAndCheckPrePublishSlug(templateFile);
70+
const handledRoute: HandledRoute = {
71+
route: routify(meta.slug || base),
72+
type: conf.type,
73+
templateFile,
74+
data: {...meta, sourceFile},
75+
};
76+
handledRoutes.push(handledRoute);
77+
if (!prePublished && Array.isArray(meta.slugs)) {
78+
/** also add routes for all available slugs */
79+
meta.slugs
80+
.filter(slug => typeof slug === 'string')
81+
.map(routify)
82+
.forEach(route => handledRoutes.push({...handledRoute, route}));
83+
}
84+
return handledRoutes;
85+
}
86+
5187
export function slugify(frag: string): string {
5288
return encodeURIComponent(
5389
frag

scully/utils/defaultAction.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,11 @@ export const generateAll = async (localBaseFilter = baseFilter) => {
4444
performance.mark('startDiscovery');
4545
performanceIds.add('Discovery');
4646
log('Pull in data to create additional routes.');
47-
const handledRoutes = await addOptionalRoutes(
48-
unhandledRoutes.filter((r: string) => typeof r === 'string' && r.startsWith(localBaseFilter))
49-
);
47+
const handledRoutes = (
48+
await addOptionalRoutes(
49+
unhandledRoutes.filter((r: string) => typeof r === 'string' && r.startsWith(localBaseFilter))
50+
)
51+
).filter(r => !r.route.endsWith('*'));
5052
performance.mark('stopDiscovery');
5153
/** save routerinfo, so its available during rendering */
5254
if (localBaseFilter === '') {

0 commit comments

Comments
 (0)