Skip to content

Commit

Permalink
feat(routeinfo): pulled complete roueInfo insto route-discovery phase (
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderElias authored Jan 30, 2020
1 parent be48c03 commit b587309
Show file tree
Hide file tree
Showing 16 changed files with 134 additions and 79 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"cSpell.words": ["Scully", "Scullyio", "ngcontent"],
"cSpell.words": ["Scully", "Scullyio", "ngcontent", "routify", "slugify"],
"peacock.affectActivityBar": true,
"peacock.affectTitleBar": true,
"peacock.affectStatusBar": true,
Expand Down
2 changes: 2 additions & 0 deletions blog/page-1.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ title: My first page
author: Sander Elias
publish date: 2019-11-26
slug: look at_my-urls Cool
slugs:
- 'page-1'
description: This is the first demo page in this sample.
---

Expand Down
1 change: 1 addition & 0 deletions blog/page-2.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ published: false
description: 'This is the second demo page in this sample.'
slugs:
- ___UNPUBLISHED___k5nhcflm_SJwD4Z0QDrIHg1PGHo2mrfLZE8sfUsPy
- page-2
---

# Page 2
Expand Down
3 changes: 3 additions & 0 deletions blog/page-3.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ title: My third page
author: Sander Elias
publish date: 2019-11-28
description: At this point, I should write something different in here.
slug: My third page,
slugs:
- page-3
---

# Page 3
Expand Down
11 changes: 3 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
"@angular/platform-browser-dynamic": "~9.0.0-rc.7",
"@angular/platform-server": "~9.0.0-rc.7",
"@angular/router": "~9.0.0-rc.7",
"@types/minimatch": "^3.0.3",
"jsdom": "^15.2.1",
"minimatch": "^3.0.4",
"rxjs": "^6.5.3",
"semver": "^6.3.0",
"tslib": "^1.10.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface ScullyRoute {
slugs?: string[];
published?: boolean;
slug?: string;
sourceFile?: string;
[prop: string]: any;
}

Expand All @@ -27,6 +28,7 @@ export class ScullyRoutesService {
}),
/** filter out all non-array results */
filter(routes => Array.isArray(routes)),
map(this.cleanDups),
shareReplay({refCount: false, bufferSize: 1})
);
available$ = this.allRoutes$.pipe(
Expand Down Expand Up @@ -66,6 +68,12 @@ export class ScullyRoutesService {
);
}

cleanDups(routes: ScullyRoute[]) {
const m = new Map<string, ScullyRoute>();
routes.forEach(r => m.set(r.sourceFile || r.route, r));
return [...m.values()];
}

reload(): void {
this.refresh.next();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import {Observable} from 'rxjs';
/**
* Returns an observable that fires a mutation when the domMutationObserves does that.
* if flattens the mutations to make handling easier, so you only get 1 mutationRecord at a time.
* @param elm the elm to obse with a mutationObserver
* @param config the config for the mutationobserver
* @param elm the elm to observe with a mutationObserver
* @param config the config for the mutation-observer
*/
export function fromMutationObserver(
elm: HTMLElement,
Expand Down
2 changes: 2 additions & 0 deletions scully/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {RouteTypes, ScullyConfig} from './utils/interfacesandenums';
import {replaceFirstRouteParamWithVal} from './utils/replaceFirstRouteParamWithVal';
import {routeSplit} from './utils/routeSplit';
import {startScully} from './utils/startup';
import {ContentMetaData} from './renderPlugins/content-render-utils/readFileAndCheckPrePublishSlug';

export {
startScully,
Expand All @@ -20,4 +21,5 @@ export {
configValidator,
httpGetJson,
scullyConfig,
ContentMetaData,
};
2 changes: 1 addition & 1 deletion scully/pluginManagement/pluginRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const registerPlugin = (
type: PluginTypes,
name: string,
plugin: any,
validator = async () => [],
validator = async (config?: any) => [],
{replaceExistingPlugin = false} = {}
) => {
if (!['router', 'render', 'fileHandler'].includes(type)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,52 +1,42 @@
import {readFileSync, writeFileSync} from 'fs';
import {stringify} from 'yamljs';
import {HandledRoute} from '../../routerPlugins/addOptionalRoutesPlugin';
import {randomString} from '../../utils/randomString';
const fm = require('front-matter');

export async function readFileAndCheckPrePublishSlug(file, route: HandledRoute) {
export interface ContentMetaData {
author?: string;
published?: boolean;
slug?: string;
'publish date'?: Date;
slugs?: string[];
title?: string;
[key: string]: any;
}

export async function readFileAndCheckPrePublishSlug(file) {
const prependString = '___UNPUBLISHED___';
const createSlug = () => `${prependString}${Date.now().toString(36)}_${randomString(32)}`;
const originalFile = readFileSync(file, 'utf-8');
const {attributes: meta, body: fileContent} = fm(originalFile);
const {attributes: meta, body: fileContent}: {attributes: ContentMetaData; body: string} = fm(originalFile);
let prePublished = false;
if (meta.hasOwnProperty('published') && meta.published === false) {
/** this post needs an pre-publish slug */
const slugs = Array.isArray(meta.slugs) ? meta.slugs : [];
let slug = slugs.find((sl: string) => sl.startsWith(prependString));
if (!slug) {
let unPublishedSlug = slugs.find((sl: string) => sl.startsWith(prependString));
if (!unPublishedSlug) {
/** there is no prepub slug so create one and update the file */
slug = createSlug();
meta.slugs = slugs.concat(slug);
unPublishedSlug = createSlug();
meta.slugs = slugs.concat(unPublishedSlug);
/** string literal, don't format "correctly" or things will break ;) */
const newFile = `---
${stringify(meta)}
---
${fileContent}`;
writeFileSync(file, newFile);
}
/** replace the route with the prepub slug */
const updatedRoute = replaceRouteWithSlug(route.route, slug);
route.route = updatedRoute;
} else if (typeof meta.slug === 'string') {
route.route = replaceRouteWithSlug(
// TODO better handling of url/filename escaping
route.route,
encodeURIComponent(
meta.slug
.trim()
.split('/')
.join('_')
.split(' ')
.join('_')
.split('?')
.join('_')
)
);
/** overwrite slug from file with prepub only in memory. we don't want a file with the original slug name now. */
meta.slug = unPublishedSlug;
prePublished = true;
}
return {meta, fileContent};
}

function replaceRouteWithSlug(route: string, slug: string) {
const lastPart = route.split('/').pop();
return route.replace(lastPart, slug);
return {meta, fileContent, prePublished};
}
3 changes: 1 addition & 2 deletions scully/renderPlugins/contentRenderPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ export async function contentRenderPlugin(html: string, route: HandledRoute) {
const file = route.templateFile;
try {
const extension = file.split('.').pop();
const {meta, fileContent} = await readFileAndCheckPrePublishSlug(file, route);
const {fileContent} = await readFileAndCheckPrePublishSlug(file);
// TODO: create additional "routes" for every slug
route.data = {...route.data, ...meta};
const attr = getIdAttrName(
html
.split('<scully-content')[1]
Expand Down
56 changes: 42 additions & 14 deletions scully/routerPlugins/contentFolderPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,70 @@
import {readdir} from 'fs';
import {basename, extname, join} from 'path';
import {configValidator, registerPlugin} from '../pluginManagement/pluginRepository';
import {registerPlugin} from '../pluginManagement/pluginRepository';
import {readFileAndCheckPrePublishSlug} from '../renderPlugins/content-render-utils/readFileAndCheckPrePublishSlug';
import {scullyConfig} from '../utils/config';
import {RouteTypeContentFolder} from '../utils/interfacesandenums';
import {log, yellow} from '../utils/log';
import {HandledRoute} from './addOptionalRoutesPlugin';

export async function contentFolderPlugin(
route: string,
angularRoute: string,
conf: RouteTypeContentFolder
): Promise<HandledRoute[]> {
const parts = route.split('/');
const parts = angularRoute.split('/');
/** for now, just handle the First parameter. Not sure if/how we can handle multiple ones. */
const param = parts.filter(p => p.startsWith(':')).map(id => id.slice(1))[0];
const paramConfig = conf[param];
if (!paramConfig) {
console.error(`missing config for parameters (${param}) in route: ${route}. Skipping`);
console.error(`missing config for parameters (${param}) in route: ${angularRoute}. Skipping`);
return [];
}
const baseRoute = route.split(':' + param)[0];
const baseRoute = angularRoute.split(':' + param)[0];
const path = join(scullyConfig.homeFolder, paramConfig.folder);
log(`Finding files in folder "${yellow(path)}"`);
const files = await new Promise<string[]>(resolve => readdir(path, (err, data) => resolve(data)));
return files.map<HandledRoute>(file => {
const ext = extname(file);
const base = basename(file, ext);
return {
route: `${baseRoute}${base}`,
const handledRoutes: HandledRoute[] = [];
for (const sourceFile of files) {
const ext = extname(sourceFile);
const templateFile = join(path, sourceFile);
const base = basename(sourceFile, ext);
const routify = frag => `${baseRoute}${slugify(frag)}`;
const {meta, prePublished} = await readFileAndCheckPrePublishSlug(templateFile);
const handledRoute: HandledRoute = {
route: routify(meta.slug || base),
type: conf.type,
templateFile: join(path, file),
templateFile,
data: {...meta, sourceFile},
};
});
handledRoutes.push(handledRoute);
if (!prePublished && Array.isArray(meta.slugs)) {
/** also add routes for all available slugs */
meta.slugs
.filter(slug => typeof slug === 'string')
.map(routify)
.forEach(route => handledRoutes.push({...handledRoute, route}));
}
}
return handledRoutes;
}

export function slugify(frag: string): string {
return encodeURIComponent(
frag
.trim()
.split('/')
.join('_')
.split(' ')
.join('_')
.split('?')
.join('_')
);
}

// TODO actual validation of the config
contentFolderPlugin[configValidator] = async conf => {
const configValidator = async conf => {
// return [yellow('all seems ok')];
return [];
};

registerPlugin('router', 'contentFolder', contentFolderPlugin);
registerPlugin('router', 'contentFolder', contentFolderPlugin, configValidator);
8 changes: 7 additions & 1 deletion scully/scully.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ const {argv: options} = yargs.option('port', {
description: 'The port to run on',
});

const {removeStaticDist} = yargs
.boolean('RSD')
.default('RSD', false)
.alias('RSD', 'removeStaticDist')
.describe('RSD', 'Use this flag to remove the Scully outfolder before starting').argv;

if (process.argv.includes('version')) {
const {version} = JSON.parse(readFileSync(join(__dirname, './package.json')).toString());
console.log('version:', version);
Expand All @@ -53,7 +59,7 @@ if (process.argv.includes('version')) {
} else {
const folder = join(scullyConfig.homeFolder, scullyConfig.distFolder);
/** copy in current build artifacts */
await moveDistAngular(folder, scullyConfig.outDir, {removeStaticDist: true, reset: false});
await moveDistAngular(folder, scullyConfig.outDir, {removeStaticDist, reset: false});

/** server ports already in use? */
const isTaken = await isPortTaken(scullyConfig.staticport);
Expand Down
38 changes: 23 additions & 15 deletions scully/systemPlugins/storeRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,31 @@ import {log, logError, yellow} from '../utils/log';
const routesFileName = '/assets/scully-routes.json';

export async function storeRoutes(routes: HandledRoute[]) {
// TODO: do something with meta-data.
let appFile;
let staticFile;
const files = [
/** in the angular source folder */
join(scullyConfig.homeFolder, scullyConfig.sourceRoot, routesFileName),
/** in the scully outfolder */
join(scullyConfig.outDir, routesFileName),
/** in the angular dist folder */
join(scullyConfig.homeFolder, scullyConfig.distFolder, routesFileName),
];
try {
const jsonResult = JSON.stringify(routes.map(r => ({route: r.route || '/', ...r.data})));
appFile = join(scullyConfig.sourceRoot, `${routesFileName}`);
createFolderFor(appFile);
writeFileSync(appFile, jsonResult);
staticFile = join(scullyConfig.outDir, routesFileName);
createFolderFor(staticFile);
writeFileSync(staticFile, jsonResult);
log(`Route list created in files:
${yellow(appFile)}
${yellow(staticFile)}`);
const write = file => {
createFolderFor(file);
writeFileSync(file, jsonResult);
};
files.forEach(write);
log(`Route list created in files:${files.map(
f => `
"${yellow(f)}"`
)}
`);
} catch {
logError(`Could not write routes to files:
${yellow(appFile)}
${yellow(staticFile)}`);
logError(`Could not write routes to files:${files.map(
f => `
"${yellow(f)}"`
)}
`);
}
}
Loading

0 comments on commit b587309

Please sign in to comment.