Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 132


[*.md]
max_line_length = off
Expand Down
37 changes: 8 additions & 29 deletions libs/scully-schematics/src/add-plugin/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
import {
Rule,
Tree,
url,
applyTemplates,
move,
chain,
SchematicContext
} from '@angular-devkit/schematics';
import { Rule, Tree, url, applyTemplates, move, chain, SchematicContext } from '@angular-devkit/schematics';
import { strings, normalize } from '@angular-devkit/core';
import { Schema } from './schema';
import { applyWithOverwrite, getRoot, getScullyConfig } from '../utils/utils';
Expand All @@ -15,36 +7,23 @@ export default (options: Schema): Rule => {
return chain([addPlugin(options), registerPlugin(options)]);
};

const addPlugin = (options: Schema) => (
tree: Tree,
context: SchematicContext
) => {
const addPlugin = (options: Schema) => (tree: Tree, context: SchematicContext) => {
const sourceRoot = getRoot(tree, options.project);
const pathName = strings.dasherize(
`${sourceRoot}/scully-plugins/`
);
const pathName = strings.dasherize(`${sourceRoot}/scully-plugins/`);
return applyWithOverwrite(url(`../files/plugin/${options.pluginType}`), [
applyTemplates({
classify: strings.classify,
dasherize: strings.dasherize,
camelize: strings.camelize,
name: options.name
name: options.name,
}),
move(normalize(pathName))
move(normalize(pathName)),
]);
};

const registerPlugin = (options: Schema) => (
tree: Tree,
context: SchematicContext
) => {
const registerPlugin = (options: Schema) => (tree: Tree, context: SchematicContext) => {
const scullyConfigFile = getScullyConfig(tree, options.project);
let scullyConfig = tree
.read(`${getRoot(tree, options.project)}/${scullyConfigFile}`)
.toString();
let scullyConfig = tree.read(`${getRoot(tree, options.project)}/${scullyConfigFile}`).toString();
scullyConfig = `require('./scully-plugins/${strings.dasherize(options.name)}.plugin.js');\n${scullyConfig}`;
tree.overwrite(
`${getRoot(tree, options.project)}/${scullyConfigFile}`,
scullyConfig
);
tree.overwrite(`${getRoot(tree, options.project)}/${scullyConfigFile}`, scullyConfig);
};
21 changes: 4 additions & 17 deletions libs/scully/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
import {
getConfig,
getPluginConfig,
setConfig,
setPluginConfig,
findPlugin,
} from './lib/pluginManagement/pluginConfig';
import {
configValidator,
registerPlugin,
} from './lib/pluginManagement/pluginRepository';
import { getConfig, getPluginConfig, setConfig, setPluginConfig, findPlugin } from './lib/pluginManagement/pluginConfig';
import { configValidator, registerPlugin } from './lib/pluginManagement/pluginRepository';
import './lib/pluginManagement/systemPlugins';
import { ContentMetaData } from './lib/renderPlugins/content-render-utils/readFileAndCheckPrePublishSlug';
import { HandledRoute } from './lib/routerPlugins/addOptionalRoutesPlugin';
import {
scullyConfig,
updateScullyConfig,
loadConfig,
} from './lib/utils/config';
import { HandledRoute } from './lib/routerPlugins/handledRoute.interface';
import { scullyConfig, updateScullyConfig, loadConfig } from './lib/utils/config';
import { httpGetJson } from './lib/utils/httpGetJson';
import { RouteTypes, ScullyConfig } from './lib/utils/interfacesandenums';
import { replaceFirstRouteParamWithVal } from './lib/utils/replaceFirstRouteParamWithVal';
Expand Down
49 changes: 49 additions & 0 deletions libs/scully/src/lib/pluginManagement/Plugin.interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { HandledRoute } from '../routerPlugins/handledRoute.interface';
import { scullySystem } from './pluginRepository';
export type ScullySystem = `___Scully_system_plugins_Alter_at_own_RISK___`;

export type ErrorString = string;
export type ConfigValidator = (HandledRoute) => ErrorString[] | Promise<ErrorString[]>;
type RoutePlugin = (route: string, config: any) => Promise<HandledRoute[]>;
type RenderPlugin = (html: string, route: HandledRoute) => Promise<string>;
export type RouteProcess = (routes: HandledRoute[]) => Promise<HandledRoute[]>;
type RouteDiscoveryPlugin = (routes: HandledRoute[]) => Promise<void>;
type AllDonePlugin = (routes: HandledRoute[]) => Promise<void>;
export type FilePlugin = (html: string, route: HandledRoute) => Promise<string>;
export interface Plugins {
render: { [name: string]: RenderPlugin };
router: { [name: string]: RoutePlugin };
routeProcess: { [name: string]: RouteProcess };
routeDiscoveryDone: { [name: string]: RouteDiscoveryPlugin };
allDone: { [name: string]: AllDonePlugin };
fileHandler: { [fileExtension: string]: FilePlugin };
[scullySystem]: { [pluginSymbol: string]: (...args: unknown[]) => unknown };
}

export type PluginTypes = keyof Plugins;

export type PluginFunction = (...args: unknown[]) => unknown;
export interface RegisterOptions {
replaceExistingPlugin?: boolean;
}
// Function overloads for registerPlugin to provide better/cleaner autocomplete help.
//TODO add jsondoc signatures on every type.
export interface Register {
(
type: 'router',
name: string | symbol,
plugin: PluginFunction,
validator?: ConfigValidator,
registerOptions?: RegisterOptions
): void;
(
type: 'render' | 'allDone' | 'routeDiscoveryDone',
name: string | symbol,
plugin: PluginFunction,
dummy?,
registerOptions?: RegisterOptions
): void;
(type: ScullySystem, name: symbol, plugin: PluginFunction, dummy?, registerOptions?: RegisterOptions): void;
(type: 'routeProcess', name: string | symbol, plugin: PluginFunction, priority?: number, registerOptions?: RegisterOptions): void;
(type: 'fileHandler', name: string, plugin: PluginFunction, additionalTypes?: string[], registerOptions?: RegisterOptions): void;
}
10 changes: 3 additions & 7 deletions libs/scully/src/lib/pluginManagement/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
export {
registerPlugin,
configValidator,
scullySystem,
} from './pluginRepository';

export { findPlugin } from './pluginConfig';
export * from './pluginRepository';
export * from './pluginConfig';
export * from './Plugin.interfaces';
68 changes: 23 additions & 45 deletions libs/scully/src/lib/pluginManagement/pluginConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,25 @@
// tslint:disable: no-shadowed-variable
import { Serializable } from 'puppeteer';
import { logError, yellow } from '../utils/log';
import {
accessPluginDirectly,
configData,
plugins,
PluginTypes,
pluginTypes,
} from './pluginRepository';
import { PluginFunction, PluginTypes } from './Plugin.interfaces';
import { accessPluginDirectly, configData, plugins, pluginTypes } from './pluginRepository';

export const backupData = configData + 'BackupData__';
export const routeConfigData = configData + 'Route_Config_Data__';
export const resetConfig = configData + 'resetData__';

export const setPluginConfig = (
name: string | symbol,
interface SetPluginConfig {
(name: string | symbol, configData: Serializable): void;
(name: string | symbol, type: PluginTypes, configData: Serializable): void;
}
export const setPluginConfig: SetPluginConfig = (
name: string,
typeOrConfig: PluginTypes | Serializable,
config?: Serializable
): void => {
let type: string;
// tslint:disable-next-line: no-angle-bracket-type-assertion
if (
(typeof typeOrConfig === 'string' || typeof typeOrConfig === 'symbol') &&
pluginTypes.includes(<any>typeOrConfig)
) {
if ((typeof typeOrConfig === 'string' || typeof typeOrConfig === 'symbol') && pluginTypes.includes(<any>typeOrConfig)) {
type = typeOrConfig;
} else {
config = (typeOrConfig as unknown) as Serializable;
Expand All @@ -48,37 +44,22 @@ export function fetchPlugins(name: string | symbol, type?: string): Function[] {
return result;
}

export function findPlugin(
name: string | symbol,
type?: string,
errorOnNotfound = true
): Function {
export function findPlugin(name: string | symbol, type?: string, errorOnNotfound = true): Function {
const found = fetchPlugins(name, type);
const displayName = typeof name === 'string' ? name : name.description;
switch (found.length) {
case 0:
if (errorOnNotfound) {
logError(
`Plugin "${yellow(displayName)}" of type "${yellow(
type
)}" is not found, can not store config`
);
logError(`Plugin "${yellow(displayName)}" of type "${yellow(type)}" is not found, can not store config`);
process.exit(15);
}
return undefined;
break;
case 1:
const pl = found[0] as Function;
return pl.hasOwnProperty(accessPluginDirectly)
? (pl[accessPluginDirectly] as Function)
: pl;
return found[0] as PluginFunction;
default:
if (errorOnNotfound) {
logError(
`Plugin "${yellow(
displayName
)}" has multiple types, please specify type to be able to store config`
);
logError(`Plugin "${yellow(displayName)}" has multiple types, please specify type to be able to store config`);
process.exit(15);
}
return undefined;
Expand All @@ -89,11 +70,15 @@ export function hasPlugin(name: string | symbol, type?: string): boolean {
return fetchPlugins(name, type).length === 1;
}

export const getConfig = <T>(plugin: any): T => (plugin[configData] || {}) as T;
export const getConfig = <T>(plugin: any): T => {
const target = plugin.hasOwnProperty(accessPluginDirectly) ? plugin[accessPluginDirectly] : plugin;
return target[configData] || ({} as T);
};

export const setConfig = (plugin: any, config: Serializable): void => {
plugin[configData] = Object.assign({}, plugin[configData] || {}, config);
plugin[backupData] = { ...plugin[configData] };
const target = plugin.hasOwnProperty(accessPluginDirectly) ? plugin[accessPluginDirectly] : plugin;
target[configData] = Object.assign({}, target[configData] || {}, config);
target[backupData] = { ...target[configData] };
};

/**
Expand All @@ -106,24 +91,17 @@ export const routePluginConfig = (
name: string,
typeOrConfig: PluginTypes | Serializable,
config?: Serializable
) => {
): void => {
let type: string;
// tslint:disable-next-line: no-angle-bracket-type-assertion
if (
(typeof typeOrConfig === 'string' || typeof typeOrConfig === 'symbol') &&
pluginTypes.includes(<any>typeOrConfig)
) {
if ((typeof typeOrConfig === 'string' || typeof typeOrConfig === 'symbol') && pluginTypes.includes(<any>typeOrConfig)) {
type = typeOrConfig;
} else {
config = (typeOrConfig as unknown) as Serializable;
}
const plugin = findPlugin(name, type);
plugin[routeConfigData] = plugin[routeConfigData] || {};
plugin[routeConfigData][route] = Object.assign(
{},
plugin[configData] || {},
config
);
plugin[routeConfigData][route] = Object.assign({}, plugin[configData] || {}, config);
plugin[resetConfig] = () => {
plugin[configData] = plugin[backupData];
};
Expand Down
Loading