From 0d18cc17eca2a26f9d321d5630795e60b25eb57b Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 14 Sep 2020 10:14:12 -0400 Subject: [PATCH 01/75] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20Remove=20suppo?= =?UTF-8?q?rt=20for=20hooks=20in=20'route.js'=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/Elder.ts | 17 +---------------- src/utils/validations.ts | 5 ----- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index c627113d..4f2f0c1d 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "devDependencies": { "@types/fs-extra": "^9.0.1", "@types/jest": "^26.0.12", - "@types/node": "^14.6.2", + "@types/node": "^14.10.1", "@typescript-eslint/eslint-plugin": "^4.0.1", "@typescript-eslint/parser": "^4.0.1", "cz-conventional-changelog": "^3.3.0", diff --git a/src/Elder.ts b/src/Elder.ts index 66b02ff6..64a0c112 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -253,7 +253,6 @@ class Elder { // add meta to routes and collect hooks from routes const userRoutesJsFile = routes(this.settings); - const routeHooks: Array = []; const userRoutes = Object.keys(userRoutesJsFile); userRoutes.forEach((routeName) => { @@ -264,20 +263,6 @@ class Elder { addedBy: 'routejs', }, }; - const processedRoute = userRoutesJsFile[routeName]; - - if (processedRoute.hooks && Array.isArray(processedRoute.hooks)) { - processedRoute.hooks.forEach((hook) => { - const hookWithMeta: HookOptions = { - ...hook, - $$meta: { - type: 'route', - addedBy: routeName, - }, - }; - routeHooks.push(hookWithMeta); - }); - } }); // plugins should never overwrite user routes. @@ -353,7 +338,7 @@ class Elder { const allSupportedHooks = hookInterface; - this.hooks = [...elderJsHooks, ...pluginHooks, ...routeHooks, ...hooksJs] + this.hooks = [...elderJsHooks, ...pluginHooks, ...hooksJs] .map((hook) => validateHook(hook)) .filter((Boolean as any) as ExcludesFalse); diff --git a/src/utils/validations.ts b/src/utils/validations.ts index 7024b357..a57fae61 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -143,11 +143,6 @@ const routeSchema = yup.object({ .label( 'Sync function that turns request objects from the all() function into permalinks which are relative to the site root', ), - hooks: yup - .array() - .notRequired() - .default([]) - .label('An array of hooks. NOTE/TODO: These run on all routes, not just the one defined on.'), }); const pluginSchema = yup.object({ From 22b6b4c47d9d1ce58f5de623ebd115413fc31970 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 14 Sep 2020 10:18:26 -0400 Subject: [PATCH 02/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Add=20'data'=20val?= =?UTF-8?q?idation=20to=20the=20route=20validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/validations.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/utils/validations.ts b/src/utils/validations.ts index a57fae61..0a0f9161 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -143,6 +143,12 @@ const routeSchema = yup.object({ .label( 'Sync function that turns request objects from the all() function into permalinks which are relative to the site root', ), + data: yup + .mixed() + .required() + .label( + `Async/sync function that returns a JS object. Can also be a plain JS object. Important: If this is a function it is passed a '{data}' parameter. This parameter should be mutated and returned to pick up any data populated via hooks or plugins.`, + ), }); const pluginSchema = yup.object({ From 50a0bb65f5ac8ec59b9bd3299fec4cea26b063f4 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 14 Sep 2020 10:21:16 -0400 Subject: [PATCH 03/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Useful=20error=20w?= =?UTF-8?q?hen=20request.route=20is=20not=20defined?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Elder.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Elder.ts b/src/Elder.ts index 64a0c112..d7824b7e 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -415,12 +415,21 @@ class Elder { await this.runHook('allRequests', this); - // TODO: We should validate that all requests have a request.route = ''; - // sometimes the request object returned by the allRequests hook may not have it set. - await asyncForEach(this.allRequests, async (request) => { if (!this.routes[request.route] || !this.routes[request.route].permalink) { - console.error(`request missing permalink, please create an issue. ${request}`); + if (!request.route) { + console.error( + `Request is missing a 'route' key. This usually happens when request objects have been added to the allRequests array via a hook or plugin. ${JSON.stringify( + request, + )}`, + ); + } else { + console.error( + `Request missing permalink but has request.route defined. This shouldn't be an Elder.js issue but if you believe it could be please create an issue. ${JSON.stringify( + request, + )}`, + ); + } } if (context === 'server') { request.type = 'server'; From a1315e9a64de6098723d59089969eb1dfa275401 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 14 Sep 2020 10:24:10 -0400 Subject: [PATCH 04/75] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20remove=20link(?= =?UTF-8?q?)=20from=20templates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/svelteComponent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/svelteComponent.ts b/src/utils/svelteComponent.ts index c3dab666..02e6ae19 100644 --- a/src/utils/svelteComponent.ts +++ b/src/utils/svelteComponent.ts @@ -50,7 +50,7 @@ const svelteComponent = (componentName) => ({ page, props, hydrateOptions }: Com const { render, clientSrc } = componentCache[cleanComponentName]; try { - const { css, html: htmlOutput, head } = render({ ...props, link: page.helpers.permalinks }); + const { css, html: htmlOutput, head } = render(props); if (css && css.code && css.code.length > 0 && page.cssStack) { page.cssStack.push({ source: componentName, priority: 50, string: css.code }); From 9a1aab90636f2a5f513c13bb40d97d7fbc0d7911 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 14 Sep 2020 11:39:10 -0400 Subject: [PATCH 05/75] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20remove=20custo?= =?UTF-8?q?mProps=20from=20Elder.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Elder.ts | 7 +- .../__snapshots__/Elder.spec.ts.snap | 84 ++----------------- src/hookInterface/hookEntityDefinitions.ts | 1 - src/hookInterface/hookInterface.ts | 22 ++--- src/hookInterface/types.ts | 1 - src/utils/Page.ts | 19 +---- src/utils/__tests__/Page.spec.ts | 3 +- .../__tests__/__snapshots__/Page.spec.ts.snap | 2 - .../__snapshots__/validations.spec.ts.snap | 19 ++--- src/utils/__tests__/validations.spec.ts | 1 + src/utils/prepareRunHook.ts | 14 +--- src/utils/prepareServer.ts | 2 - src/utils/validations.ts | 3 +- src/workerBuild.ts | 2 - 14 files changed, 26 insertions(+), 154 deletions(-) diff --git a/src/Elder.ts b/src/Elder.ts index d7824b7e..df170fcb 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -56,8 +56,6 @@ class Elder { hookInterface: any; - customProps: any; - query: QueryOptions; allRequests: Array; @@ -346,11 +344,8 @@ class Elder { this.hooks = this.hooks.filter((h) => !this.settings.hooks.disable.includes(h.name)); } - // TODO: plugins should be able to register their own hooks? - this.data = {}; this.hookInterface = allSupportedHooks; - this.customProps = {}; this.query = {}; this.allRequests = []; @@ -375,7 +370,7 @@ class Elder { }); this.runHook('customizeHooks', this).then(async () => { - // we now have customProps and a new hookInterface. + // we now have any customizations to the hookInterface. this.runHook = prepareRunHook({ hooks: this.hooks, allSupportedHooks: this.hookInterface, diff --git a/src/__tests__/__snapshots__/Elder.spec.ts.snap b/src/__tests__/__snapshots__/Elder.spec.ts.snap index 9055187e..b55db317 100644 --- a/src/__tests__/__snapshots__/Elder.spec.ts.snap +++ b/src/__tests__/__snapshots__/Elder.spec.ts.snap @@ -4,7 +4,6 @@ exports[`#Elder hookSrcFile not found 1`] = ` Elder { "allRequests": Array [], "bootstrapComplete": Promise {}, - "customProps": Object {}, "data": Object {}, "errors": Array [], "helpers": Object { @@ -18,22 +17,20 @@ Elder { "hookInterface": Array [ Object { "advanced": true, - "context": "Run before collecting all hooks.", + "context": "Used to modify what hooks can mutate which properties all hooks.", "experimental": true, "hook": "customizeHooks", "location": "Elder.ts", "mutable": Array [ "hookInterface", - "customProps", "errors", ], "props": Array [ "hookInterface", - "customProps", "errors", ], "use": "

This hook receives the hookInterface.ts file which defines all hook interactions. You can customize all 'props' and 'mutable' of - all hooks by using this hook. This is a power user hook and would often be used in conjunction with customProps.

", + all hooks by using this hook. This is a power user hook and unless you know Elder.js internals don't mess with it.

", }, Object { "advanced": false, @@ -64,7 +61,7 @@ Elder { ", }, Object { - "advanced": true, + "advanced": false, "context": "allRequests which represents all of the request objects have been collected from route and plugins. This makes the 'allRequests' array mutable.", "experimental": false, "hook": "allRequests", @@ -134,29 +131,6 @@ Elder {
  • Anything you'd use an Express 'req' or 'next' for you can do and customize other parts of the Elder.js on this hook.
  • ", }, - Object { - "advanced": true, - "context": "This hook is run just after a Page.ts object is created for a request. Page.ts objects are the main object used during page generation.", - "experimental": true, - "hook": "modifyCustomProps", - "location": "Page.ts", - "mutable": Array [ - "customProps", - "request", - "errors", - "helpers", - "query", - ], - "props": Array [ - "customProps", - "request", - "errors", - "helpers", - "query", - "settings", - ], - "use": "

    This hook is often used in conjunction with the 'customizeHooks' hook to modify 'customProps' based on the request. This is very much a power user hook.

    ", - }, Object { "advanced": false, "context": "This is executed at the beginning the request object being processed.", @@ -499,16 +473,6 @@ Elder { "priority": 50, "run": [Function], }, - Object { - "$$meta": Object { - "addedBy": "route-a", - "type": "route", - }, - "description": "test", - "hook": "routeHook", - "name": "route hook", - "run": [MockFunction], - }, Object { "$$meta": Object { "addedBy": "hooks.js", @@ -608,7 +572,6 @@ Elder { }, ], "bootstrapComplete": Promise {}, - "customProps": Object {}, "data": Object {}, "errors": Array [], "helpers": Object { @@ -622,22 +585,20 @@ Elder { "hookInterface": Array [ Object { "advanced": true, - "context": "Run before collecting all hooks.", + "context": "Used to modify what hooks can mutate which properties all hooks.", "experimental": true, "hook": "customizeHooks", "location": "Elder.ts", "mutable": Array [ "hookInterface", - "customProps", "errors", ], "props": Array [ "hookInterface", - "customProps", "errors", ], "use": "

    This hook receives the hookInterface.ts file which defines all hook interactions. You can customize all 'props' and 'mutable' of - all hooks by using this hook. This is a power user hook and would often be used in conjunction with customProps.

    ", + all hooks by using this hook. This is a power user hook and unless you know Elder.js internals don't mess with it.

    ", }, Object { "advanced": false, @@ -668,7 +629,7 @@ Elder { ", }, Object { - "advanced": true, + "advanced": false, "context": "allRequests which represents all of the request objects have been collected from route and plugins. This makes the 'allRequests' array mutable.", "experimental": false, "hook": "allRequests", @@ -738,29 +699,6 @@ Elder {
  • Anything you'd use an Express 'req' or 'next' for you can do and customize other parts of the Elder.js on this hook.
  • ", }, - Object { - "advanced": true, - "context": "This hook is run just after a Page.ts object is created for a request. Page.ts objects are the main object used during page generation.", - "experimental": true, - "hook": "modifyCustomProps", - "location": "Page.ts", - "mutable": Array [ - "customProps", - "request", - "errors", - "helpers", - "query", - ], - "props": Array [ - "customProps", - "request", - "errors", - "helpers", - "query", - "settings", - ], - "use": "

    This hook is often used in conjunction with the 'customizeHooks' hook to modify 'customProps' based on the request. This is very much a power user hook.

    ", - }, Object { "advanced": false, "context": "This is executed at the beginning the request object being processed.", @@ -1133,16 +1071,6 @@ Elder { "name": "test hook 3", "run": [Function], }, - Object { - "$$meta": Object { - "addedBy": "route-a", - "type": "route", - }, - "description": "test", - "hook": "routeHook", - "name": "route hook", - "run": [MockFunction], - }, Object { "$$meta": Object { "addedBy": "hooks.js", diff --git a/src/hookInterface/hookEntityDefinitions.ts b/src/hookInterface/hookEntityDefinitions.ts index 5931d794..4ab8398d 100644 --- a/src/hookInterface/hookEntityDefinitions.ts +++ b/src/hookInterface/hookEntityDefinitions.ts @@ -3,7 +3,6 @@ const hookEntityDefinitions = { allRequests: `Every request object collected from all routes during bootstrap. It is important to note that 'allRequests' will be different at the 'request' hook during a build because the requests are split between different processes during build time using the allRequests object.`, hookInterface: 'The hook interface is what defines the "contract" for each hook. It includes what properties the hook has access to and which of those properties can be mutated.', - customProps: 'An object that represents any custom props added during the "customizeHook" hook', errors: 'An array of errors collected during the build process.', helpers: 'An object of helpers loaded from `./src/helpers/index.js` in addition to the Elder.js provided helper functions.', diff --git a/src/hookInterface/hookInterface.ts b/src/hookInterface/hookInterface.ts index bb20cc75..111fbd20 100644 --- a/src/hookInterface/hookInterface.ts +++ b/src/hookInterface/hookInterface.ts @@ -6,11 +6,11 @@ import type { HookInterface } from './types'; export const hookInterface: Array = [ { hook: 'customizeHooks', - props: ['hookInterface', 'customProps', 'errors'], - mutable: ['hookInterface', 'customProps', 'errors'], - context: 'Run before collecting all hooks.', + props: ['hookInterface', 'errors'], + mutable: ['hookInterface', 'errors'], + context: 'Used to modify what hooks can mutate which properties all hooks.', use: `

    This hook receives the hookInterface.ts file which defines all hook interactions. You can customize all 'props' and 'mutable' of - all hooks by using this hook. This is a power user hook and would often be used in conjunction with customProps.

    `, + all hooks by using this hook. This is a power user hook and unless you know Elder.js internals don't mess with it.

    `, location: 'Elder.ts', experimental: true, advanced: true, @@ -44,7 +44,7 @@ export const hookInterface: Array = [

    NOTE: If you are modifying 'allRequests' you must set 'request.route' key for each request.

    `, location: 'Elder.ts', experimental: false, - advanced: true, + advanced: false, }, // above this is Elder.js @@ -94,18 +94,6 @@ export const hookInterface: Array = [ advanced: true, }, - { - hook: 'modifyCustomProps', - props: ['customProps', 'request', 'errors', 'helpers', 'query', 'settings'], - mutable: ['customProps', 'request', 'errors', 'helpers', 'query'], - context: - 'This hook is run just after a Page.ts object is created for a request. Page.ts objects are the main object used during page generation.', - use: `

    This hook is often used in conjunction with the 'customizeHooks' hook to modify 'customProps' based on the request. This is very much a power user hook.

    `, - location: 'Page.ts', - experimental: true, - advanced: true, - }, - { hook: 'request', props: ['helpers', 'data', 'settings', 'request', 'allRequests', 'query', 'errors', 'routes', 'route'], diff --git a/src/hookInterface/types.ts b/src/hookInterface/types.ts index 43988a0d..b55a285e 100644 --- a/src/hookInterface/types.ts +++ b/src/hookInterface/types.ts @@ -3,7 +3,6 @@ export type Hook = | 'bootstrap' | 'allRequests' | 'middleware' - | 'modifyCustomProps' | 'request' | 'data' | 'stacks' diff --git a/src/utils/Page.ts b/src/utils/Page.ts index dd3cdc4f..9bd35603 100644 --- a/src/utils/Page.ts +++ b/src/utils/Page.ts @@ -142,8 +142,6 @@ class Page { perf: any; - customProps: any; - htmlString: string; headStack: Stack; @@ -158,19 +156,7 @@ class Page { footerStack: Stack; - constructor({ - request, - settings, - query, - helpers, - data, - route, - runHook, - allRequests, - routes, - errors, - customProps = {}, - }) { + constructor({ request, settings, query, helpers, data, route, runHook, allRequests, routes, errors }) { this.uid = getUniqueId(); perf(this); this.perf.start('page'); @@ -185,7 +171,6 @@ class Page { this.query = query; this.errors = [...errors]; this.routes = routes; - this.customProps = customProps; this.htmlString = ''; this.headStack = []; @@ -197,8 +182,6 @@ class Page { this.processStack = prepareProcessStack(this); - this.runHook('modifyCustomProps', this); - this.perf.end('constructor'); this.perf.start('initToBuildGap'); diff --git a/src/utils/__tests__/Page.spec.ts b/src/utils/__tests__/Page.spec.ts index be9a71e5..e5703223 100644 --- a/src/utils/__tests__/Page.spec.ts +++ b/src/utils/__tests__/Page.spec.ts @@ -221,9 +221,8 @@ describe('#Page', () => { it('initialize and build', async () => { const page = new Page(pageInput); expect(page).toMatchSnapshot(); - expect(hooks).toEqual(['modifyCustomProps']); await page.build(); - expect(hooks).toEqual(['modifyCustomProps', 'request', 'data', 'stacks', 'head', 'html', 'requestComplete']); + expect(hooks).toEqual(['request', 'data', 'stacks', 'head', 'html', 'requestComplete']); expect(page).toMatchSnapshot(); const htmlString = await page.html(); expect(htmlString.trim()).toEqual(expectedOutput); diff --git a/src/utils/__tests__/__snapshots__/Page.spec.ts.snap b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap index 269060ba..8c50c657 100644 --- a/src/utils/__tests__/__snapshots__/Page.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap @@ -29,7 +29,6 @@ Page { "beforeHydrateStack": Array [], "cssStack": Array [], "customJsStack": Array [], - "customProps": Object {}, "data": Object {}, "errors": Array [], "footerStack": Array [], @@ -244,7 +243,6 @@ Page { "customJsStack": Array [ "customJsStack", ], - "customProps": Object {}, "data": Object { "worldPopulation": 7805564950, }, diff --git a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap index 2d62d34b..b00d32b0 100644 --- a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap @@ -1368,7 +1368,7 @@ ObjectSchema { "_exclusive": Object {}, "_mutate": undefined, "_nodes": Array [ - "hooks", + "data", "permalink", "all", "template", @@ -1414,34 +1414,31 @@ ObjectSchema { "transforms": Array [], "type": "mixed", }, - "hooks": ArraySchema { + "data": SchemaType { "_blacklist": RefSet { "list": Set {}, "refs": Map {}, }, "_conditions": Array [], - "_default": Array [], + "_default": Object {}, "_deps": Array [], "_exclusive": Object {}, - "_label": "An array of hooks. NOTE/TODO: These run on all routes, not just the one defined on.", + "_label": "Async/sync function that returns a JS object. Can also be a plain JS object. Important: If this is a function it is passed a '{data}' parameter. This parameter should be mutated and returned to pick up any data populated via hooks or plugins.", "_mutate": undefined, + "_nullable": true, "_options": Object { "abortEarly": true, "recursive": true, }, - "_subType": undefined, - "_type": "array", + "_type": "mixed", "_typeError": [Function], "_whitelist": RefSet { "list": Set {}, "refs": Map {}, }, - "innerType": undefined, "tests": Array [], - "transforms": Array [ - [Function], - ], - "type": "array", + "transforms": Array [], + "type": "mixed", }, "permalink": SchemaType { "_blacklist": RefSet { diff --git a/src/utils/__tests__/validations.spec.ts b/src/utils/__tests__/validations.spec.ts index 6b69a209..bfecfa7e 100644 --- a/src/utils/__tests__/validations.spec.ts +++ b/src/utils/__tests__/validations.spec.ts @@ -82,6 +82,7 @@ describe('#validations', () => { all: jest.fn(), permalink: jest.fn(), hooks: [], + data: {}, }; expect(validateRoute(validRoute, 'Home')).toEqual(validRoute); // works with valid hook diff --git a/src/utils/prepareRunHook.ts b/src/utils/prepareRunHook.ts index 8831502d..ff22ba05 100644 --- a/src/utils/prepareRunHook.ts +++ b/src/utils/prepareRunHook.ts @@ -11,7 +11,6 @@ function prepareRunHook({ hooks, allSupportedHooks, settings }) { throw new Error(`Hook ${hookName} not defined in hookInterface or via plugins.`); } - const customPropKeys = []; const hookProps = hookDefinition.props.reduce((out, cv) => { if (Object.hasOwnProperty.call(props, cv)) { if (!hookDefinition.mutable.includes(cv)) { @@ -19,13 +18,6 @@ function prepareRunHook({ hooks, allSupportedHooks, settings }) { } else { out[cv] = props[cv]; } - } else if (typeof props.customProps === 'object' && props.customProps[cv]) { - if (!hookDefinition.mutable.includes(cv)) { - out[cv] = createReadOnlyProxy(props.customProps[cv], cv, hookName); - } else { - out[cv] = props.customProps[cv]; - } - customPropKeys.push(cv); } else { console.error( `Hook named '${hookName}' cannot be run because prop ${cv} is not in scope to pass to the hook. Hook contract broken.`, @@ -81,11 +73,7 @@ function prepareRunHook({ hooks, allSupportedHooks, settings }) { ) { hookDefinition.mutable.forEach((key) => { if ({}.hasOwnProperty.call(hookOutput, key)) { - if (customPropKeys.includes(key)) { - props.customProps[key] = hookOutput[key]; - } else { - props[key] = hookOutput[key]; - } + props[key] = hookOutput[key]; } }); } diff --git a/src/utils/prepareServer.ts b/src/utils/prepareServer.ts index efd5efa6..f5bc282a 100644 --- a/src/utils/prepareServer.ts +++ b/src/utils/prepareServer.ts @@ -13,7 +13,6 @@ function prepareServer({ bootstrapComplete }) { allRequests, runHook, errors, - customProps, } = await bootstrapComplete; if (req.path) { @@ -49,7 +48,6 @@ function prepareServer({ bootstrapComplete }) { allRequests, routes, errors, - customProps, }; await runHook('middleware', { ...forPage, req, next, res }); diff --git a/src/utils/validations.ts b/src/utils/validations.ts index 0a0f9161..9f19a2f7 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -145,7 +145,8 @@ const routeSchema = yup.object({ ), data: yup .mixed() - .required() + .notRequired() + .default({}) .label( `Async/sync function that returns a JS object. Can also be a plain JS object. Important: If this is a function it is passed a '{data}' parameter. This parameter should be mutated and returned to pick up any data populated via hooks or plugins.`, ), diff --git a/src/workerBuild.ts b/src/workerBuild.ts index a7bc4f96..1b3ef2ac 100644 --- a/src/workerBuild.ts +++ b/src/workerBuild.ts @@ -9,7 +9,6 @@ async function workerBuild({ bootstrapComplete, workerRequests }) { runHook, routes: workerRoutes, errors, - customProps, allRequests, } = await bootstrapComplete; @@ -37,7 +36,6 @@ async function workerBuild({ bootstrapComplete, workerRequests }) { runHook, routes: workerRoutes, errors, - customProps, }); const { errors: buildErrors, timings } = await page.build(); i += 1; From e77877bba208b18841f94cb64be59f6f615ca70d Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 14 Sep 2020 13:05:38 -0400 Subject: [PATCH 06/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20compileHtml=20hook?= =?UTF-8?q?=20to=20give=20complete=20control=20over=20html?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 8 +-- .../__snapshots__/Elder.spec.ts.snap | 72 +++++++++++++++++-- .../__snapshots__/hooks.spec.ts.snap | 7 ++ src/__tests__/hooks.spec.ts | 28 ++++++-- src/hookInterface/hookInterface.ts | 15 +++- src/hookInterface/types.ts | 3 +- src/hooks.ts | 12 ++++ src/utils/Page.ts | 43 +++++------ src/utils/__tests__/Page.spec.ts | 26 +------ .../__tests__/__snapshots__/Page.spec.ts.snap | 53 ++++---------- .../__snapshots__/validations.spec.ts.snap | 1 - src/utils/__tests__/prepareRunHook.spec.ts | 20 ------ 12 files changed, 163 insertions(+), 125 deletions(-) diff --git a/package-lock.json b/package-lock.json index 395a810c..7261b8e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.4", + "version": "0.1.5", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1590,9 +1590,9 @@ "dev": true }, "@types/node": { - "version": "14.6.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.2.tgz", - "integrity": "sha512-onlIwbaeqvZyniGPfdw/TEhKIh79pz66L1q06WUQqJLnAb6wbjvOtepLYTGHTqzdXgBYIE3ZdmqHDGsRsbBz7A==", + "version": "14.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.10.1.tgz", + "integrity": "sha512-aYNbO+FZ/3KGeQCEkNhHFRIzBOUgc7QvcVNKXbfnhDkSfwUv91JsQQa10rDgKSTSLkXZ1UIyPe4FJJNVgw1xWQ==", "dev": true }, "@types/normalize-package-data": { diff --git a/src/__tests__/__snapshots__/Elder.spec.ts.snap b/src/__tests__/__snapshots__/Elder.spec.ts.snap index b55db317..5b742558 100644 --- a/src/__tests__/__snapshots__/Elder.spec.ts.snap +++ b/src/__tests__/__snapshots__/Elder.spec.ts.snap @@ -104,7 +104,6 @@ Elder { "settings", "allRequests", "routes", - "customProps", "req", "next", "res", @@ -119,7 +118,6 @@ Elder { "settings", "allRequests", "routes", - "customProps", "req", "next", "res", @@ -268,9 +266,30 @@ Elder { "query", "errors", ], - "use": "

    This hook's headSting represents everything that will be written to <head> tag excluding CSS (those are managed on the style hook).

    + "use": "

    This hook's headSting represents everything that will be written to <head> tag.

    There are many possible SEO uses to this hook, especially for plugins. That said, we recommend users who want to set common SEO elements such as tags <title> and meta descriptions programatically to do it from within Svelte templates using the <svelte:head></svelte:head> tag. Chances are you won't need this field unless you're a power user and need access to the raw head.

    ", }, + Object { + "advanced": true, + "context": "This is where Elder.js merges the html from the Svelte layout with stacks and wraps it in an tag.", + "experimental": false, + "hook": "compileHtml", + "location": "Page.ts", + "mutable": Array [ + "errors", + "htmlString", + ], + "props": Array [ + "helpers", + "data", + "request", + "headString", + "footerString", + "layoutHtml", + "htmlString", + ], + "use": "

    This stack should only be used when you need to have full control over the <html> document. Make sure if you use this to add 'elderCompileHtml' to the 'hooks.disable' array in your elder.config.js or your template will be overwritten.

    ", + }, Object { "advanced": false, "context": "Executed when all of the html has been compiled.", @@ -418,6 +437,17 @@ Elder { "priority": 1, "run": [Function], }, + Object { + "$$meta": Object { + "addedBy": "elder.js", + "type": "internal", + }, + "description": "Creates an HTML string out of the Svelte layout and stacks.", + "hook": "compileHtml", + "name": "elderCompileHtml", + "priority": 100, + "run": [Function], + }, Object { "$$meta": Object { "addedBy": "elder.js", @@ -672,7 +702,6 @@ Elder { "settings", "allRequests", "routes", - "customProps", "req", "next", "res", @@ -687,7 +716,6 @@ Elder { "settings", "allRequests", "routes", - "customProps", "req", "next", "res", @@ -836,9 +864,30 @@ Elder { "query", "errors", ], - "use": "

    This hook's headSting represents everything that will be written to <head> tag excluding CSS (those are managed on the style hook).

    + "use": "

    This hook's headSting represents everything that will be written to <head> tag.

    There are many possible SEO uses to this hook, especially for plugins. That said, we recommend users who want to set common SEO elements such as tags <title> and meta descriptions programatically to do it from within Svelte templates using the <svelte:head></svelte:head> tag. Chances are you won't need this field unless you're a power user and need access to the raw head.

    ", }, + Object { + "advanced": true, + "context": "This is where Elder.js merges the html from the Svelte layout with stacks and wraps it in an tag.", + "experimental": false, + "hook": "compileHtml", + "location": "Page.ts", + "mutable": Array [ + "errors", + "htmlString", + ], + "props": Array [ + "helpers", + "data", + "request", + "headString", + "footerString", + "layoutHtml", + "htmlString", + ], + "use": "

    This stack should only be used when you need to have full control over the <html> document. Make sure if you use this to add 'elderCompileHtml' to the 'hooks.disable' array in your elder.config.js or your template will be overwritten.

    ", + }, Object { "advanced": false, "context": "Executed when all of the html has been compiled.", @@ -986,6 +1035,17 @@ Elder { "priority": 1, "run": [Function], }, + Object { + "$$meta": Object { + "addedBy": "elder.js", + "type": "internal", + }, + "description": "Creates an HTML string out of the Svelte layout and stacks.", + "hook": "compileHtml", + "name": "elderCompileHtml", + "priority": 100, + "run": [Function], + }, Object { "$$meta": Object { "addedBy": "elder.js", diff --git a/src/__tests__/__snapshots__/hooks.spec.ts.snap b/src/__tests__/__snapshots__/hooks.spec.ts.snap index 69682f33..85e53502 100644 --- a/src/__tests__/__snapshots__/hooks.spec.ts.snap +++ b/src/__tests__/__snapshots__/hooks.spec.ts.snap @@ -107,6 +107,13 @@ Array [ "priority": 1, "run": [Function], }, + Object { + "description": "Creates an HTML string out of the Svelte layout and stacks.", + "hook": "compileHtml", + "name": "elderCompileHtml", + "priority": 100, + "run": [Function], + }, Object { "description": "Log any errors to the console.", "hook": "error", diff --git a/src/__tests__/hooks.spec.ts b/src/__tests__/hooks.spec.ts index e79038c2..325d1b4c 100644 --- a/src/__tests__/hooks.spec.ts +++ b/src/__tests__/hooks.spec.ts @@ -46,12 +46,26 @@ describe('#hooks', () => { ).toMatchSnapshot(); expect(await hooks[4].run({ beforeHydrateStack: [], settings: {} })).toBe(null); }); + + it('elderCreateHtmlString', async () => { + expect( + await hooks[5].run({ + request: { route: 'test' }, + headString: 'head', + footerString: 'footer', + layoutHtml: 'layout', + }), + ).toStrictEqual({ + htmlString: 'headlayoutfooter', + }); + }); + it('elderConsoleLogErrors', async () => { - expect(await hooks[5].run({ errors: ['foo', 'bar'] })).toBe(undefined); + expect(await hooks[6].run({ errors: ['foo', 'bar'] })).toBe(undefined); }); it('elderWriteHtmlFileToPublic', async () => { expect( - await hooks[6].run({ + await hooks[7].run({ request: { permalink: '/foo' }, htmlString: 'string', errors: [], @@ -59,7 +73,7 @@ describe('#hooks', () => { }), ).toBe(null); expect( - await hooks[6].run({ + await hooks[7].run({ request: { permalink: '/foo' }, htmlString: 'string', errors: [], @@ -67,7 +81,7 @@ describe('#hooks', () => { }), ).toBe(null); expect( - await hooks[6].run({ + await hooks[7].run({ request: { permalink: '/foo' }, htmlString: 'string', errors: [], @@ -77,7 +91,7 @@ describe('#hooks', () => { }); it('elderDisplayRequestTime', async () => { expect( - await hooks[7].run({ + await hooks[8].run({ request: { permalink: '/foo' }, timings: [ { name: 'foo', duration: 500 }, @@ -89,7 +103,7 @@ describe('#hooks', () => { }); it('elderShowParsedBuildTimes', async () => { expect( - await hooks[8].run({ + await hooks[9].run({ timings: [ [ { name: 'foo', duration: 500 }, @@ -106,7 +120,7 @@ describe('#hooks', () => { }); it('elderWriteBuildErrors', async () => { expect( - await hooks[9].run({ + await hooks[10].run({ errors: ['error1', 'error2'], settings: { debug: { performance: true } }, }), diff --git a/src/hookInterface/hookInterface.ts b/src/hookInterface/hookInterface.ts index 111fbd20..4ad5f33d 100644 --- a/src/hookInterface/hookInterface.ts +++ b/src/hookInterface/hookInterface.ts @@ -61,7 +61,6 @@ export const hookInterface: Array = [ 'settings', 'allRequests', 'routes', - 'customProps', 'req', 'next', 'res', @@ -76,7 +75,6 @@ export const hookInterface: Array = [ 'settings', 'allRequests', 'routes', - 'customProps', 'req', 'next', 'res', @@ -195,13 +193,24 @@ export const hookInterface: Array = [ props: ['helpers', 'data', 'settings', 'request', 'headString', 'query', 'errors'], mutable: ['errors', 'headString'], context: 'Executed just before writing the tag to the page.', - use: `

    This hook's headSting represents everything that will be written to <head> tag excluding CSS (those are managed on the style hook).

    + use: `

    This hook's headSting represents everything that will be written to <head> tag.

    There are many possible SEO uses to this hook, especially for plugins. That said, we recommend users who want to set common SEO elements such as tags <title> and meta descriptions programatically to do it from within Svelte templates using the <svelte:head></svelte:head> tag. Chances are you won't need this field unless you're a power user and need access to the raw head.

    `, location: 'Page.ts', experimental: false, advanced: true, }, + { + hook: 'compileHtml', + props: ['helpers', 'data', 'request', 'headString', 'footerString', 'layoutHtml', 'htmlString'], + mutable: ['errors', 'htmlString'], + context: 'This is where Elder.js merges the html from the Svelte layout with stacks and wraps it in an tag.', + use: `

    This hook should only be used when you need to have full control over the <html> document. Make sure if you use this to add 'elderCompileHtml' to the 'hooks.disable' array in your elder.config.js or your template will be overwritten.

    `, + location: 'Page.ts', + experimental: false, + advanced: true, + }, + { hook: 'html', props: ['helpers', 'data', 'settings', 'request', 'htmlString', 'query', 'errors'], diff --git a/src/hookInterface/types.ts b/src/hookInterface/types.ts index b55a285e..42d32ccd 100644 --- a/src/hookInterface/types.ts +++ b/src/hookInterface/types.ts @@ -10,7 +10,8 @@ export type Hook = | 'html' | 'requestComplete' | 'error' - | 'buildComplete'; + | 'buildComplete' + | 'compileHtml'; export type HookInterface = { hook: Hook; diff --git a/src/hooks.ts b/src/hooks.ts index c22a2e2d..5fea9519 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -133,6 +133,18 @@ const hooks: Array = [ return null; }, }, + { + hook: 'compileHtml', + name: 'elderCompileHtml', + description: 'Creates an HTML string out of the Svelte layout and stacks.', + priority: 50, + run: async ({ request, headString, footerString, layoutHtml, htmlString }) => { + return { + htmlString: `${headString}${layoutHtml}${footerString}`, + }; + }, + }, + { hook: 'error', name: 'elderConsoleLogErrors', diff --git a/src/utils/Page.ts b/src/utils/Page.ts index 9bd35603..56cc2a99 100644 --- a/src/utils/Page.ts +++ b/src/utils/Page.ts @@ -51,7 +51,7 @@ const buildPage = async (page) => { page.perf.end('html.template'); page.perf.start('html.layout'); - const layoutHtml = page.route.layout({ + page.layoutHtml = page.route.layout({ page, props: { data: page.data, @@ -65,34 +65,30 @@ const buildPage = async (page) => { // Run header hooks / stacks to make headString await page.runHook('stacks', page); + + // prepare for head hook page.head = page.processStack('headStack'); page.cssString = ''; page.cssString = page.processStack('cssStack'); - page.styleTag = ``; + page.styleTag = ``; page.headString = `${page.head}${page.styleTag}`; - page.beforeHydrate = page.processStack('beforeHydrateStack'); - page.hydrate = ``; - page.customJs = page.processStack('customJsStack'); - page.footer = page.processStack('footerStack'); await page.runHook('head', page); - page.perf.start('html.createHtmlString'); - page.htmlString = ` - - - ${page.headString} - - - ${layoutHtml} - ${page.hydrateStack.length > 0 ? page.beforeHydrate : '' /* page.hydrateStack.length is correct here */} - ${page.hydrateStack.length > 0 ? page.hydrate : ''} - ${page.customJsStack.length > 0 ? page.customJs : ''} - ${page.footerStack.length > 0 ? page.footer : ''} - - + // prepare for compileHtml + const beforeHydrate = page.processStack('beforeHydrateStack'); + const hydrate = ``; + const customJs = page.processStack('customJsStack'); + const footer = page.processStack('footerStack'); + + page.footerString = ` + ${page.hydrateStack.length > 0 ? beforeHydrate : '' /* page.hydrateStack.length is correct here */} + ${page.hydrateStack.length > 0 ? hydrate : ''} + ${page.customJsStack.length > 0 ? customJs : ''} + ${page.footerStack.length > 0 ? footer : ''} `; - page.perf.end('html.createHtmlString'); + + await page.runHook('compileHtml', page); await page.runHook('html', page); @@ -142,6 +138,10 @@ class Page { perf: any; + layoutHtml: string; + + cssString: string; + htmlString: string; headStack: Stack; @@ -171,6 +171,7 @@ class Page { this.query = query; this.errors = [...errors]; this.routes = routes; + this.cssString = ''; this.htmlString = ''; this.headStack = []; diff --git a/src/utils/__tests__/Page.spec.ts b/src/utils/__tests__/Page.spec.ts index e5703223..68f9efa2 100644 --- a/src/utils/__tests__/Page.spec.ts +++ b/src/utils/__tests__/Page.spec.ts @@ -87,7 +87,7 @@ const settings = { }, debug: { stacks: false, - hooks: false, + hooks: true, performance: false, build: false, automagic: false, @@ -204,34 +204,12 @@ describe('#Page', () => { runHook, }; - const expectedOutput = ` - - - headStack - - -
    - beforeHydrateStack - - customJsStack - footerStack - - `; - it('initialize and build', async () => { const page = new Page(pageInput); expect(page).toMatchSnapshot(); await page.build(); - expect(hooks).toEqual(['request', 'data', 'stacks', 'head', 'html', 'requestComplete']); + expect(hooks).toEqual(['request', 'data', 'stacks', 'head', 'compileHtml', 'html', 'requestComplete']); expect(page).toMatchSnapshot(); - const htmlString = await page.html(); - expect(htmlString.trim()).toEqual(expectedOutput); - }); - - it('init and request html', async () => { - const page = new Page({ ...pageInput, route: { ...pageInput.route, data: { worldPopulation: 7805564950 } } }); - const html = await page.html(); - expect(html.trim()).toEqual(expectedOutput); }); it('init and request html, throw catched errors', async () => { diff --git a/src/utils/__tests__/__snapshots__/Page.spec.ts.snap b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap index 8c50c657..eb9553fa 100644 --- a/src/utils/__tests__/__snapshots__/Page.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap @@ -28,6 +28,7 @@ Page { ], "beforeHydrateStack": Array [], "cssStack": Array [], + "cssString": "", "customJsStack": Array [], "data": Object {}, "errors": Array [], @@ -175,7 +176,7 @@ Page { "debug": Object { "automagic": false, "build": false, - "hooks": false, + "hooks": true, "performance": false, "stacks": false, }, @@ -235,11 +236,9 @@ Page { "type": "build", }, ], - "beforeHydrate": "beforeHydrateStack", "beforeHydrateStack": Array [], "cssStack": Array [], "cssString": "cssStack", - "customJs": "customJsStack", "customJsStack": Array [ "customJsStack", ], @@ -247,35 +246,27 @@ Page { "worldPopulation": 7805564950, }, "errors": Array [], - "footer": "footerStack", "footerStack": Array [ "footerStack", ], + "footerString": " + beforeHydrateStack + + customJsStack + footerStack + ", "head": "headStack", "headStack": Array [], - "headString": "headStack", + "headString": "headStack", "helpers": Object { "metersInAMile": 0.00062137119224, "permalinks": Object {}, }, - "htmlString": " - - - headStack - - -
    - beforeHydrateStack - - customJsStack - footerStack - - - ", - "hydrate": "", + "htmlString": "", "hydrateStack": Array [ "hydrateStack", ], + "layoutHtml": "
    ", "perf": Object { "end": [MockFunction] { "calls": Array [ @@ -294,9 +285,6 @@ Page { Array [ "html.layout", ], - Array [ - "html.createHtmlString", - ], Array [ "page", ], @@ -326,10 +314,6 @@ Page { "type": "return", "value": undefined, }, - Object { - "type": "return", - "value": undefined, - }, ], }, "start": [MockFunction] { @@ -352,9 +336,6 @@ Page { Array [ "html.layout", ], - Array [ - "html.createHtmlString", - ], ], "results": Array [ Object { @@ -381,10 +362,6 @@ Page { "type": "return", "value": undefined, }, - Object { - "type": "return", - "value": undefined, - }, ], }, "stop": [MockFunction] { @@ -486,7 +463,7 @@ Page { "debug": Object { "automagic": false, "build": false, - "hooks": false, + "hooks": true, "performance": false, "stacks": false, }, @@ -573,7 +550,7 @@ Page { "debug": Object { "automagic": false, "build": false, - "hooks": false, + "hooks": true, "performance": false, "stacks": false, }, @@ -661,7 +638,7 @@ Page { "debug": Object { "automagic": false, "build": false, - "hooks": false, + "hooks": true, "performance": false, "stacks": false, }, @@ -691,7 +668,7 @@ Page { "typescript": false, "worker": true, }, - "styleTag": "", + "styleTag": "", "timings": Array [], "uid": "xxxxxxxxxx", } diff --git a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap index b00d32b0..12283a83 100644 --- a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap @@ -1425,7 +1425,6 @@ ObjectSchema { "_exclusive": Object {}, "_label": "Async/sync function that returns a JS object. Can also be a plain JS object. Important: If this is a function it is passed a '{data}' parameter. This parameter should be mutated and returned to pick up any data populated via hooks or plugins.", "_mutate": undefined, - "_nullable": true, "_options": Object { "abortEarly": true, "recursive": true, diff --git a/src/utils/__tests__/prepareRunHook.spec.ts b/src/utils/__tests__/prepareRunHook.spec.ts index fd80215d..a53a2491 100644 --- a/src/utils/__tests__/prepareRunHook.spec.ts +++ b/src/utils/__tests__/prepareRunHook.spec.ts @@ -72,26 +72,6 @@ describe('#prepareRunHook', () => { expect(errors).toEqual(['something bad happened']); }); - it('works for custom props', async () => { - const errors = []; - await expect( - await prepareRunHookFn('bootstrap-custom', { settings, errors, perf, customProps: { customProp: 'testProp' } }), - ).toEqual({ - customProps: { - customProp: 'testProp', - }, - errors: [], - perf, - settings: { - debug: { - hooks: true, - }, - magicNumber: 42, - }, - }); - expect(errors).toEqual([]); - }); - it('cannot mutate not mutable prop', async () => { prepareRunHookFn = prepareRunHook({ hooks, allSupportedHooks, settings }); const errors = []; From b10e38df6a91444edd567387971dddace20ca352 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 14 Sep 2020 13:36:56 -0400 Subject: [PATCH 07/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Make=20sure=20rout?= =?UTF-8?q?e=20`data`=20functions=20have=20readonly=20props?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Elder.ts | 9 +++++---- src/utils/Page.ts | 10 ++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Elder.ts b/src/Elder.ts index df170fcb..a010cbf8 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -371,6 +371,7 @@ class Elder { this.runHook('customizeHooks', this).then(async () => { // we now have any customizations to the hookInterface. + // we need to rebuild runHook with these customizations. this.runHook = prepareRunHook({ hooks: this.hooks, allSupportedHooks: this.hookInterface, @@ -385,10 +386,10 @@ class Elder { let allRequestsForRoute = []; if (typeof route.all === 'function') { allRequestsForRoute = await route.all({ - settings: this.settings, - query: this.query, - helpers: this.helpers, - data: this.data, + settings: createReadOnlyProxy(this.settings, 'settings', `${routeName} all function`), + query: createReadOnlyProxy(this.query, 'query', `${routeName} all function`), + helpers: createReadOnlyProxy(this.helpers, 'helpers', `${routeName} all function`), + data: createReadOnlyProxy(this.data, 'data', `${routeName} all function`), }); } else if (Array.isArray(route.all)) { allRequestsForRoute = route.all; diff --git a/src/utils/Page.ts b/src/utils/Page.ts index 56cc2a99..52624951 100644 --- a/src/utils/Page.ts +++ b/src/utils/Page.ts @@ -35,10 +35,7 @@ const buildPage = async (page) => { // start building templates page.perf.start('html.template'); - - // template building starts here - - const routeHTML = page.route.templateComponent({ + page.routeHTML = page.route.templateComponent({ page, props: { data: page.data, @@ -47,9 +44,10 @@ const buildPage = async (page) => { request: page.request, }, }); - page.perf.end('html.template'); + // shortcodes here. + page.perf.start('html.layout'); page.layoutHtml = page.route.layout({ page, @@ -58,7 +56,7 @@ const buildPage = async (page) => { helpers: page.helpers, settings: page.settings, request: page.request, - routeHTML, + routeHTML: page.routeHTML, }, }); page.perf.end('html.layout'); From f85ddbb6931b2bbbe279b2b0bd05afa3099be85b Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 15 Sep 2020 12:17:35 -0400 Subject: [PATCH 08/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20initial=20shortcod?= =?UTF-8?q?e=20support=20with=20async?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 5 +++ package.json | 1 + src/Elder.ts | 28 ++++++++++++ src/hookInterface/hookInterface.ts | 23 ++++++++++ src/hookInterface/types.ts | 5 ++- src/hooks.ts | 41 ++++++++++++++++++ src/utils/Page.ts | 17 +++++--- src/utils/prepareServer.ts | 2 + src/utils/prepareShortcodeParser.ts | 66 +++++++++++++++++++++++++++++ src/utils/types.ts | 15 +++++++ src/utils/validations.ts | 19 +++++++++ src/workerBuild.ts | 2 + 12 files changed, 217 insertions(+), 7 deletions(-) create mode 100644 src/utils/prepareShortcodeParser.ts diff --git a/package-lock.json b/package-lock.json index 7261b8e3..ef5db6d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -510,6 +510,11 @@ "dev": true, "optional": true }, + "@elderjs/shortcodes": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@elderjs/shortcodes/-/shortcodes-1.0.5.tgz", + "integrity": "sha512-5NofJ/1OuKNEUPYYrnTkNHMjMZarw7XG6d5NqXavyraxTEA48bVrY3hH5bxYQipMhxRJHNkF6QSQjmwpLAE0kQ==" + }, "@eslint/eslintrc": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.0.tgz", diff --git a/package.json b/package.json index 4f2f0c1d..d36c2106 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "glob": "^7.1.6", "intersection-observer": "^0.11.0", "lodash.defaultsdeep": "^4.6.1", + "@elderjs/shortcodes": "^1.0.5", "nanoid": "^3.1.12", "systemjs": "^6.5.0", "yup": "^0.29.3" diff --git a/src/Elder.ts b/src/Elder.ts index a010cbf8..109d584f 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -32,6 +32,7 @@ import { RequestsOptions, PluginOptions, ExcludesFalse, + ShortcodeDefs, } from './utils/types'; import createReadOnlyProxy from './utils/createReadOnlyProxy'; import workerBuild from './workerBuild'; @@ -70,6 +71,8 @@ class Elder { builder: any; + shortcodes: ShortcodeDefs; + constructor({ context, worker = false }) { this.bootstrapComplete = new Promise((resolve) => { this.markBootstrapComplete = resolve; @@ -154,6 +157,8 @@ class Elder { if (!validatedPlugin) return; plugin = validatedPlugin; + // TODO: Collect plugin, shortcodes here. + // clean props the plugin shouldn't be able to change between hook... specifically their hooks; let { hooks: pluginHooksArray } = plugin; @@ -357,6 +362,29 @@ class Elder { inlineSvelteComponent, }; + this.shortcodes = [ + { + shortcode: 'svelteComponent', + run: async ({ props, content, data, helpers, request, query }) => { + console.log('ran'); + return { + html: helpers.inlineSvelteComponent({ name: props.name, props: props.props, options: props.options }), + }; + }, + }, + // { + // shortcode: 'box', + // run: async ({ content }) => { + // return { + // html: `
    ${content}
    `, + // css: '.test{}', + // js: '', + // head: '', + // }; + // }, + // }, + ]; + if (context === 'server') { this.server = prepareServer({ bootstrapComplete: this.bootstrapComplete }); } diff --git a/src/hookInterface/hookInterface.ts b/src/hookInterface/hookInterface.ts index 4ad5f33d..4b0c1b16 100644 --- a/src/hookInterface/hookInterface.ts +++ b/src/hookInterface/hookInterface.ts @@ -154,6 +154,29 @@ export const hookInterface: Array = [ advanced: true, }, + { + hook: 'shortcodes', + props: [ + 'helpers', + 'data', + 'settings', + 'request', + 'query', + 'errors', + 'cssStack', + 'headStack', + 'customJsStack', + 'routeHtml', + 'shortcodes', + ], + mutable: ['errors', 'routeHtml', 'cssStack', 'headStack', 'customJsStack'], + context: `Executed after the route's html has been compiled, but before the layout html has been compiled.`, + use: `

    Elder.js uses this hook to process shortcodes. The vast majority of users won't need to use this hook, but if you'd like to disable shortcodes completely, you can add 'elderProcessShortcodes' to hooks.disable in your elder.config.js file.

    `, + location: 'Page.ts', + experimental: false, + advanced: true, + }, + { hook: 'stacks', props: [ diff --git a/src/hookInterface/types.ts b/src/hookInterface/types.ts index 42d32ccd..cd9a75e8 100644 --- a/src/hookInterface/types.ts +++ b/src/hookInterface/types.ts @@ -5,13 +5,14 @@ export type Hook = | 'middleware' | 'request' | 'data' + | 'shortcodes' | 'stacks' | 'head' + | 'compileHtml' | 'html' | 'requestComplete' | 'error' - | 'buildComplete' - | 'compileHtml'; + | 'buildComplete'; export type HookInterface = { hook: Hook; diff --git a/src/hooks.ts b/src/hooks.ts index 5fea9519..fed94c70 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -3,6 +3,7 @@ import fs from 'fs-extra'; import { parseBuildPerf } from './utils'; import externalHelpers from './externalHelpers'; import { HookOptions } from './hookInterface/types'; +import prepareShortcodeParser from './utils/prepareShortcodeParser'; const hooks: Array = [ { @@ -28,6 +29,46 @@ const hooks: Array = [ return null; }, }, + { + hook: 'shortcodes', + name: 'elderProcessShortcodes', + description: + "Builds the shortcode parser, parses shortcodes from the html returned by the route's html and appends anything needed to the stacks.", + priority: 50, + run: async ({ + helpers, + data, + settings, + request, + query, + cssStack, + headStack, + customJsStack, + routeHtml, + shortcodes, + }) => { + const ShortcodeParser = prepareShortcodeParser({ + shortcodes, + helpers, + data, + settings, + request, + query, + cssStack, + headStack, + customJsStack, + }); + + const html = await ShortcodeParser.parse(routeHtml); + + return { + routeHtml: html, + headStack, + cssStack, + customJsStack, + }; + }, + }, { hook: 'stacks', name: 'elderAddMetaCharsetToHead', diff --git a/src/utils/Page.ts b/src/utils/Page.ts index 52624951..b2f113a2 100644 --- a/src/utils/Page.ts +++ b/src/utils/Page.ts @@ -2,7 +2,7 @@ import getUniqueId from './getUniqueId'; import perf from './perf'; import prepareProcessStack from './prepareProcessStack'; -import { QueryOptions, Stack, SettingOptions, ConfigOptions, RequestOptions } from './types'; +import { QueryOptions, Stack, SettingOptions, ConfigOptions, RequestOptions, ShortcodeDefs } from './types'; import { RoutesOptions } from '../routes/types'; import createReadOnlyProxy from './createReadOnlyProxy'; @@ -35,7 +35,7 @@ const buildPage = async (page) => { // start building templates page.perf.start('html.template'); - page.routeHTML = page.route.templateComponent({ + page.routeHtml = page.route.templateComponent({ page, props: { data: page.data, @@ -48,6 +48,9 @@ const buildPage = async (page) => { // shortcodes here. + await page.runHook('shortcodes', page); + + // todo: readonly proxies? page.perf.start('html.layout'); page.layoutHtml = page.route.layout({ page, @@ -56,12 +59,11 @@ const buildPage = async (page) => { helpers: page.helpers, settings: page.settings, request: page.request, - routeHTML: page.routeHTML, + routeHTML: page.routeHtml, }, }); page.perf.end('html.layout'); - // Run header hooks / stacks to make headString await page.runHook('stacks', page); // prepare for head hook @@ -138,6 +140,8 @@ class Page { layoutHtml: string; + routeHtml: string; + cssString: string; htmlString: string; @@ -154,7 +158,9 @@ class Page { footerStack: Stack; - constructor({ request, settings, query, helpers, data, route, runHook, allRequests, routes, errors }) { + shortcodes: ShortcodeDefs; + + constructor({ request, settings, query, helpers, data, route, runHook, allRequests, routes, errors, shortcodes }) { this.uid = getUniqueId(); perf(this); this.perf.start('page'); @@ -178,6 +184,7 @@ class Page { this.hydrateStack = []; this.customJsStack = []; this.footerStack = []; + this.shortcodes = shortcodes; this.processStack = prepareProcessStack(this); diff --git a/src/utils/prepareServer.ts b/src/utils/prepareServer.ts index f5bc282a..1c57aeb6 100644 --- a/src/utils/prepareServer.ts +++ b/src/utils/prepareServer.ts @@ -13,6 +13,7 @@ function prepareServer({ bootstrapComplete }) { allRequests, runHook, errors, + shortcodes, } = await bootstrapComplete; if (req.path) { @@ -48,6 +49,7 @@ function prepareServer({ bootstrapComplete }) { allRequests, routes, errors, + shortcodes, }; await runHook('middleware', { ...forPage, req, next, res }); diff --git a/src/utils/prepareShortcodeParser.ts b/src/utils/prepareShortcodeParser.ts new file mode 100644 index 00000000..38c79ffb --- /dev/null +++ b/src/utils/prepareShortcodeParser.ts @@ -0,0 +1,66 @@ +const ShortcodeParser = require('@elderjs/shortcodes'); +const { ShortcodeResponse } = require('./types'); + +function prepareShortcodeParser({ + shortcodes, + helpers, + data, + settings, + request, + query, + cssStack, + headStack, + customJsStack, +}) { + const { openPattern, closePattern } = settings.shortcodes; + const shortcodeParser = ShortcodeParser({ openPattern, closePattern }); + + shortcodes.forEach((shortcode) => { + if (typeof shortcode.run !== 'function') + throw new Error(`Shortcodes must have a run function. Problem code: ${JSON.stringify(shortcode)}`); + if (typeof shortcode.shortcode !== 'string') + throw new Error( + `Shortcodes must have a shortcode property to define their usage. Problem code: ${JSON.stringify(shortcode)}`, + ); + + shortcodeParser.add(shortcode.shortcode, async (props, content) => { + // todo, async? + + console.log(shortcode.shortcode, props, content); + + // plugin? + const { html, css, js, head } = await shortcode.run({ + props, + content, + data, + request, + query, + helpers, + }); + + if (css) { + cssStack.push({ + source: `${shortcode.shortcode} shortcode`, + string: css, + }); + } + if (js) { + customJsStack.push({ + source: `${shortcode.shortcode} shortcode`, + string: js, + }); + } + if (head) { + headStack.push({ + source: `${shortcode.shortcode} shortcode`, + string: head, + }); + } + return html; + }); + }); + + return shortcodeParser; +} + +export default prepareShortcodeParser; diff --git a/src/utils/types.ts b/src/utils/types.ts index 60ece28a..10843612 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -126,3 +126,18 @@ export interface ComponentPayload { props: any; hydrateOptions?: HydrateOptions; } + +export interface ShortcodeDef { + shortcode: string; + run: (any) => ShortcodeResponse | Promise; + plugin?: any; // plugin closure scope? +} + +export interface ShortcodeResponse { + html?: string; + css?: string; + js?: string; + head?: string; +} + +export type ShortcodeDefs = Array; diff --git a/src/utils/validations.ts b/src/utils/validations.ts index 9f19a2f7..0f677f99 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -4,6 +4,19 @@ import type { RouteOptions } from '../routes/types'; import type { HookOptions } from '../hookInterface/types'; import hookInterface from '../hookInterface/hookInterface'; +const shortcodeSchema = yup.object({ + shortcode: yup.string().required().label(`The 'name' of the shortcode. {{name /}}`), + run: yup + .mixed() + .required() + .test( + 'isFunction', + 'run() should be a function or async function', + (value) => typeof value === 'function' || (typeof value === 'object' && value.then === 'function'), + ) + .label(`A sync/async function that returns the html, css, js, and head to be added to the html.`), +}); + const configSchema = yup.object({ siteUrl: yup.string().notRequired().default('').label(`The domain your site is hosted on. https://yourdomain.com.`), locations: yup @@ -118,6 +131,11 @@ const configSchema = yup.object({ ), }), typescript: yup.boolean().default(false).label('This causes Elder.js to look in the /build/ folder '), + shortcodes: yup.object({ + openPattern: yup.string().default('{{').label('Opening pattern for identifying shortcodes in html output.'), + closePattern: yup.string().default('}}').label('closing pattern for identifying shortcodes in html output.'), + customShortcodes: yup.array().default([]).label('An array of custom shortcodes'), + }), plugins: yup.object().default({}).label('Used to define Elder.js plugins.'), }); @@ -289,4 +307,5 @@ export { hookSchema, routeSchema, pluginSchema, + shortcodeSchema, }; diff --git a/src/workerBuild.ts b/src/workerBuild.ts index 1b3ef2ac..faeb41bc 100644 --- a/src/workerBuild.ts +++ b/src/workerBuild.ts @@ -10,6 +10,7 @@ async function workerBuild({ bootstrapComplete, workerRequests }) { routes: workerRoutes, errors, allRequests, + shortcodes, } = await bootstrapComplete; // potential issue that since builds are split across processes, @@ -36,6 +37,7 @@ async function workerBuild({ bootstrapComplete, workerRequests }) { runHook, routes: workerRoutes, errors, + shortcodes, }); const { errors: buildErrors, timings } = await page.build(); i += 1; From eaade32b93158b46f318cb0026b02d077577a895 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 15 Sep 2020 14:15:01 -0400 Subject: [PATCH 09/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20inlineSvelte=20com?= =?UTF-8?q?ponent=20shortcode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Elder.ts | 32 ++++++++++++++++------------- src/hookInterface/hookInterface.ts | 3 ++- src/utils/prepareShortcodeParser.ts | 8 ++------ 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/Elder.ts b/src/Elder.ts index 109d584f..5534f19d 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -365,24 +365,28 @@ class Elder { this.shortcodes = [ { shortcode: 'svelteComponent', - run: async ({ props, content, data, helpers, request, query }) => { - console.log('ran'); + run: async ({ props, helpers }) => { + if (!props.name) throw new Error(`svelteComponent shortcode requires a name="" property.`); return { - html: helpers.inlineSvelteComponent({ name: props.name, props: props.props, options: props.options }), + html: helpers.inlineSvelteComponent({ + name: props.name, + props: props.props || {}, + options: props.options || {}, + }), + }; + }, + }, + { + shortcode: 'box', + run: async ({ content }) => { + return { + html: `
    ${content}
    `, + css: '.test{}', + js: '', + head: '', }; }, }, - // { - // shortcode: 'box', - // run: async ({ content }) => { - // return { - // html: `
    ${content}
    `, - // css: '.test{}', - // js: '', - // head: '', - // }; - // }, - // }, ]; if (context === 'server') { diff --git a/src/hookInterface/hookInterface.ts b/src/hookInterface/hookInterface.ts index 4b0c1b16..f761f26e 100644 --- a/src/hookInterface/hookInterface.ts +++ b/src/hookInterface/hookInterface.ts @@ -171,7 +171,8 @@ export const hookInterface: Array = [ ], mutable: ['errors', 'routeHtml', 'cssStack', 'headStack', 'customJsStack'], context: `Executed after the route's html has been compiled, but before the layout html has been compiled.`, - use: `

    Elder.js uses this hook to process shortcodes. The vast majority of users won't need to use this hook, but if you'd like to disable shortcodes completely, you can add 'elderProcessShortcodes' to hooks.disable in your elder.config.js file.

    `, + use: `

    Elder.js uses this hook to process shortcodes. The vast majority of users won't need to use this hook, but if you were so inclined you could write your own shortcode parser or if you'd like to disable shortcodes completely, you can add 'elderProcessShortcodes' to hooks.disable in your elder.config.js file.

    +

    NOTE: Don't use this hook for anything besides shortcodes.

    `, location: 'Page.ts', experimental: false, advanced: true, diff --git a/src/utils/prepareShortcodeParser.ts b/src/utils/prepareShortcodeParser.ts index 38c79ffb..630bae13 100644 --- a/src/utils/prepareShortcodeParser.ts +++ b/src/utils/prepareShortcodeParser.ts @@ -1,5 +1,4 @@ const ShortcodeParser = require('@elderjs/shortcodes'); -const { ShortcodeResponse } = require('./types'); function prepareShortcodeParser({ shortcodes, @@ -24,11 +23,7 @@ function prepareShortcodeParser({ ); shortcodeParser.add(shortcode.shortcode, async (props, content) => { - // todo, async? - - console.log(shortcode.shortcode, props, content); - - // plugin? + // todo: plugin? const { html, css, js, head } = await shortcode.run({ props, content, @@ -36,6 +31,7 @@ function prepareShortcodeParser({ request, query, helpers, + settings, }); if (css) { From 88cdbd08287223deeda02e50bc9bee5a669348c6 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 15 Sep 2020 15:01:47 -0400 Subject: [PATCH 10/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Validate=20shortco?= =?UTF-8?q?des=20from=20Elder,=20Plugins,=20and=20Config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 6 ++-- package.json | 2 +- src/Elder.ts | 55 ++++++++++------------------- src/shortcodes.ts | 23 ++++++++++++ src/utils/getConfig.ts | 8 ++++- src/utils/index.ts | 3 +- src/utils/prepareShortcodeParser.ts | 1 + src/utils/types.ts | 12 ++++++- src/utils/validations.ts | 23 +++++++++++- 9 files changed, 88 insertions(+), 45 deletions(-) create mode 100644 src/shortcodes.ts diff --git a/package-lock.json b/package-lock.json index ef5db6d6..68c13073 100644 --- a/package-lock.json +++ b/package-lock.json @@ -511,9 +511,9 @@ "optional": true }, "@elderjs/shortcodes": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@elderjs/shortcodes/-/shortcodes-1.0.5.tgz", - "integrity": "sha512-5NofJ/1OuKNEUPYYrnTkNHMjMZarw7XG6d5NqXavyraxTEA48bVrY3hH5bxYQipMhxRJHNkF6QSQjmwpLAE0kQ==" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@elderjs/shortcodes/-/shortcodes-1.0.6.tgz", + "integrity": "sha512-8n6FpnCbr4RnJYQDs7869zeywYXNyVtZnA5E4fHYWp2/fJX3OlDp7eYfMj6AnoE+E3Ehs5LVn9uT+rqUXcA0pQ==" }, "@eslint/eslintrc": { "version": "0.1.0", diff --git a/package.json b/package.json index d36c2106..20769e50 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "glob": "^7.1.6", "intersection-observer": "^0.11.0", "lodash.defaultsdeep": "^4.6.1", - "@elderjs/shortcodes": "^1.0.5", + "@elderjs/shortcodes": "^1.0.6", "nanoid": "^3.1.12", "systemjs": "^6.5.0", "yup": "^0.29.3" diff --git a/src/Elder.ts b/src/Elder.ts index 5534f19d..ed80153c 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -17,6 +17,7 @@ import { validateHook, validateRoute, validatePlugin, + validateShortcode, permalinks, asyncForEach, getHashedSvelteComponents, @@ -37,6 +38,7 @@ import { import createReadOnlyProxy from './utils/createReadOnlyProxy'; import workerBuild from './workerBuild'; import { inlineSvelteComponent } from './partialHydration/inlineSvelteComponent'; +import elderJsShortcodes from './shortcodes'; const getElderConfig = getConfig; @@ -106,7 +108,7 @@ class Elder { */ let pluginRoutes: RoutesOptions = {}; const pluginHooks: Array = []; - + const pluginShortcodes: ShortcodeDefs = []; const pluginNames = Object.keys(this.settings.plugins); for (let i = 0; i < pluginNames.length; i += 1) { @@ -157,8 +159,6 @@ class Elder { if (!validatedPlugin) return; plugin = validatedPlugin; - // TODO: Collect plugin, shortcodes here. - // clean props the plugin shouldn't be able to change between hook... specifically their hooks; let { hooks: pluginHooksArray } = plugin; @@ -177,10 +177,6 @@ class Elder { // pass the plugin definition into the closure of every hook. let pluginDefinition = sanitizedPlugin; - // TODO: In a future release add in specific helpers to allow plugins to implement the - // same hook signature as we use on plugin.helpers; Plugin defined hooks will basically "shadow" - // system hooks. - // eslint-disable-next-line no-param-reassign payload.plugin = pluginDefinition; @@ -251,6 +247,14 @@ class Elder { pluginRoutes = { ...pluginRoutes, ...sanitizedRoute }; }); } + + plugin.shortcodes.forEach((shortcode) => { + shortcode.$$meta = { + type: 'plugin', + addedBy: pluginName, + }; + pluginShortcodes.push(shortcode); + }); } // add meta to routes and collect hooks from routes @@ -331,6 +335,7 @@ class Elder { } } + // validate hooks const elderJsHooks: Array = internalHooks.map((hook) => ({ ...hook, $$meta: { @@ -339,8 +344,6 @@ class Elder { }, })); - const allSupportedHooks = hookInterface; - this.hooks = [...elderJsHooks, ...pluginHooks, ...hooksJs] .map((hook) => validateHook(hook)) .filter((Boolean as any) as ExcludesFalse); @@ -349,8 +352,13 @@ class Elder { this.hooks = this.hooks.filter((h) => !this.settings.hooks.disable.includes(h.name)); } + // validate shortcodes + this.shortcodes = [...elderJsShortcodes, ...pluginShortcodes, ...config.shortcodes.customShortcodes] + .map((shortcode) => validateShortcode(shortcode)) + .filter((Boolean as any) as ExcludesFalse); + this.data = {}; - this.hookInterface = allSupportedHooks; + this.hookInterface = hookInterface; this.query = {}; this.allRequests = []; @@ -362,33 +370,6 @@ class Elder { inlineSvelteComponent, }; - this.shortcodes = [ - { - shortcode: 'svelteComponent', - run: async ({ props, helpers }) => { - if (!props.name) throw new Error(`svelteComponent shortcode requires a name="" property.`); - return { - html: helpers.inlineSvelteComponent({ - name: props.name, - props: props.props || {}, - options: props.options || {}, - }), - }; - }, - }, - { - shortcode: 'box', - run: async ({ content }) => { - return { - html: `
    ${content}
    `, - css: '.test{}', - js: '', - head: '', - }; - }, - }, - ]; - if (context === 'server') { this.server = prepareServer({ bootstrapComplete: this.bootstrapComplete }); } diff --git a/src/shortcodes.ts b/src/shortcodes.ts new file mode 100644 index 00000000..43e12aef --- /dev/null +++ b/src/shortcodes.ts @@ -0,0 +1,23 @@ +import { ShortcodeDefs } from './utils/types'; + +const shortcodes: ShortcodeDefs = [ + { + shortcode: 'svelteComponent', + run: async ({ props, helpers }) => { + if (!props.name) throw new Error(`svelteComponent shortcode requires a name="" property.`); + return { + html: helpers.inlineSvelteComponent({ + name: props.name, + props: props.props || {}, + options: props.options || {}, + }), + }; + }, + $$meta: { + addedBy: 'elder', + type: 'elder', + }, + }, +]; + +export default shortcodes; diff --git a/src/utils/getConfig.ts b/src/utils/getConfig.ts index dddcc825..6d714a98 100644 --- a/src/utils/getConfig.ts +++ b/src/utils/getConfig.ts @@ -3,8 +3,9 @@ import defaultsDeep from 'lodash.defaultsdeep'; import path from 'path'; import fs from 'fs'; import { ConfigOptions } from './types'; -import { getDefaultConfig } from './validations'; +import { getDefaultConfig, validateShortcode } from './validations'; import tsConfigExist from './tsConfigExist'; +import shortcodes from '../shortcodes'; function getConfig(context?: string): ConfigOptions { const explorerSync = cosmiconfigSync('elder'); @@ -58,6 +59,11 @@ function getConfig(context?: string): ConfigOptions { } } + config.shortcodes.customShortcodes = config.shortcodes.customShortcodes.map((shortcode) => ({ + ...shortcode, + $$meta: { type: 'config', addedBy: 'elder.config.js' }, + })); + return config; } diff --git a/src/utils/index.ts b/src/utils/index.ts index a52fc33a..64c45046 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -13,7 +13,7 @@ import prepareRunHook from './prepareRunHook'; import shuffleArray from './shuffleArray'; import { prepareServer } from './prepareServer'; -import { validateHook, validateRoute, validatePlugin } from './validations'; +import { validateHook, validateRoute, validatePlugin, validateShortcode } from './validations'; import prepareProcessStack from './prepareProcessStack'; import getConfig from './getConfig'; @@ -23,6 +23,7 @@ export { svelteComponent, getHashedSvelteComponents, getUniqueId, + validateShortcode, IntersectionObserver, Page, parseBuildPerf, diff --git a/src/utils/prepareShortcodeParser.ts b/src/utils/prepareShortcodeParser.ts index 630bae13..e7342132 100644 --- a/src/utils/prepareShortcodeParser.ts +++ b/src/utils/prepareShortcodeParser.ts @@ -32,6 +32,7 @@ function prepareShortcodeParser({ query, helpers, settings, + plugin: shortcode.plugin, }); if (css) { diff --git a/src/utils/types.ts b/src/utils/types.ts index 10843612..b38a63c2 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -44,6 +44,11 @@ export type ConfigOptions = { }; typescript: boolean; worker: boolean; + shortcodes: { + openPattern: string; + closePattern: string; + customShortcodes: ShortcodeDefs; + }; }; type Internal = { @@ -109,6 +114,7 @@ export type PluginOptions = { routes?: RoutesOptions; hooks: Array; config?: Object; + shortcodes?: ShortcodeDefs; }; // eslint-disable-next-line no-undef @@ -130,7 +136,11 @@ export interface ComponentPayload { export interface ShortcodeDef { shortcode: string; run: (any) => ShortcodeResponse | Promise; - plugin?: any; // plugin closure scope? + plugin?: any; // reference to the plugin closure scope. + $$meta: { + addedBy: string; + type: string; + }; } export interface ShortcodeResponse { diff --git a/src/utils/validations.ts b/src/utils/validations.ts index 0f677f99..43108975 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -1,5 +1,5 @@ import * as yup from 'yup'; -import type { ConfigOptions, PluginOptions } from './types'; +import type { ConfigOptions, PluginOptions, ShortcodeDef } from './types'; import type { RouteOptions } from '../routes/types'; import type { HookOptions } from '../hookInterface/types'; import hookInterface from '../hookInterface/hookInterface'; @@ -191,6 +191,7 @@ const pluginSchema = yup.object({ .default({}) .notRequired() .label('(optional) An object of default configs. These will be used when none are set in their elder.config.js.'), + shortcodes: yup.array().of(shortcodeSchema).notRequired().default([]).label('Array of shortcodes'), }); const hookSchema = yup @@ -297,10 +298,30 @@ function validateHook(hook): HookOptions | false { } } +function validateShortcode(shortcode): ShortcodeDef | false { + try { + shortcodeSchema.validateSync(shortcode); + const validated = shortcodeSchema.cast(shortcode); + return validated; + } catch (err) { + if (shortcode && shortcode.$$meta && shortcode.$$meta.type === 'plugin') { + console.error( + `Plugin ${shortcode.$$meta.addedBy} uses a shortcode, but it is ignored due to error(s). Please create a ticket with that plugin so the author can investigate it.`, + err.errors, + err.value, + ); + } else { + console.error(`Hook ignored due to error(s).`, err.errors, err.value); + } + return false; + } +} + export { validateRoute, validatePlugin, validateHook, + validateShortcode, // validateConfig, getDefaultConfig, configSchema, From cbda1002e6c9a373884ac9cc7aaa10cbfb665516 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 15 Sep 2020 16:18:03 -0400 Subject: [PATCH 11/75] =?UTF-8?q?chore:=20=F0=9F=A4=96=20remove=20duplicat?= =?UTF-8?q?e=20console=20log?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Elder.ts | 92 ++++++++++++++++++++++++++--- src/hookInterface/hookInterface.ts | 1 + src/hooks.ts | 6 +- src/shortcodes.ts | 22 ++++++- src/utils/Page.ts | 1 - src/utils/getConfig.ts | 5 -- src/utils/prepareShortcodeParser.ts | 42 ++++++++++--- src/utils/validations.ts | 1 - 8 files changed, 144 insertions(+), 26 deletions(-) diff --git a/src/Elder.ts b/src/Elder.ts index ed80153c..451317b2 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -101,6 +101,14 @@ class Elder { this.settings.debug.automagic = false; } + this.data = {}; + this.hookInterface = hookInterface; + + this.query = {}; + this.allRequests = []; + this.serverLookupObject = {}; + this.errors = []; + /** * Plugin initalization * * Collect plugin routes @@ -257,6 +265,13 @@ class Elder { }); } + /** + * Finalize Routes + * Add in user routes + * Add in plugin routes + * Validate them + */ + // add meta to routes and collect hooks from routes const userRoutesJsFile = routes(this.settings); @@ -287,6 +302,13 @@ class Elder { this.routes = validatedRoutes; + /** + * Finalize hooks + * Import User Hooks.js + * Validate Hooks + * Filter out hooks that are disabled. + */ + let hooksJs: Array = []; const hookSrcPath = path.resolve(process.cwd(), srcFolder, './hooks.js'); const hookBuildPath = path.resolve(process.cwd(), buildFolder, './hooks.js'); @@ -344,6 +366,7 @@ class Elder { }, })); + // validate hooks this.hooks = [...elderJsHooks, ...pluginHooks, ...hooksJs] .map((hook) => validateHook(hook)) .filter((Boolean as any) as ExcludesFalse); @@ -352,18 +375,71 @@ class Elder { this.hooks = this.hooks.filter((h) => !this.settings.hooks.disable.includes(h.name)); } + /** + * Finalize Shortcodes + * Import User Shortcodes.js + * Validate Shortcodes + */ + + let shortcodesJs: ShortcodeDefs = []; + const shortcodeSrcPath = path.resolve(process.cwd(), srcFolder, './shortcodes.js'); + const shortcodeBuildPath = path.resolve(process.cwd(), buildFolder, './shortcodes.js'); + + if (this.settings.debug.automagic) { + console.log( + `debug.automagic::Attempting to automagically pull in shortcodes from your ${shortcodeSrcPath} ${ + buildFolder ? `with a fallback to ${shortcodeBuildPath}` : '' + }`, + ); + } + try { + const shortcodes: ShortcodeDefs = config.typescript + ? require(shortcodeSrcPath).default + : require(shortcodeSrcPath); + shortcodesJs = shortcodes.map((shortcode) => ({ + ...shortcode, + $$meta: { + type: 'shortcodes.js', + addedBy: 'shortcodes.js', + }, + })); + } catch (err) { + if (err.code === 'MODULE_NOT_FOUND') { + if (buildFolder && buildFolder.length > 0) { + try { + const shortcodeBuildFile: ShortcodeDefs = config.typescript + ? require(shortcodeBuildPath).default + : require(shortcodeBuildPath); + shortcodesJs = shortcodeBuildFile.map((shortcode) => ({ + ...shortcode, + $$meta: { + type: 'shortcodes.js', + addedBy: 'shortcodes.js', + }, + })); + } catch (err2) { + if (err2.code !== 'MODULE_NOT_FOUND') { + console.error(err); + } + } + } else if (this.settings.debug.automagic) { + console.log(`No luck finding that hooks file. You can add one at ${shortcodeBuildPath}`); + } + } else { + console.error(err); + } + } + // validate shortcodes - this.shortcodes = [...elderJsShortcodes, ...pluginShortcodes, ...config.shortcodes.customShortcodes] + this.shortcodes = [...elderJsShortcodes, ...pluginShortcodes, ...shortcodesJs] .map((shortcode) => validateShortcode(shortcode)) .filter((Boolean as any) as ExcludesFalse); - this.data = {}; - this.hookInterface = hookInterface; - - this.query = {}; - this.allRequests = []; - this.serverLookupObject = {}; - this.errors = []; + /** + * + * Almost ready for customize hooks and bootstrap + * Just wire up the last few things. + */ this.helpers = { permalinks: permalinks({ routes: this.routes, settings: this.settings }), diff --git a/src/hookInterface/hookInterface.ts b/src/hookInterface/hookInterface.ts index f761f26e..0ba70f07 100644 --- a/src/hookInterface/hookInterface.ts +++ b/src/hookInterface/hookInterface.ts @@ -168,6 +168,7 @@ export const hookInterface: Array = [ 'customJsStack', 'routeHtml', 'shortcodes', + 'allRequests', ], mutable: ['errors', 'routeHtml', 'cssStack', 'headStack', 'customJsStack'], context: `Executed after the route's html has been compiled, but before the layout html has been compiled.`, diff --git a/src/hooks.ts b/src/hooks.ts index fed94c70..66b64cbe 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -46,6 +46,7 @@ const hooks: Array = [ customJsStack, routeHtml, shortcodes, + allRequests, }) => { const ShortcodeParser = prepareShortcodeParser({ shortcodes, @@ -57,6 +58,7 @@ const hooks: Array = [ cssStack, headStack, customJsStack, + allRequests, }); const html = await ShortcodeParser.parse(routeHtml); @@ -191,8 +193,8 @@ const hooks: Array = [ name: 'elderConsoleLogErrors', description: 'Log any errors to the console.', priority: 100, - run: async ({ errors }) => { - console.error(errors); + run: async ({ errors, request }) => { + console.error(request.permalink, errors); }, }, { diff --git a/src/shortcodes.ts b/src/shortcodes.ts index 43e12aef..b9ed52db 100644 --- a/src/shortcodes.ts +++ b/src/shortcodes.ts @@ -5,11 +5,29 @@ const shortcodes: ShortcodeDefs = [ shortcode: 'svelteComponent', run: async ({ props, helpers }) => { if (!props.name) throw new Error(`svelteComponent shortcode requires a name="" property.`); + + let parsedProps = {}; + try { + parsedProps = JSON.parse(props.props); + } catch { + console.error( + `Can't parse ${props.name} svelteComponent prop=${props.props} to JSON. It needs to be serializable.`, + ); + } + + let parsedOptions = {}; + try { + parsedOptions = JSON.parse(props.options); + } catch { + console.error( + `Can't parse ${props.name} svelteComponent options=${props.options} to JSON. It needs to be serializable.`, + ); + } return { html: helpers.inlineSvelteComponent({ name: props.name, - props: props.props || {}, - options: props.options || {}, + props: parsedProps, + options: parsedOptions, }), }; }, diff --git a/src/utils/Page.ts b/src/utils/Page.ts index b2f113a2..8b9b36df 100644 --- a/src/utils/Page.ts +++ b/src/utils/Page.ts @@ -104,7 +104,6 @@ const buildPage = async (page) => { await page.runHook('error', page); } } catch (err) { - console.log(err, page.permalink); page.errors.push(err); await page.runHook('error', page); } diff --git a/src/utils/getConfig.ts b/src/utils/getConfig.ts index 6d714a98..cb6364b6 100644 --- a/src/utils/getConfig.ts +++ b/src/utils/getConfig.ts @@ -59,11 +59,6 @@ function getConfig(context?: string): ConfigOptions { } } - config.shortcodes.customShortcodes = config.shortcodes.customShortcodes.map((shortcode) => ({ - ...shortcode, - $$meta: { type: 'config', addedBy: 'elder.config.js' }, - })); - return config; } diff --git a/src/utils/prepareShortcodeParser.ts b/src/utils/prepareShortcodeParser.ts index e7342132..d8dc3642 100644 --- a/src/utils/prepareShortcodeParser.ts +++ b/src/utils/prepareShortcodeParser.ts @@ -1,4 +1,6 @@ -const ShortcodeParser = require('@elderjs/shortcodes'); +import ShortcodeParser from '@elderjs/shortcodes'; +import createReadOnlyProxy from './createReadOnlyProxy'; +// TODO: Needs TS magic. function prepareShortcodeParser({ shortcodes, @@ -7,6 +9,7 @@ function prepareShortcodeParser({ settings, request, query, + allRequests, cssStack, headStack, customJsStack, @@ -27,12 +30,37 @@ function prepareShortcodeParser({ const { html, css, js, head } = await shortcode.run({ props, content, - data, - request, - query, - helpers, - settings, plugin: shortcode.plugin, + data: createReadOnlyProxy( + data, + 'data', + `${shortcode.shortcode} defined by ${JSON.stringify(shortcode.$$meta)}`, + ), + request: createReadOnlyProxy( + request, + 'request', + `${shortcode.shortcode} defined by ${JSON.stringify(shortcode.$$meta)}`, + ), + query: createReadOnlyProxy( + query, + 'query', + `${shortcode.shortcode} defined by ${JSON.stringify(shortcode.$$meta)}`, + ), + helpers: createReadOnlyProxy( + helpers, + 'helpers', + `${shortcode.shortcode} defined by ${JSON.stringify(shortcode.$$meta)}`, + ), + settings: createReadOnlyProxy( + settings, + 'settings', + `${shortcode.shortcode} defined by ${JSON.stringify(shortcode.$$meta)}`, + ), + allRequests: createReadOnlyProxy( + allRequests, + 'allRequests', + `${shortcode.shortcode} defined by ${JSON.stringify(shortcode.$$meta)}`, + ), }); if (css) { @@ -53,7 +81,7 @@ function prepareShortcodeParser({ string: head, }); } - return html; + return html || ''; }); }); diff --git a/src/utils/validations.ts b/src/utils/validations.ts index 43108975..86670fa3 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -134,7 +134,6 @@ const configSchema = yup.object({ shortcodes: yup.object({ openPattern: yup.string().default('{{').label('Opening pattern for identifying shortcodes in html output.'), closePattern: yup.string().default('}}').label('closing pattern for identifying shortcodes in html output.'), - customShortcodes: yup.array().default([]).label('An array of custom shortcodes'), }), plugins: yup.object().default({}).label('Used to define Elder.js plugins.'), }); From 7a7f6430e1df21d6102f23fb9c404b95dcbdd6ce Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 15 Sep 2020 16:49:47 -0400 Subject: [PATCH 12/75] =?UTF-8?q?test:=20=F0=9F=92=8D=20Get=20tests=20work?= =?UTF-8?q?ing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Elder.ts | 37 +- src/__tests__/Elder.spec.ts | 3 + .../__snapshots__/Elder.spec.ts.snap | 780 +----------------- .../__snapshots__/hooks.spec.ts.snap | 18 +- src/__tests__/hooks.spec.ts | 49 +- src/utils/__tests__/Page.spec.ts | 12 +- .../__tests__/__snapshots__/Page.spec.ts.snap | 3 + .../__snapshots__/validations.spec.ts.snap | 114 +++ src/utils/__tests__/index.spec.ts | 1 + src/utils/__tests__/validations.spec.ts | 5 + src/utils/validations.ts | 2 +- 11 files changed, 250 insertions(+), 774 deletions(-) diff --git a/src/Elder.ts b/src/Elder.ts index 451317b2..7b56f725 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -57,8 +57,6 @@ class Elder { runHook: (string, Object) => Promise; - hookInterface: any; - query: QueryOptions; allRequests: Array; @@ -101,14 +99,6 @@ class Elder { this.settings.debug.automagic = false; } - this.data = {}; - this.hookInterface = hookInterface; - - this.query = {}; - this.allRequests = []; - this.serverLookupObject = {}; - this.errors = []; - /** * Plugin initalization * * Collect plugin routes @@ -256,13 +246,15 @@ class Elder { }); } - plugin.shortcodes.forEach((shortcode) => { - shortcode.$$meta = { - type: 'plugin', - addedBy: pluginName, - }; - pluginShortcodes.push(shortcode); - }); + if (plugin.shortcodes && plugin.shortcodes.length > 0) { + plugin.shortcodes.forEach((shortcode) => { + shortcode.$$meta = { + type: 'plugin', + addedBy: pluginName, + }; + pluginShortcodes.push(shortcode); + }); + } } /** @@ -441,6 +433,13 @@ class Elder { * Just wire up the last few things. */ + this.data = {}; + + this.query = {}; + this.allRequests = []; + this.serverLookupObject = {}; + this.errors = []; + this.helpers = { permalinks: permalinks({ routes: this.routes, settings: this.settings }), inlineSvelteComponent, @@ -454,7 +453,7 @@ class Elder { const hooksMinusPlugins = this.hooks.filter((h) => h.$$meta.type !== 'plugin'); this.runHook = prepareRunHook({ hooks: hooksMinusPlugins, - allSupportedHooks: this.hookInterface, + allSupportedHooks: hookInterface, settings: this.settings, }); @@ -463,7 +462,7 @@ class Elder { // we need to rebuild runHook with these customizations. this.runHook = prepareRunHook({ hooks: this.hooks, - allSupportedHooks: this.hookInterface, + allSupportedHooks: hookInterface, settings: this.settings, }); diff --git a/src/__tests__/Elder.spec.ts b/src/__tests__/Elder.spec.ts index 8e3ae1ad..4ea3a714 100644 --- a/src/__tests__/Elder.spec.ts +++ b/src/__tests__/Elder.spec.ts @@ -114,6 +114,7 @@ describe('#Elder', () => { it('plugin found but invalid', async () => { jest.mock('../utils/validations', () => ({ validatePlugin: () => false, + validateShortcode: (i) => i, })); jest.mock('fs-extra', () => ({ existsSync: () => true, @@ -178,6 +179,7 @@ describe('#Elder', () => { validatePlugin: (i) => i, validateHook: (i) => i, validateRoute: (i) => i, + validateShortcode: (i) => i, })); jest.mock('fs-extra', () => ({ existsSync: () => true, @@ -224,6 +226,7 @@ describe('#Elder', () => { validatePlugin: (i) => i, validateHook: (i) => i, validateRoute: (i) => i, + validateShortcode: (i) => i, })); jest.mock('fs-extra', () => ({ existsSync: () => true, diff --git a/src/__tests__/__snapshots__/Elder.spec.ts.snap b/src/__tests__/__snapshots__/Elder.spec.ts.snap index 5b742558..20345939 100644 --- a/src/__tests__/__snapshots__/Elder.spec.ts.snap +++ b/src/__tests__/__snapshots__/Elder.spec.ts.snap @@ -14,373 +14,6 @@ Elder { "test-b": [Function], }, }, - "hookInterface": Array [ - Object { - "advanced": true, - "context": "Used to modify what hooks can mutate which properties all hooks.", - "experimental": true, - "hook": "customizeHooks", - "location": "Elder.ts", - "mutable": Array [ - "hookInterface", - "errors", - ], - "props": Array [ - "hookInterface", - "errors", - ], - "use": "

    This hook receives the hookInterface.ts file which defines all hook interactions. You can customize all 'props' and 'mutable' of - all hooks by using this hook. This is a power user hook and unless you know Elder.js internals don't mess with it.

    ", - }, - Object { - "advanced": false, - "context": "Routes, plugins, and hooks have been collected and validated.", - "experimental": false, - "hook": "bootstrap", - "location": "Elder.ts", - "mutable": Array [ - "errors", - "helpers", - "data", - "settings", - "query", - ], - "props": Array [ - "helpers", - "data", - "settings", - "routes", - "hooks", - "query", - "errors", - ], - "use": "
      -
    • Often used to populate the empty query object with a database or API connection as query is passed to the all() function which is used to generate request objects.
    • -
    • Internally used to automatically populate the helpers object with the helpers found in './src/helpers/index.js'.
    • -
    • Can be used to set information on the data object that is needed throughout the entire lifecycle. (sitewide settings)
    • -
    ", - }, - Object { - "advanced": false, - "context": "allRequests which represents all of the request objects have been collected from route and plugins. This makes the 'allRequests' array mutable.", - "experimental": false, - "hook": "allRequests", - "location": "Elder.ts", - "mutable": Array [ - "errors", - "allRequests", - ], - "props": Array [ - "helpers", - "data", - "settings", - "allRequests", - "routes", - "query", - "errors", - ], - "use": "

    The main use here is to allow users to adjust the requests that Elder.js is aware of.

    -
      -
    • This could be used for incremental builds. By filtering and overwriting the allRequests array building just a single route or even a single request is doable.
    • -
    • This hook is used by elderjs-plugin-random to register temporary requests that it later intercepts to redirect to a random page of a route.
    • -
    • This hook is used by elderjs-plugin-markdown to register processed markdown files and their slugs Elder.js
    • -
    - -

    NOTE: If you are modifying 'allRequests' you must set 'request.route' key for each request.

    ", - }, - Object { - "advanced": true, - "context": "Fired upon a request that originates from the express/polka middleware version of Elder.js. The hook has access to \\"req\\" and \\"next\\" common in express like middleware.", - "experimental": true, - "hook": "middleware", - "location": "prepareServer.ts", - "mutable": Array [ - "errors", - "request", - "query", - "helpers", - "data", - "route", - "settings", - "allRequests", - "routes", - "req", - "next", - "res", - ], - "props": Array [ - "errors", - "request", - "query", - "helpers", - "data", - "route", - "settings", - "allRequests", - "routes", - "req", - "next", - "res", - ], - "use": "

    If you're looking to use Elder.js with express/polka to build a server rendered website, then you'll be interested in this hook as it includes the familiar 'req' and 'next' objects as often used in Express middleware.

    -
      -
    • This hook could be used to set user or session information stored on the 'req' prop anywhere it is needed such as on the Elder.js 'request' object or 'data' object.
    • -
    • If you're looking to pass in details about the query string deeper into your application, you could use this hook to do so.
    • -
    • Anything you'd use an Express 'req' or 'next' for you can do and customize other parts of the Elder.js on this hook.
    • -
    ", - }, - Object { - "advanced": false, - "context": "This is executed at the beginning the request object being processed.", - "experimental": false, - "hook": "request", - "location": "Page.ts", - "mutable": Array [ - "errors", - "helpers", - "data", - "settings", - "request", - "route", - ], - "props": Array [ - "helpers", - "data", - "settings", - "request", - "allRequests", - "query", - "errors", - "routes", - "route", - ], - "use": "

    This hook gives access to the entire state of a request lifecycle before it starts.

    -
      -
    • Primarily used to set 'request' specific data that is required by all routes so doesn't make sense to share across multiple 'data' functions.
    • -
    • If you have helper functions that need a closure isolated to a specific page generation lifecycle here is where you should attach them.
    • -
    • If you need to programmatically change the route, you can do so here. This is how the elderjs-plugin-random works.
    • -
    • This hook is commonly uses by plugins that need to add route level data that is dependent on the request to populate.
    • -
    - ", - }, - Object { - "advanced": true, - "context": "This hook is run after the route's \\"data\\" function has executed.", - "experimental": false, - "hook": "data", - "location": "Page.ts", - "mutable": Array [ - "errors", - "data", - "cssStack", - "headStack", - "beforeHydrateStack", - "hydrateStack", - "customJsStack", - "footerStack", - ], - "props": Array [ - "data", - "request", - "errors", - "helpers", - "query", - "routes", - "cssStack", - "headStack", - "beforeHydrateStack", - "hydrateStack", - "customJsStack", - "footerStack", - "settings", - ], - "use": "

    This hook is mainly used by plugins/hooks to offer functionality at the route level that is dependent on the route's \\"data\\" function has returning but isn't suitable to live in multiple data function across many routes due to code duplication.

    -

    Examples of things we (ElderGuide.com) have done or have seen users do:

    -
      -
    • LD+JSON: Plugins/hooks that add LD+JSON may need the a route's \\"data\\" function to be executed before they have the data needed to run.
    • -
    • Breadcrumbs: Plugins/hooks that add breadcrumbs may be dependent on the \\"data\\" function of a route.
    • -
    • Table Of Contents: Plugins/hooks that automatically generate a table of contents will be dependent on data from a route's data function.
    • -
    • Reference Plugins: Plugins/hooks that collect references from content and add them to the footer of the page content.
    • -
    • Last Updated Data: Determining the last updated date for a page is often better to do in a central place instead of in many \\"data\\" functions.
    • -
    -

    Stacks are made available here so that strings can be added to the head or footer of the page easily.

    - ", - }, - Object { - "advanced": true, - "context": "Executed just before processing all of the stacks into strings.", - "experimental": false, - "hook": "stacks", - "location": "Page.ts", - "mutable": Array [ - "errors", - "cssStack", - "headStack", - "beforeHydrateStack", - "hydrateStack", - "customJsStack", - "footerStack", - ], - "props": Array [ - "helpers", - "data", - "settings", - "request", - "query", - "errors", - "cssStack", - "headStack", - "beforeHydrateStack", - "hydrateStack", - "customJsStack", - "footerStack", - ], - "use": "

    Elder.js uses 'stacks' to manage it's string concatenation. If you are unfamiliar, stacks are basically an array of strings, with a priority, and some meta data. This hook let's you manipulate or view the stacks before they are written to the page and is designed for use by plugins.

    -

    This hook will mainly be used when you need to add arbitrary strings to the footer. In most cases, users should be using <svelte:head></svelte:head> to add content to the head.

    -
      -
    • headStack: Internally all content used in are added to the head stack. If you were looking to add ld+json to the page, you could do it here. If you're looking to write <title> tags, we recommend doing it within Svelte templates unless you are writing a plugin in which case you may want to also look at the 'head' hook.
    • -
    • cssStack: The 'cssStack' represents all of the css strings emitted by the SSR Svelte components. Plugins can add css here (such as critical path CSS), but we recommend users add them directly in Svelte files. Note: Do not wrap strings added to the stack in <style>.
    • -
    • beforeHydrateStack: default this stack includes a polyfill for intersection observer and systemjs for loading svelte. This stack is not run unless there are Svelte components to be hydrated.
    • -
    • hydrateStack: the hydrateStack contains strings which represent all of the root svelte components which will be hydrated.
    • -
    • customJsStack: Used to add custom JS to the site. This is done after the Svelte components are written to the page.
    • -
    • footerStack: the footerStack which is an array of html or html friendly strings that will be written to the footer. This is generally the ideal place for plugins to add Analytics scripts as it fires after all other JS.
    • -
    - ", - }, - Object { - "advanced": true, - "context": "Executed just before writing the tag to the page.", - "experimental": false, - "hook": "head", - "location": "Page.ts", - "mutable": Array [ - "errors", - "headString", - ], - "props": Array [ - "helpers", - "data", - "settings", - "request", - "headString", - "query", - "errors", - ], - "use": "

    This hook's headSting represents everything that will be written to <head> tag.

    -

    There are many possible SEO uses to this hook, especially for plugins. That said, we recommend users who want to set common SEO elements such as tags <title> and meta descriptions programatically to do it from within Svelte templates using the <svelte:head></svelte:head> tag. Chances are you won't need this field unless you're a power user and need access to the raw head.

    ", - }, - Object { - "advanced": true, - "context": "This is where Elder.js merges the html from the Svelte layout with stacks and wraps it in an tag.", - "experimental": false, - "hook": "compileHtml", - "location": "Page.ts", - "mutable": Array [ - "errors", - "htmlString", - ], - "props": Array [ - "helpers", - "data", - "request", - "headString", - "footerString", - "layoutHtml", - "htmlString", - ], - "use": "

    This stack should only be used when you need to have full control over the <html> document. Make sure if you use this to add 'elderCompileHtml' to the 'hooks.disable' array in your elder.config.js or your template will be overwritten.

    ", - }, - Object { - "advanced": false, - "context": "Executed when all of the html has been compiled.", - "experimental": false, - "hook": "html", - "location": "Page.ts", - "mutable": Array [ - "errors", - "htmlString", - ], - "props": Array [ - "helpers", - "data", - "settings", - "request", - "htmlString", - "query", - "errors", - ], - "use": "

    This hook receives the full html of the document. With great power comes great responsibility.

    -
      -
    • Can be used to compress the html/css/js.
    • -
    • Could be used to programmatically extract h2/h3 tags and build/inject a table of contents with something like Cheeriojs.
    • -
    • If you need to modify the final html output, here is where you can do it.
    • -
    ", - }, - Object { - "advanced": false, - "context": "This hook marks the end of the request lifecycle.", - "experimental": false, - "hook": "requestComplete", - "location": "Page.ts", - "mutable": Array [ - "errors", - ], - "props": Array [ - "request", - "htmlString", - "query", - "settings", - "errors", - "timings", - "data", - ], - "use": "

    This hook is triggered on an individual 'request object' completing whether Elder.js is being used in the \\"build\\" or a \\"server\\" mode.

    -
      -
    • Internally, Elder.js uses this hook to write html to the \\"public folder\\".
    • -
    • Useful for uploading static html to s3 or another source.
    • -
    • Could also be used to write the output of a route's \\"data\\" function file to help with client site routing if you were so inclined.
    • -
    • This hook may also be used by plugins to clean up any request specific 'state' they have stored.
    • -
    • By default Elder.js adds a hook here to all server requests that outputs how long the request took to generate. If you want to see detailed output from this hook set debug.speed = true in your config file.
    • -
    ", - }, - Object { - "advanced": false, - "context": "Executed only if the script has encountered errors and they are pushed to the errors array.", - "experimental": false, - "hook": "error", - "location": "Page.ts, build.ts", - "mutable": Array [], - "props": Array [ - "helpers", - "data", - "settings", - "request", - "query", - "errors", - ], - "use": "

    As the script encounters errors, they are collected and presented on this hook at the end of a request and the end of an entire build.

    ", - }, - Object { - "advanced": false, - "context": "Executed after a build is complete", - "experimental": false, - "hook": "buildComplete", - "location": "build.ts", - "mutable": Array [], - "props": Array [ - "helpers", - "data", - "settings", - "timings", - "query", - "errors", - "routes", - ], - "use": "

    Contains whether the build was successful. If not it contains errors for the entire build. Also includes - average performance details, and a granular performance object. Could be used to fire off additional scripts such as generating a sitemap or copying asset files to the public folder.

    -

    Plugins: Because builds are split across processes, a plugin doesn't not have a shared memory space across all processes.

    ", - }, - ], "hooks": Array [ Object { "$$meta": Object { @@ -393,6 +26,17 @@ Elder { "priority": 100, "run": [Function], }, + Object { + "$$meta": Object { + "addedBy": "elder.js", + "type": "internal", + }, + "description": "Builds the shortcode parser, parses shortcodes from the html returned by the route's html and appends anything needed to the stacks.", + "hook": "shortcodes", + "name": "elderProcessShortcodes", + "priority": 50, + "run": [Function], + }, Object { "$$meta": Object { "addedBy": "elder.js", @@ -445,7 +89,7 @@ Elder { "description": "Creates an HTML string out of the Svelte layout and stacks.", "hook": "compileHtml", "name": "elderCompileHtml", - "priority": 100, + "priority": 50, "run": [Function], }, Object { @@ -588,6 +232,16 @@ Elder { }, "typescript": true, }, + "shortcodes": Array [ + Object { + "$$meta": Object { + "addedBy": "elder", + "type": "elder", + }, + "run": [Function], + "shortcode": "svelteComponent", + }, + ], } `; @@ -612,373 +266,6 @@ Elder { "test-b": [Function], }, }, - "hookInterface": Array [ - Object { - "advanced": true, - "context": "Used to modify what hooks can mutate which properties all hooks.", - "experimental": true, - "hook": "customizeHooks", - "location": "Elder.ts", - "mutable": Array [ - "hookInterface", - "errors", - ], - "props": Array [ - "hookInterface", - "errors", - ], - "use": "

    This hook receives the hookInterface.ts file which defines all hook interactions. You can customize all 'props' and 'mutable' of - all hooks by using this hook. This is a power user hook and unless you know Elder.js internals don't mess with it.

    ", - }, - Object { - "advanced": false, - "context": "Routes, plugins, and hooks have been collected and validated.", - "experimental": false, - "hook": "bootstrap", - "location": "Elder.ts", - "mutable": Array [ - "errors", - "helpers", - "data", - "settings", - "query", - ], - "props": Array [ - "helpers", - "data", - "settings", - "routes", - "hooks", - "query", - "errors", - ], - "use": "
      -
    • Often used to populate the empty query object with a database or API connection as query is passed to the all() function which is used to generate request objects.
    • -
    • Internally used to automatically populate the helpers object with the helpers found in './src/helpers/index.js'.
    • -
    • Can be used to set information on the data object that is needed throughout the entire lifecycle. (sitewide settings)
    • -
    ", - }, - Object { - "advanced": false, - "context": "allRequests which represents all of the request objects have been collected from route and plugins. This makes the 'allRequests' array mutable.", - "experimental": false, - "hook": "allRequests", - "location": "Elder.ts", - "mutable": Array [ - "errors", - "allRequests", - ], - "props": Array [ - "helpers", - "data", - "settings", - "allRequests", - "routes", - "query", - "errors", - ], - "use": "

    The main use here is to allow users to adjust the requests that Elder.js is aware of.

    -
      -
    • This could be used for incremental builds. By filtering and overwriting the allRequests array building just a single route or even a single request is doable.
    • -
    • This hook is used by elderjs-plugin-random to register temporary requests that it later intercepts to redirect to a random page of a route.
    • -
    • This hook is used by elderjs-plugin-markdown to register processed markdown files and their slugs Elder.js
    • -
    - -

    NOTE: If you are modifying 'allRequests' you must set 'request.route' key for each request.

    ", - }, - Object { - "advanced": true, - "context": "Fired upon a request that originates from the express/polka middleware version of Elder.js. The hook has access to \\"req\\" and \\"next\\" common in express like middleware.", - "experimental": true, - "hook": "middleware", - "location": "prepareServer.ts", - "mutable": Array [ - "errors", - "request", - "query", - "helpers", - "data", - "route", - "settings", - "allRequests", - "routes", - "req", - "next", - "res", - ], - "props": Array [ - "errors", - "request", - "query", - "helpers", - "data", - "route", - "settings", - "allRequests", - "routes", - "req", - "next", - "res", - ], - "use": "

    If you're looking to use Elder.js with express/polka to build a server rendered website, then you'll be interested in this hook as it includes the familiar 'req' and 'next' objects as often used in Express middleware.

    -
      -
    • This hook could be used to set user or session information stored on the 'req' prop anywhere it is needed such as on the Elder.js 'request' object or 'data' object.
    • -
    • If you're looking to pass in details about the query string deeper into your application, you could use this hook to do so.
    • -
    • Anything you'd use an Express 'req' or 'next' for you can do and customize other parts of the Elder.js on this hook.
    • -
    ", - }, - Object { - "advanced": false, - "context": "This is executed at the beginning the request object being processed.", - "experimental": false, - "hook": "request", - "location": "Page.ts", - "mutable": Array [ - "errors", - "helpers", - "data", - "settings", - "request", - "route", - ], - "props": Array [ - "helpers", - "data", - "settings", - "request", - "allRequests", - "query", - "errors", - "routes", - "route", - ], - "use": "

    This hook gives access to the entire state of a request lifecycle before it starts.

    -
      -
    • Primarily used to set 'request' specific data that is required by all routes so doesn't make sense to share across multiple 'data' functions.
    • -
    • If you have helper functions that need a closure isolated to a specific page generation lifecycle here is where you should attach them.
    • -
    • If you need to programmatically change the route, you can do so here. This is how the elderjs-plugin-random works.
    • -
    • This hook is commonly uses by plugins that need to add route level data that is dependent on the request to populate.
    • -
    - ", - }, - Object { - "advanced": true, - "context": "This hook is run after the route's \\"data\\" function has executed.", - "experimental": false, - "hook": "data", - "location": "Page.ts", - "mutable": Array [ - "errors", - "data", - "cssStack", - "headStack", - "beforeHydrateStack", - "hydrateStack", - "customJsStack", - "footerStack", - ], - "props": Array [ - "data", - "request", - "errors", - "helpers", - "query", - "routes", - "cssStack", - "headStack", - "beforeHydrateStack", - "hydrateStack", - "customJsStack", - "footerStack", - "settings", - ], - "use": "

    This hook is mainly used by plugins/hooks to offer functionality at the route level that is dependent on the route's \\"data\\" function has returning but isn't suitable to live in multiple data function across many routes due to code duplication.

    -

    Examples of things we (ElderGuide.com) have done or have seen users do:

    -
      -
    • LD+JSON: Plugins/hooks that add LD+JSON may need the a route's \\"data\\" function to be executed before they have the data needed to run.
    • -
    • Breadcrumbs: Plugins/hooks that add breadcrumbs may be dependent on the \\"data\\" function of a route.
    • -
    • Table Of Contents: Plugins/hooks that automatically generate a table of contents will be dependent on data from a route's data function.
    • -
    • Reference Plugins: Plugins/hooks that collect references from content and add them to the footer of the page content.
    • -
    • Last Updated Data: Determining the last updated date for a page is often better to do in a central place instead of in many \\"data\\" functions.
    • -
    -

    Stacks are made available here so that strings can be added to the head or footer of the page easily.

    - ", - }, - Object { - "advanced": true, - "context": "Executed just before processing all of the stacks into strings.", - "experimental": false, - "hook": "stacks", - "location": "Page.ts", - "mutable": Array [ - "errors", - "cssStack", - "headStack", - "beforeHydrateStack", - "hydrateStack", - "customJsStack", - "footerStack", - ], - "props": Array [ - "helpers", - "data", - "settings", - "request", - "query", - "errors", - "cssStack", - "headStack", - "beforeHydrateStack", - "hydrateStack", - "customJsStack", - "footerStack", - ], - "use": "

    Elder.js uses 'stacks' to manage it's string concatenation. If you are unfamiliar, stacks are basically an array of strings, with a priority, and some meta data. This hook let's you manipulate or view the stacks before they are written to the page and is designed for use by plugins.

    -

    This hook will mainly be used when you need to add arbitrary strings to the footer. In most cases, users should be using <svelte:head></svelte:head> to add content to the head.

    -
      -
    • headStack: Internally all content used in are added to the head stack. If you were looking to add ld+json to the page, you could do it here. If you're looking to write <title> tags, we recommend doing it within Svelte templates unless you are writing a plugin in which case you may want to also look at the 'head' hook.
    • -
    • cssStack: The 'cssStack' represents all of the css strings emitted by the SSR Svelte components. Plugins can add css here (such as critical path CSS), but we recommend users add them directly in Svelte files. Note: Do not wrap strings added to the stack in <style>.
    • -
    • beforeHydrateStack: default this stack includes a polyfill for intersection observer and systemjs for loading svelte. This stack is not run unless there are Svelte components to be hydrated.
    • -
    • hydrateStack: the hydrateStack contains strings which represent all of the root svelte components which will be hydrated.
    • -
    • customJsStack: Used to add custom JS to the site. This is done after the Svelte components are written to the page.
    • -
    • footerStack: the footerStack which is an array of html or html friendly strings that will be written to the footer. This is generally the ideal place for plugins to add Analytics scripts as it fires after all other JS.
    • -
    - ", - }, - Object { - "advanced": true, - "context": "Executed just before writing the tag to the page.", - "experimental": false, - "hook": "head", - "location": "Page.ts", - "mutable": Array [ - "errors", - "headString", - ], - "props": Array [ - "helpers", - "data", - "settings", - "request", - "headString", - "query", - "errors", - ], - "use": "

    This hook's headSting represents everything that will be written to <head> tag.

    -

    There are many possible SEO uses to this hook, especially for plugins. That said, we recommend users who want to set common SEO elements such as tags <title> and meta descriptions programatically to do it from within Svelte templates using the <svelte:head></svelte:head> tag. Chances are you won't need this field unless you're a power user and need access to the raw head.

    ", - }, - Object { - "advanced": true, - "context": "This is where Elder.js merges the html from the Svelte layout with stacks and wraps it in an tag.", - "experimental": false, - "hook": "compileHtml", - "location": "Page.ts", - "mutable": Array [ - "errors", - "htmlString", - ], - "props": Array [ - "helpers", - "data", - "request", - "headString", - "footerString", - "layoutHtml", - "htmlString", - ], - "use": "

    This stack should only be used when you need to have full control over the <html> document. Make sure if you use this to add 'elderCompileHtml' to the 'hooks.disable' array in your elder.config.js or your template will be overwritten.

    ", - }, - Object { - "advanced": false, - "context": "Executed when all of the html has been compiled.", - "experimental": false, - "hook": "html", - "location": "Page.ts", - "mutable": Array [ - "errors", - "htmlString", - ], - "props": Array [ - "helpers", - "data", - "settings", - "request", - "htmlString", - "query", - "errors", - ], - "use": "

    This hook receives the full html of the document. With great power comes great responsibility.

    -
      -
    • Can be used to compress the html/css/js.
    • -
    • Could be used to programmatically extract h2/h3 tags and build/inject a table of contents with something like Cheeriojs.
    • -
    • If you need to modify the final html output, here is where you can do it.
    • -
    ", - }, - Object { - "advanced": false, - "context": "This hook marks the end of the request lifecycle.", - "experimental": false, - "hook": "requestComplete", - "location": "Page.ts", - "mutable": Array [ - "errors", - ], - "props": Array [ - "request", - "htmlString", - "query", - "settings", - "errors", - "timings", - "data", - ], - "use": "

    This hook is triggered on an individual 'request object' completing whether Elder.js is being used in the \\"build\\" or a \\"server\\" mode.

    -
      -
    • Internally, Elder.js uses this hook to write html to the \\"public folder\\".
    • -
    • Useful for uploading static html to s3 or another source.
    • -
    • Could also be used to write the output of a route's \\"data\\" function file to help with client site routing if you were so inclined.
    • -
    • This hook may also be used by plugins to clean up any request specific 'state' they have stored.
    • -
    • By default Elder.js adds a hook here to all server requests that outputs how long the request took to generate. If you want to see detailed output from this hook set debug.speed = true in your config file.
    • -
    ", - }, - Object { - "advanced": false, - "context": "Executed only if the script has encountered errors and they are pushed to the errors array.", - "experimental": false, - "hook": "error", - "location": "Page.ts, build.ts", - "mutable": Array [], - "props": Array [ - "helpers", - "data", - "settings", - "request", - "query", - "errors", - ], - "use": "

    As the script encounters errors, they are collected and presented on this hook at the end of a request and the end of an entire build.

    ", - }, - Object { - "advanced": false, - "context": "Executed after a build is complete", - "experimental": false, - "hook": "buildComplete", - "location": "build.ts", - "mutable": Array [], - "props": Array [ - "helpers", - "data", - "settings", - "timings", - "query", - "errors", - "routes", - ], - "use": "

    Contains whether the build was successful. If not it contains errors for the entire build. Also includes - average performance details, and a granular performance object. Could be used to fire off additional scripts such as generating a sitemap or copying asset files to the public folder.

    -

    Plugins: Because builds are split across processes, a plugin doesn't not have a shared memory space across all processes.

    ", - }, - ], "hooks": Array [ Object { "$$meta": Object { @@ -991,6 +278,17 @@ Elder { "priority": 100, "run": [Function], }, + Object { + "$$meta": Object { + "addedBy": "elder.js", + "type": "internal", + }, + "description": "Builds the shortcode parser, parses shortcodes from the html returned by the route's html and appends anything needed to the stacks.", + "hook": "shortcodes", + "name": "elderProcessShortcodes", + "priority": 50, + "run": [Function], + }, Object { "$$meta": Object { "addedBy": "elder.js", @@ -1043,7 +341,7 @@ Elder { "description": "Creates an HTML string out of the Svelte layout and stacks.", "hook": "compileHtml", "name": "elderCompileHtml", - "priority": 100, + "priority": 50, "run": [Function], }, Object { @@ -1224,5 +522,15 @@ Elder { }, "typescript": true, }, + "shortcodes": Array [ + Object { + "$$meta": Object { + "addedBy": "elder", + "type": "elder", + }, + "run": [Function], + "shortcode": "svelteComponent", + }, + ], } `; diff --git a/src/__tests__/__snapshots__/hooks.spec.ts.snap b/src/__tests__/__snapshots__/hooks.spec.ts.snap index 85e53502..7d3b90f2 100644 --- a/src/__tests__/__snapshots__/hooks.spec.ts.snap +++ b/src/__tests__/__snapshots__/hooks.spec.ts.snap @@ -70,6 +70,15 @@ Object { } `; +exports[`#hooks elderProcessShortcodes 1`] = ` +Object { + "helpers": Object { + "old": [MockFunction], + "permalink": [MockFunction], + }, +} +`; + exports[`#hooks matchesSnapshot 1`] = ` Array [ Object { @@ -79,6 +88,13 @@ Array [ "priority": 100, "run": [Function], }, + Object { + "description": "Builds the shortcode parser, parses shortcodes from the html returned by the route's html and appends anything needed to the stacks.", + "hook": "shortcodes", + "name": "elderProcessShortcodes", + "priority": 50, + "run": [Function], + }, Object { "description": "Adds to the head.", "hook": "stacks", @@ -111,7 +127,7 @@ Array [ "description": "Creates an HTML string out of the Svelte layout and stacks.", "hook": "compileHtml", "name": "elderCompileHtml", - "priority": 100, + "priority": 50, "run": [Function], }, Object { diff --git a/src/__tests__/hooks.spec.ts b/src/__tests__/hooks.spec.ts index 325d1b4c..0639552c 100644 --- a/src/__tests__/hooks.spec.ts +++ b/src/__tests__/hooks.spec.ts @@ -26,30 +26,42 @@ describe('#hooks', () => { expect(hooks).toMatchSnapshot(); }); it('elderAddExternalHelpers', async () => { - expect(await hooks[0].run({ helpers: { old: jest.fn() }, query: {}, settings: {} })).toMatchSnapshot(); + const hook = hooks.find((h) => h.name === 'elderAddExternalHelpers'); + expect(await hook.run({ helpers: { old: jest.fn() }, query: {}, settings: {} })).toMatchSnapshot(); + }); + it('elderProcessShortcodes', async () => { + const hook = hooks.find((h) => h.name === 'elderAddExternalHelpers'); + expect(await hook.run({ helpers: { old: jest.fn() }, query: {}, settings: {} })).toMatchSnapshot(); + + // TODO!!! }); it('elderAddMetaCharsetToHead', async () => { - expect(await hooks[1].run({ headStack: [] })).toMatchSnapshot(); + const hook = hooks.find((h) => h.name === 'elderAddMetaCharsetToHead'); + expect(await hook.run({ headStack: [] })).toMatchSnapshot(); }); it('elderAddMetaViewportToHead', async () => { - expect(await hooks[2].run({ headStack: [] })).toMatchSnapshot(); + const hook = hooks.find((h) => h.name === 'elderAddMetaViewportToHead'); + expect(await hook.run({ headStack: [] })).toMatchSnapshot(); }); it('elderAddDefaultIntersectionObserver', async () => { + const hook = hooks.find((h) => h.name === 'elderAddDefaultIntersectionObserver'); expect( - await hooks[3].run({ beforeHydrateStack: [], settings: { locations: { intersectionObserverPoly: 'foo' } } }), + await hook.run({ beforeHydrateStack: [], settings: { locations: { intersectionObserverPoly: 'foo' } } }), ).toMatchSnapshot(); - expect(await hooks[3].run({ beforeHydrateStack: [], settings: {} })).toBe(null); + expect(await hook.run({ beforeHydrateStack: [], settings: {} })).toBe(null); }); it('elderAddSystemJs', async () => { + const hook = hooks.find((h) => h.name === 'elderAddSystemJs'); expect( - await hooks[4].run({ beforeHydrateStack: [], headStack: [], settings: { locations: { systemJs: 'foo' } } }), + await hook.run({ beforeHydrateStack: [], headStack: [], settings: { locations: { systemJs: 'foo' } } }), ).toMatchSnapshot(); - expect(await hooks[4].run({ beforeHydrateStack: [], settings: {} })).toBe(null); + expect(await hook.run({ beforeHydrateStack: [], settings: {} })).toBe(null); }); - it('elderCreateHtmlString', async () => { + it('elderCompileHtml', async () => { + const hook = hooks.find((h) => h.name === 'elderCompileHtml'); expect( - await hooks[5].run({ + await hook.run({ request: { route: 'test' }, headString: 'head', footerString: 'footer', @@ -61,11 +73,13 @@ describe('#hooks', () => { }); it('elderConsoleLogErrors', async () => { - expect(await hooks[6].run({ errors: ['foo', 'bar'] })).toBe(undefined); + const hook = hooks.find((h) => h.name === 'elderConsoleLogErrors'); + expect(await hook.run({ request: { permalink: '/foo' }, errors: ['foo', 'bar'] })).toBe(undefined); }); it('elderWriteHtmlFileToPublic', async () => { + const hook = hooks.find((h) => h.name === 'elderWriteHtmlFileToPublic'); expect( - await hooks[7].run({ + await hook.run({ request: { permalink: '/foo' }, htmlString: 'string', errors: [], @@ -73,7 +87,7 @@ describe('#hooks', () => { }), ).toBe(null); expect( - await hooks[7].run({ + await hook.run({ request: { permalink: '/foo' }, htmlString: 'string', errors: [], @@ -81,7 +95,7 @@ describe('#hooks', () => { }), ).toBe(null); expect( - await hooks[7].run({ + await hook.run({ request: { permalink: '/foo' }, htmlString: 'string', errors: [], @@ -90,8 +104,9 @@ describe('#hooks', () => { ).toEqual({ errors: [new Error('Failed to write')] }); }); it('elderDisplayRequestTime', async () => { + const hook = hooks.find((h) => h.name === 'elderDisplayRequestTime'); expect( - await hooks[8].run({ + await hook.run({ request: { permalink: '/foo' }, timings: [ { name: 'foo', duration: 500 }, @@ -102,8 +117,9 @@ describe('#hooks', () => { ).toBe(undefined); }); it('elderShowParsedBuildTimes', async () => { + const hook = hooks.find((h) => h.name === 'elderShowParsedBuildTimes'); expect( - await hooks[9].run({ + await hook.run({ timings: [ [ { name: 'foo', duration: 500 }, @@ -119,8 +135,9 @@ describe('#hooks', () => { ).toBe(undefined); }); it('elderWriteBuildErrors', async () => { + const hook = hooks.find((h) => h.name === 'elderWriteBuildErrors'); expect( - await hooks[10].run({ + await hook.run({ errors: ['error1', 'error2'], settings: { debug: { performance: true } }, }), diff --git a/src/utils/__tests__/Page.spec.ts b/src/utils/__tests__/Page.spec.ts index 68f9efa2..65f14401 100644 --- a/src/utils/__tests__/Page.spec.ts +++ b/src/utils/__tests__/Page.spec.ts @@ -202,13 +202,23 @@ describe('#Page', () => { routes, errors: [], runHook, + shortcodes: [], }; it('initialize and build', async () => { const page = new Page(pageInput); expect(page).toMatchSnapshot(); await page.build(); - expect(hooks).toEqual(['request', 'data', 'stacks', 'head', 'compileHtml', 'html', 'requestComplete']); + expect(hooks).toEqual([ + 'request', + 'data', + 'shortcodes', + 'stacks', + 'head', + 'compileHtml', + 'html', + 'requestComplete', + ]); expect(page).toMatchSnapshot(); }); diff --git a/src/utils/__tests__/__snapshots__/Page.spec.ts.snap b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap index eb9553fa..13d724f8 100644 --- a/src/utils/__tests__/__snapshots__/Page.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap @@ -206,6 +206,7 @@ Page { "typescript": false, "worker": true, }, + "shortcodes": Array [], "uid": "xxxxxxxxxx", } `; @@ -592,6 +593,7 @@ Page { ], }, }, + "routeHtml": undefined, "routes": Object { "content": Object { "$$meta": Object { @@ -668,6 +670,7 @@ Page { "typescript": false, "worker": true, }, + "shortcodes": Array [], "styleTag": "", "timings": Array [], "uid": "xxxxxxxxxx", diff --git a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap index 12283a83..f2e64163 100644 --- a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap @@ -14,6 +14,7 @@ ObjectSchema { "_mutate": undefined, "_nodes": Array [ "plugins", + "shortcodes", "typescript", "build", "server", @@ -779,6 +780,93 @@ ObjectSchema { ], "type": "object", }, + "shortcodes": ObjectSchema { + "_blacklist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "_conditions": Array [], + "_defaultDefault": [Function], + "_deps": Array [], + "_excludedEdges": Array [], + "_exclusive": Object {}, + "_mutate": undefined, + "_nodes": Array [ + "closePattern", + "openPattern", + ], + "_options": Object { + "abortEarly": true, + "recursive": true, + }, + "_type": "object", + "_typeError": [Function], + "_whitelist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "fields": Object { + "closePattern": StringSchema { + "_blacklist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "_conditions": Array [], + "_default": "}}", + "_deps": Array [], + "_exclusive": Object {}, + "_label": "closing pattern for identifying shortcodes in html output.", + "_mutate": undefined, + "_options": Object { + "abortEarly": true, + "recursive": true, + }, + "_type": "string", + "_typeError": [Function], + "_whitelist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "tests": Array [], + "transforms": Array [ + [Function], + ], + "type": "string", + }, + "openPattern": StringSchema { + "_blacklist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "_conditions": Array [], + "_default": "{{", + "_deps": Array [], + "_exclusive": Object {}, + "_label": "Opening pattern for identifying shortcodes in html output.", + "_mutate": undefined, + "_options": Object { + "abortEarly": true, + "recursive": true, + }, + "_type": "string", + "_typeError": [Function], + "_whitelist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "tests": Array [], + "transforms": Array [ + [Function], + ], + "type": "string", + }, + }, + "tests": Array [], + "transforms": Array [ + [Function], + ], + "type": "object", + }, "siteUrl": StringSchema { "_blacklist": RefSet { "list": Set {}, @@ -1151,6 +1239,7 @@ ObjectSchema { "_exclusive": Object {}, "_mutate": undefined, "_nodes": Array [ + "shortcodes", "config", "hooks", "routes", @@ -1346,6 +1435,31 @@ ObjectSchema { ], "type": "object", }, + "shortcodes": SchemaType { + "_blacklist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "_conditions": Array [], + "_default": Array [], + "_deps": Array [], + "_exclusive": Object {}, + "_label": "Array of shortcodes", + "_mutate": undefined, + "_options": Object { + "abortEarly": true, + "recursive": true, + }, + "_type": "mixed", + "_typeError": [Function], + "_whitelist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "tests": Array [], + "transforms": Array [], + "type": "mixed", + }, }, "tests": Array [], "transforms": Array [ diff --git a/src/utils/__tests__/index.spec.ts b/src/utils/__tests__/index.spec.ts index 3495c53e..0c7ca475 100644 --- a/src/utils/__tests__/index.spec.ts +++ b/src/utils/__tests__/index.spec.ts @@ -7,6 +7,7 @@ test('includes all', () => { 'svelteComponent', 'getHashedSvelteComponents', 'getUniqueId', + 'validateShortcode', 'IntersectionObserver', 'Page', 'parseBuildPerf', diff --git a/src/utils/__tests__/validations.spec.ts b/src/utils/__tests__/validations.spec.ts index bfecfa7e..0afbb72c 100644 --- a/src/utils/__tests__/validations.spec.ts +++ b/src/utils/__tests__/validations.spec.ts @@ -54,6 +54,10 @@ describe('#validations', () => { prefix: '', }, typescript: false, + shortcodes: { + closePattern: '}}', + openPattern: '{{', + }, }; test('getDefaultConfig', () => { expect(getDefaultConfig()).toEqual(defaultConfig); @@ -101,6 +105,7 @@ describe('#validations', () => { description: 'just for testing', init: jest.fn(), // FIXME: init should be required or test should allow not defined hooks: [1, 2, 3], // TODO: nested hook validation? + shortcodes: [], }; expect(validatePlugin(validPlugin)).toEqual({ ...validPlugin, config: {}, routes: {} }); expect(validatePlugin({ ...validPlugin, config: defaultConfig })).toEqual({ diff --git a/src/utils/validations.ts b/src/utils/validations.ts index 86670fa3..4cf76ed0 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -190,7 +190,7 @@ const pluginSchema = yup.object({ .default({}) .notRequired() .label('(optional) An object of default configs. These will be used when none are set in their elder.config.js.'), - shortcodes: yup.array().of(shortcodeSchema).notRequired().default([]).label('Array of shortcodes'), + shortcodes: yup.mixed().notRequired().default([]).label('Array of shortcodes'), }); const hookSchema = yup From ce1b7495fa5a2e72c396b113de967676bdcc535a Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 15 Sep 2020 17:01:30 -0400 Subject: [PATCH 13/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20reverse=20stack=20?= =?UTF-8?q?and=20hook=20priority=20so=20100=20is=20highest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks.ts | 22 +++++++++---------- .../__tests__/prepareProcessStack.spec.ts | 2 +- src/utils/prepareProcessStack.ts | 2 +- src/utils/prepareRunHook.ts | 2 +- src/utils/validations.ts | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/hooks.ts b/src/hooks.ts index 66b64cbe..af79683d 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -10,7 +10,7 @@ const hooks: Array = [ hook: 'bootstrap', name: 'elderAddExternalHelpers', description: 'Adds external helpers to helpers object', - priority: 100, + priority: 1, run: async ({ helpers, query, settings }) => { let additionalHelpers = {}; try { @@ -75,7 +75,7 @@ const hooks: Array = [ hook: 'stacks', name: 'elderAddMetaCharsetToHead', description: `Adds to the head.`, - priority: 1, + priority: 100, run: async ({ headStack }) => { return { headStack: [ @@ -83,7 +83,7 @@ const hooks: Array = [ { source: 'elderAddMetaCharsetToHead', string: ``, - priority: 1, + priority: 100, }, ], }; @@ -93,7 +93,7 @@ const hooks: Array = [ hook: 'stacks', name: 'elderAddMetaViewportToHead', description: `Adds to the head.`, - priority: 10, + priority: 90, run: async ({ headStack }) => { return { headStack: [ @@ -101,7 +101,7 @@ const hooks: Array = [ { source: 'elderAddMetaViewportToHead', string: ``, - priority: 10, + priority: 90, }, ], }; @@ -111,7 +111,7 @@ const hooks: Array = [ hook: 'stacks', name: 'elderAddDefaultIntersectionObserver', description: 'Sets up the default polyfill for the intersection observer', - priority: 1, + priority: 100, run: async ({ beforeHydrateStack, settings }) => { if (settings && settings.locations && {}.hasOwnProperty.call(settings.locations, 'intersectionObserverPoly')) { if (settings.locations.intersectionObserverPoly) { @@ -126,7 +126,7 @@ const hooks: Array = [ document.getElementsByTagName('head')[0].appendChild(script); }; `, - priority: 1, + priority: 100, }, ...beforeHydrateStack, ], @@ -153,7 +153,7 @@ const hooks: Array = [ { source: 'elderAddSystemJs', string: ``, - priority: 2, + priority: 99, }, ...beforeHydrateStack, ], @@ -162,7 +162,7 @@ const hooks: Array = [ { source: 'elderAddSystemJs', string: ``, - priority: 2, + priority: 99, }, ...headStack, ], @@ -192,7 +192,7 @@ const hooks: Array = [ hook: 'error', name: 'elderConsoleLogErrors', description: 'Log any errors to the console.', - priority: 100, + priority: 1, run: async ({ errors, request }) => { console.error(request.permalink, errors); }, @@ -201,7 +201,7 @@ const hooks: Array = [ hook: 'requestComplete', name: 'elderWriteHtmlFileToPublic', description: 'Write the html output to public.', - priority: 100, + priority: 1, run: async ({ settings, request, htmlString, errors }) => { if (settings.build) { const file = path.resolve(process.cwd(), `${settings.locations.public}${request.permalink}/index.html`); diff --git a/src/utils/__tests__/prepareProcessStack.spec.ts b/src/utils/__tests__/prepareProcessStack.spec.ts index 57dd7f51..5d9fad64 100644 --- a/src/utils/__tests__/prepareProcessStack.spec.ts +++ b/src/utils/__tests__/prepareProcessStack.spec.ts @@ -30,5 +30,5 @@ test('#prepareProcessStack', () => { }, }; const processStackFn = prepareProcessStack(page); - expect(processStackFn('testStack')).toEqual('-1--10--50-'); + expect(processStackFn('testStack')).toEqual('-50--10--1-'); }); diff --git a/src/utils/prepareProcessStack.ts b/src/utils/prepareProcessStack.ts index b6a09872..ccd606b1 100644 --- a/src/utils/prepareProcessStack.ts +++ b/src/utils/prepareProcessStack.ts @@ -3,7 +3,7 @@ function prepareProcessStack(page) { page.perf.start(`stack.${name}`); const str = page[name] .map((s) => ({ ...s, priority: s.priority || 50 })) - .sort((a, b) => a.priority - b.priority) + .sort((a, b) => b.priority - a.priority) .reduce((out, cv, i, arr) => { if (page.settings.debug && page.settings.debug.stacks) { console.log(`stack.${name}`, arr, i); diff --git a/src/utils/prepareRunHook.ts b/src/utils/prepareRunHook.ts index ff22ba05..9deda87b 100644 --- a/src/utils/prepareRunHook.ts +++ b/src/utils/prepareRunHook.ts @@ -30,7 +30,7 @@ function prepareRunHook({ hooks, allSupportedHooks, settings }) { const theseHooks = hooks.filter((h) => h.hook === hookName); if (theseHooks && Array.isArray(theseHooks) && theseHooks.length > 0) { // lower priority is more important. - const hookList = theseHooks.sort((a, b) => a.priority - b.priority); + const hookList = theseHooks.sort((a, b) => b.priority - a.priority); if (settings && settings.debug && settings.debug.hooks) { console.log(`Hooks registered on ${hookName}:`, hookList); diff --git a/src/utils/validations.ts b/src/utils/validations.ts index 4cf76ed0..b8ca4df2 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -212,7 +212,7 @@ const hookSchema = yup .optional() .default(50) .label( - 'The priority level a hook should run at. Elder.js hooks run at 1 or 100 where 1 is the highest priorty and 100 is the lowest priority.', + 'The priority level a hook should run at. Elder.js hooks run here 100 is the highest priority and 1 is the lowest priority.', ), run: yup .mixed() From 3957ad57dfc0e365bbc4ae8a10c59a4ee517a202 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 15 Sep 2020 17:03:47 -0400 Subject: [PATCH 14/75] 0.1.6-next.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 68c13073..304fcf7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.5", + "version": "0.1.6-next.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 20769e50..485e02c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.5", + "version": "0.1.6-next.0", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From fb65ca8e897122c2a604317c9b89bfc37cc8b3c5 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Wed, 16 Sep 2020 11:59:20 -0400 Subject: [PATCH 15/75] =?UTF-8?q?fix:=20=F0=9F=90=9B=20fix=20hook=20interf?= =?UTF-8?q?ace=20missing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Elder.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Elder.ts b/src/Elder.ts index 7b56f725..bbbca11a 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -71,6 +71,8 @@ class Elder { builder: any; + hookInterface: any; + shortcodes: ShortcodeDefs; constructor({ context, worker = false }) { @@ -439,6 +441,7 @@ class Elder { this.allRequests = []; this.serverLookupObject = {}; this.errors = []; + this.hookInterface = hookInterface; this.helpers = { permalinks: permalinks({ routes: this.routes, settings: this.settings }), From f571f03aef3ef5c1efaeb372cce465a6c8f8abc8 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Wed, 16 Sep 2020 11:59:48 -0400 Subject: [PATCH 16/75] =?UTF-8?q?fix:=20=F0=9F=90=9B=20begin=20depreciatin?= =?UTF-8?q?g=20routeHTML=20for=20routeHtml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/Page.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/Page.ts b/src/utils/Page.ts index 8b9b36df..a2f454f9 100644 --- a/src/utils/Page.ts +++ b/src/utils/Page.ts @@ -59,7 +59,8 @@ const buildPage = async (page) => { helpers: page.helpers, settings: page.settings, request: page.request, - routeHTML: page.routeHtml, + routeHTML: page.routeHtml, //todo, depreciate this + routeHtml: page.routeHtml, }, }); page.perf.end('html.layout'); From dd8c60140b77a3509541295f4fb99cf71ee4cf4a Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Wed, 16 Sep 2020 12:00:19 -0400 Subject: [PATCH 17/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20internalize=20roll?= =?UTF-8?q?up=20config=20as=20an=20Elder.js=20export?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 1171 ++++++++++++++++++++++++---------- package.json | 17 +- src/utils/getRollupConfig.ts | 256 ++++++++ src/utils/index.ts | 2 + 4 files changed, 1108 insertions(+), 338 deletions(-) create mode 100644 src/utils/getRollupConfig.ts diff --git a/package-lock.json b/package-lock.json index 304fcf7e..569945bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,19 +13,19 @@ } }, "@babel/core": { - "version": "7.11.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.4.tgz", - "integrity": "sha512-5deljj5HlqRXN+5oJTY7Zs37iH3z3b++KjiKtIsJy1NrjOOVSEaJHEetLBhyu0aQOSNNZ/0IuEAan9GzRuDXHg==", + "version": "7.11.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.6.tgz", + "integrity": "sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.11.4", + "@babel/generator": "^7.11.6", "@babel/helper-module-transforms": "^7.11.0", "@babel/helpers": "^7.10.4", - "@babel/parser": "^7.11.4", + "@babel/parser": "^7.11.5", "@babel/template": "^7.10.4", - "@babel/traverse": "^7.11.0", - "@babel/types": "^7.11.0", + "@babel/traverse": "^7.11.5", + "@babel/types": "^7.11.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.1", @@ -60,12 +60,12 @@ } }, "@babel/generator": { - "version": "7.11.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.4.tgz", - "integrity": "sha512-Rn26vueFx0eOoz7iifCN2UHT6rGtnkSGWSoDRIy8jZN3B91PzeSULbswfLoOWuTuAcNwpG/mxy+uCTDnZ9Mp1g==", + "version": "7.11.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.6.tgz", + "integrity": "sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA==", "dev": true, "requires": { - "@babel/types": "^7.11.0", + "@babel/types": "^7.11.5", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -111,7 +111,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", - "dev": true, "requires": { "@babel/types": "^7.10.4" } @@ -204,9 +203,9 @@ } }, "@babel/parser": { - "version": "7.11.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.4.tgz", - "integrity": "sha512-MggwidiH+E9j5Sh8pbrX5sJvMcsqS5o+7iB42M9/k0CD63MjYbdP4nhSh7uB5wnv2/RVzTZFTxzF/kIa5mrCqA==", + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz", + "integrity": "sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -328,17 +327,17 @@ } }, "@babel/traverse": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz", - "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==", + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.5.tgz", + "integrity": "sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.11.0", + "@babel/generator": "^7.11.5", "@babel/helper-function-name": "^7.10.4", "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.11.0", - "@babel/types": "^7.11.0", + "@babel/parser": "^7.11.5", + "@babel/types": "^7.11.5", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" @@ -353,10 +352,9 @@ } }, "@babel/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", - "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", - "dev": true, + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz", + "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==", "requires": { "@babel/helper-validator-identifier": "^7.10.4", "lodash": "^4.17.19", @@ -380,24 +378,24 @@ } }, "@commitlint/execute-rule": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-9.1.2.tgz", - "integrity": "sha512-NGbeo0KCVYo1yj9vVPFHv6RGFpIF6wcQxpFYUKGIzZVV9Vz1WyiKS689JXa99Dt1aN0cZlEJJLnTNDIgYls0Vg==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-11.0.0.tgz", + "integrity": "sha512-g01p1g4BmYlZ2+tdotCavrMunnPFPhTzG1ZiLKTCYrooHRbmvqo42ZZn4QMStUEIcn+jfLb6BRZX3JzIwA1ezQ==", "dev": true, "optional": true }, "@commitlint/load": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-9.1.2.tgz", - "integrity": "sha512-FPL82xBuF7J3EJ57kLVoligQP4BFRwrknooP+vNT787AXmQ/Fddc/iYYwHwy67pNkk5N++/51UyDl/CqiHb6nA==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-11.0.0.tgz", + "integrity": "sha512-t5ZBrtgvgCwPfxmG811FCp39/o3SJ7L+SNsxFL92OR4WQxPcu6c8taD0CG2lzOHGuRyuMxZ7ps3EbngT2WpiCg==", "dev": true, "optional": true, "requires": { - "@commitlint/execute-rule": "^9.1.2", - "@commitlint/resolve-extends": "^9.1.2", - "@commitlint/types": "^9.1.2", + "@commitlint/execute-rule": "^11.0.0", + "@commitlint/resolve-extends": "^11.0.0", + "@commitlint/types": "^11.0.0", "chalk": "4.1.0", - "cosmiconfig": "^6.0.0", + "cosmiconfig": "^7.0.0", "lodash": "^4.17.19", "resolve-from": "^5.0.0" }, @@ -441,20 +439,6 @@ "dev": true, "optional": true }, - "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, - "optional": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -482,9 +466,9 @@ } }, "@commitlint/resolve-extends": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-9.1.2.tgz", - "integrity": "sha512-HcoL+qFGmWEu9VM4fY0HI+VzF4yHcg3x+9Hx6pYFZ+r2wLbnKs964y0v68oyMO/mS/46MVoLNXZGR8U3adpadg==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-11.0.0.tgz", + "integrity": "sha512-WinU6Uv6L7HDGLqn/To13KM1CWvZ09VHZqryqxXa1OY+EvJkfU734CwnOEeNlSCK7FVLrB4kmodLJtL1dkEpXw==", "dev": true, "optional": true, "requires": { @@ -504,9 +488,9 @@ } }, "@commitlint/types": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-9.1.2.tgz", - "integrity": "sha512-r3fwVbVH+M8W0qYlBBZFsUwKe6NT5qvz+EmU7sr8VeN1cQ63z+3cfXyTo7WGGEMEgKiT0jboNAK3b1FZp8k9LQ==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-11.0.0.tgz", + "integrity": "sha512-VoNqai1vR5anRF5Tuh/+SWDFk7xi7oMwHrHrbm1BprYXjB2RJsWLhUrStMssDxEl5lW/z3EUdg8RvH/IUBccSQ==", "dev": true, "optional": true }, @@ -516,15 +500,35 @@ "integrity": "sha512-8n6FpnCbr4RnJYQDs7869zeywYXNyVtZnA5E4fHYWp2/fJX3OlDp7eYfMj6AnoE+E3Ehs5LVn9uT+rqUXcA0pQ==" }, "@eslint/eslintrc": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.0.tgz", - "integrity": "sha512-bfL5365QSCmH6cPeFT7Ywclj8C7LiF7sO6mUGzZhtAMV7iID1Euq6740u/SRi4C80NOnVz/CEfK8/HO+nCAPJg==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", + "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + } } }, "@istanbuljs/load-nyc-config": { @@ -749,6 +753,15 @@ "@types/istanbul-lib-report": "*" } }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + } + }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -798,6 +811,12 @@ "requires": { "has-flag": "^4.0.0" } + }, + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true } } }, @@ -1442,7 +1461,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", - "dev": true, "requires": { "@nodelib/fs.stat": "2.0.3", "run-parallel": "^1.1.9" @@ -1451,19 +1469,72 @@ "@nodelib/fs.stat": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", - "dev": true + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==" }, "@nodelib/fs.walk": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", - "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.3", "fastq": "^1.6.0" } }, + "@rollup/plugin-commonjs": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-14.0.0.tgz", + "integrity": "sha512-+PSmD9ePwTAeU106i9FRdc+Zb3XUWyW26mo5Atr2mk82hor8+nPwkztEjFo8/B1fJKfaQDg9aM2bzQkjhi7zOw==", + "requires": { + "@rollup/pluginutils": "^3.0.8", + "commondir": "^1.0.1", + "estree-walker": "^1.0.1", + "glob": "^7.1.2", + "is-reference": "^1.1.2", + "magic-string": "^0.25.2", + "resolve": "^1.11.0" + } + }, + "@rollup/plugin-json": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", + "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "requires": { + "@rollup/pluginutils": "^3.0.8" + } + }, + "@rollup/plugin-node-resolve": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.4.0.tgz", + "integrity": "sha512-LFqKdRLn0ShtQyf6SBYO69bGE1upV6wUhBX0vFOUnLAyzx5cwp8svA0eHUnu8+YU57XOkrMtfG63QOpQx25pHQ==", + "requires": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deep-freeze": "^0.0.1", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.17.0" + } + }, + "@rollup/plugin-replace": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.3.3.tgz", + "integrity": "sha512-XPmVXZ7IlaoWaJLkSCDaa0Y6uVo5XQYHhiMFzOd5qSv5rE+t/UJToPIOE56flKIxBFQI27ONsxb7dqHnwSsjKQ==", + "requires": { + "@rollup/pluginutils": "^3.0.8", + "magic-string": "^0.25.5" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, "@sinonjs/commons": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", @@ -1515,9 +1586,9 @@ } }, "@types/babel__traverse": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.13.tgz", - "integrity": "sha512-i+zS7t6/s9cdQvbqKDARrcbrPvtJGlbYsMkazo03nTAK3RX9FNrLllXys22uiTGJapPOTZTQ35nHh4ISph4SLQ==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.14.tgz", + "integrity": "sha512-8w9szzKs14ZtBVuP6Wn7nMLRJ0D6dfB0VEBEyRgxrZ/Ln49aNMykrghM2FaNn4FJRzNppCSa0Rv9pBRM5Xc3wg==", "dev": true, "requires": { "@babel/types": "^7.3.0" @@ -1529,6 +1600,11 @@ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + }, "@types/fs-extra": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.1.tgz", @@ -1538,6 +1614,15 @@ "@types/node": "*" } }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, "@types/graceful-fs": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.3.tgz", @@ -1573,9 +1658,9 @@ } }, "@types/jest": { - "version": "26.0.12", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.12.tgz", - "integrity": "sha512-vZOFjm562IPb1EmaKxMjdcouxVb1l3NqoUH4XC4tDQ2R/AWde+0HXBUhyfc6L+7vc3mJ393U+5vr3nH2CLSVVg==", + "version": "26.0.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.14.tgz", + "integrity": "sha512-Hz5q8Vu0D288x3iWXePSn53W7hAjP0H7EQ6QvDO9c7t46mR0lNOLlfuwQ+JkVxuhygHzlzPX+0jKdA3ZgSh+Vg==", "dev": true, "requires": { "jest-diff": "^25.2.1", @@ -1583,9 +1668,9 @@ } }, "@types/json-schema": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", - "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", "dev": true }, "@types/json5": { @@ -1594,11 +1679,15 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" + }, "@types/node": { - "version": "14.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.10.1.tgz", - "integrity": "sha512-aYNbO+FZ/3KGeQCEkNhHFRIzBOUgc7QvcVNKXbfnhDkSfwUv91JsQQa10rDgKSTSLkXZ1UIyPe4FJJNVgw1xWQ==", - "dev": true + "version": "14.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.10.2.tgz", + "integrity": "sha512-IzMhbDYCpv26pC2wboJ4MMOa9GKtjplXfcAqrMeNJpUUwpM/2ATt2w1JPUXwS6spu856TvKZL2AOmeU2rAxskw==" }, "@types/normalize-package-data": { "version": "2.4.0", @@ -1612,11 +1701,19 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "@types/prettier": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.0.tgz", - "integrity": "sha512-hiYA88aHiEIgDmeKlsyVsuQdcFn3Z2VuFd/Xm/HCnGnPD8UFU5BM128uzzRVVGEzKDKYUrRsRH9S2o+NUy/3IA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.1.tgz", + "integrity": "sha512-2zs+O+UkDsJ1Vcp667pd3f8xearMdopz/z54i99wtRDI5KLmngk7vlrYZD0ZjKHaROR03EznlBbVY9PfAEyJIQ==", "dev": true }, + "@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "requires": { + "@types/node": "*" + } + }, "@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", @@ -1639,13 +1736,13 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.1.tgz", - "integrity": "sha512-pQZtXupCn11O4AwpYVUX4PDFfmIJl90ZgrEBg0CEcqlwvPiG0uY81fimr1oMFblZnpKAq6prrT9a59pj1x58rw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.1.1.tgz", + "integrity": "sha512-Hoxyt99EA9LMmqo/5PuWWPeWeB3mKyvibfJ1Hy5SfiUpjE8Nqp+5QNd9fOkzL66+fqvIWSIE+Ett16LGMzCGnQ==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.0.1", - "@typescript-eslint/scope-manager": "4.0.1", + "@typescript-eslint/experimental-utils": "4.1.1", + "@typescript-eslint/scope-manager": "4.1.1", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", @@ -1654,85 +1751,93 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz", - "integrity": "sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.1.1.tgz", + "integrity": "sha512-jzYsNciHoa4Z3c1URtmeT/bamYm8Dwfw6vuN3WHIE/BXb1iC4KveAnXDErTAZtPVxTYBaYn3n2gbt6F6D2rm1A==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.0.1", - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/typescript-estree": "4.0.1", + "@typescript-eslint/scope-manager": "4.1.1", + "@typescript-eslint/types": "4.1.1", + "@typescript-eslint/typescript-estree": "4.1.1", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/parser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.0.1.tgz", - "integrity": "sha512-1+qLmXHNAWSQ7RB6fdSQszAiA7JTwzakj5cNYjBTUmpH2cqilxMZEIV+DRKjVZs8NzP3ALmKexB0w/ExjcK9Iw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.1.1.tgz", + "integrity": "sha512-NLIhmicpKGfJbdXyQBz9j48PA6hq6e+SDOoXy7Ak6bq1ebGqbgG+fR1UIDAuay6OjQdot69c/URu2uLlsP8GQQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.0.1", - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/typescript-estree": "4.0.1", + "@typescript-eslint/scope-manager": "4.1.1", + "@typescript-eslint/types": "4.1.1", + "@typescript-eslint/typescript-estree": "4.1.1", "debug": "^4.1.1" } }, "@typescript-eslint/scope-manager": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz", - "integrity": "sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.1.1.tgz", + "integrity": "sha512-0W8TTobCvIIQ2FsrYTffyZGAAFUyIbEHq5EYJb1m7Rpd005jrnOvKOo8ywCLhs/Bm17C+KsrUboBvBAARQVvyA==", "dev": true, "requires": { - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/visitor-keys": "4.0.1" + "@typescript-eslint/types": "4.1.1", + "@typescript-eslint/visitor-keys": "4.1.1" } }, "@typescript-eslint/types": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.0.1.tgz", - "integrity": "sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.1.1.tgz", + "integrity": "sha512-zrBiqOKYerMTllKcn+BP+i1b7LW/EbMMYytroXMxUTvFPn1smkCu0D7lSAx29fTUO4jnwV0ljSvYQtn2vNrNxA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz", - "integrity": "sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.1.1.tgz", + "integrity": "sha512-2AUg5v0liVBsqbGxBphbJ0QbGqSRVaF5qPoTPWcxop+66vMdU1h4CCvHxTC47+Qb+Pr4l2RhXDd41JNpwcQEKw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.0.1", - "@typescript-eslint/visitor-keys": "4.0.1", + "@typescript-eslint/types": "4.1.1", + "@typescript-eslint/visitor-keys": "4.1.1", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", "lodash": "^4.17.15", "semver": "^7.3.2", "tsutils": "^3.17.1" + }, + "dependencies": { + "globby": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", + "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + } } }, "@typescript-eslint/visitor-keys": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz", - "integrity": "sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.1.1.tgz", + "integrity": "sha512-/EOOXbA2ferGLG6RmCHEQ0lTTLkOlXYDgblCmQk3tIU7mTPLm4gKhFMeeUSe+bcchTUsKeCk8xcpbop5Zr/8Rw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.0.1", + "@typescript-eslint/types": "4.1.1", "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true - } } }, "abab": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.4.tgz", - "integrity": "sha512-Eu9ELJWCz/c1e9gTiCY+FceWxcqzjYEbqMgtndnuSqZSUCOL73TWNK2mHfIj4Cw2E/ongOp+JISVNCmovt2KYQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", "dev": true }, "acorn": { @@ -1752,9 +1857,9 @@ } }, "acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", - "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", "dev": true }, "acorn-walk": { @@ -1763,10 +1868,19 @@ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "version": "6.12.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", + "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -1782,21 +1896,10 @@ "dev": true }, "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "dev": true, - "requires": { - "type-fest": "^0.11.0" - }, - "dependencies": { - "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "dev": true - } - } + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true }, "ansi-regex": { "version": "5.0.0", @@ -1863,13 +1966,33 @@ "define-properties": "^1.1.3", "es-abstract": "^1.17.0", "is-string": "^1.0.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" }, "array-unique": { "version": "0.3.2", @@ -1885,6 +2008,27 @@ "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "asn1": { @@ -2169,7 +2313,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -2201,8 +2344,12 @@ "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==" }, "cache-base": { "version": "1.0.1", @@ -2304,6 +2451,11 @@ } } }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -2388,6 +2540,11 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, "commitizen": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.2.1.tgz", @@ -2459,24 +2616,6 @@ "graceful-fs": "^4.1.6" } }, - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", - "dev": true - }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -2485,6 +2624,11 @@ } } }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -2521,6 +2665,14 @@ "dev": true, "requires": { "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } } }, "copy-descriptor": { @@ -2529,6 +2681,11 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, + "core-js": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", + "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -2556,6 +2713,17 @@ "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } } }, "cssom": { @@ -2649,6 +2817,11 @@ "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", "dev": true }, + "deep-freeze": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz", + "integrity": "sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ=" + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -2658,8 +2831,7 @@ "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" }, "define-properties": { "version": "1.1.3", @@ -2711,6 +2883,21 @@ } } }, + "del": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/del/-/del-5.1.0.tgz", + "integrity": "sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==", + "requires": { + "globby": "^10.0.1", + "graceful-fs": "^4.2.2", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.1", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2751,7 +2938,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, "requires": { "path-type": "^4.0.0" } @@ -2830,9 +3016,9 @@ } }, "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "version": "1.18.0-next.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz", + "integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==", "dev": true, "requires": { "es-to-primitive": "^1.2.1", @@ -2840,8 +3026,9 @@ "has": "^1.0.3", "has-symbols": "^1.0.1", "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", "object-keys": "^1.1.1", "object.assign": "^4.1.0", "string.prototype.trimend": "^1.0.1", @@ -2919,13 +3106,13 @@ } }, "eslint": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.0.tgz", - "integrity": "sha512-qgtVyLZqKd2ZXWnLQA4NtVbOyH56zivOAdBFWE54RFkSZjokzNrcP4Z0eVWsZ+84ByXv+jL9k/wE1ENYe8xRFw==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.9.0.tgz", + "integrity": "sha512-V6QyhX21+uXp4T+3nrNfI3hQNBDa/P8ga7LoQOenwrlEFXrEnUEE+ok1dMtaS3b6rmLXhT1TkTIsG75HMLbknA==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.1.0", + "@eslint/eslintrc": "^0.1.3", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -2998,6 +3185,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3010,6 +3203,12 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3178,6 +3377,12 @@ "semver": "^7.3.2", "tsutils": "^3.17.1" } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true } } }, @@ -3191,12 +3396,12 @@ } }, "eslint-scope": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", - "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "requires": { - "esrecurse": "^4.1.0", + "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, @@ -3207,12 +3412,20 @@ "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } } }, "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", "dev": true }, "espree": { @@ -3224,6 +3437,14 @@ "acorn": "^7.4.0", "acorn-jsx": "^5.2.0", "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } } }, "esprima": { @@ -3250,12 +3471,20 @@ } }, "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "requires": { - "estraverse": "^4.1.0" + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } } }, "estraverse": { @@ -3264,6 +3493,11 @@ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3330,15 +3564,6 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } } } }, @@ -3626,7 +3851,6 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", - "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -3652,7 +3876,6 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", - "dev": true, "requires": { "reusify": "^1.0.4" } @@ -3688,7 +3911,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -3920,7 +4142,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, "optional": true }, "function-bind": { @@ -4000,7 +4221,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -4037,17 +4257,6 @@ "ini": "^1.3.4", "is-windows": "^1.0.1", "which": "^1.2.14" - }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } } }, "globals": { @@ -4060,16 +4269,17 @@ } }, "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", - "dev": true, + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", "requires": { + "@types/glob": "^7.1.1", "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", "slash": "^3.0.0" } }, @@ -4232,8 +4442,7 @@ "ignore": { "version": "5.1.8", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" }, "import-fresh": { "version": "3.2.1", @@ -4320,6 +4529,11 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -4361,12 +4575,6 @@ "through": "^2.3.6" }, "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", @@ -4462,9 +4670,9 @@ "dev": true }, "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz", + "integrity": "sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==", "dev": true }, "is-ci": { @@ -4537,8 +4745,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -4555,16 +4762,35 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=" + }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "dev": true + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" + }, + "is-path-inside": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", + "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==" }, "is-plain-object": { "version": "2.0.4", @@ -4581,6 +4807,14 @@ "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", "dev": true }, + "is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "requires": { + "@types/estree": "*" + } + }, "is-regex": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", @@ -4950,6 +5184,12 @@ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", "dev": true }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, "npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -4959,6 +5199,15 @@ "path-key": "^3.0.0" } }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6521,12 +6770,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6918,6 +7161,15 @@ "@types/istanbul-lib-report": "*" } }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + } + }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -6967,6 +7219,12 @@ "requires": { "has-flag": "^4.0.0" } + }, + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true } } }, @@ -6974,7 +7232,6 @@ "version": "26.3.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.3.0.tgz", "integrity": "sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw==", - "dev": true, "requires": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -6984,14 +7241,12 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -7060,9 +7315,9 @@ "dev": true }, "json-parse-even-better-errors": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.0.tgz", - "integrity": "sha512-o3aP+RsWDJZayj1SbHNQAI8x0v3T3SKiGoZlNYfbUP1S3omJQ6i9CnqADqkSPaOAxwua4/1YWx5CM7oiChJt2Q==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "json-schema": { "version": "0.2.3", @@ -7171,6 +7426,12 @@ "requires": { "error-ex": "^1.2.0" } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true } } }, @@ -7185,9 +7446,9 @@ } }, "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, "lodash-es": { "version": "4.17.15", @@ -7223,6 +7484,14 @@ "integrity": "sha1-eB4YMpaqlPbU2RbcM10NF676I/g=", "dev": true }, + "magic-string": { + "version": "0.25.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", + "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -7279,20 +7548,17 @@ "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, "micromatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, "requires": { "braces": "^3.0.1", "picomatch": "^2.0.5" @@ -7314,9 +7580,9 @@ } }, "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "minimatch": { @@ -7436,6 +7702,18 @@ "shellwords": "^0.1.1", "uuid": "^8.3.0", "which": "^2.0.2" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "optional": true, + "requires": { + "isexe": "^2.0.0" + } + } } }, "normalize-package-data": { @@ -7546,15 +7824,15 @@ } }, "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", + "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.0", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" } }, "object.entries": { @@ -7566,6 +7844,27 @@ "define-properties": "^1.1.3", "es-abstract": "^1.17.5", "has": "^1.0.3" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "object.pick": { @@ -7587,6 +7886,27 @@ "es-abstract": "^1.17.0-next.1", "function-bind": "^1.1.1", "has": "^1.0.3" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "once": { @@ -7598,12 +7918,12 @@ } }, "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { - "mimic-fn": "^2.1.0" + "mimic-fn": "^1.0.0" } }, "optionator": { @@ -7656,6 +7976,14 @@ "p-limit": "^1.1.0" } }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "requires": { + "aggregate-error": "^3.0.0" + } + }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", @@ -7719,8 +8047,7 @@ "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "path-type": { "version": "4.0.0", @@ -7736,8 +8063,7 @@ "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" }, "pify": { "version": "2.3.0", @@ -7776,9 +8102,9 @@ "dev": true }, "prettier": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.1.tgz", - "integrity": "sha512-9bY+5ZWCfqj3ghYBLxApy2zf6m+NJo5GzmLTpr9FsApsfjriNnS2dahWReHMi7qNPhhHl9SYHJs2cHZLgexNIw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", + "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", "dev": true }, "prettier-linter-helpers": { @@ -7878,6 +8204,14 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -8045,11 +8379,15 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=" + }, "resolve": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, "requires": { "path-parse": "^1.0.6" } @@ -8110,23 +8448,6 @@ "requires": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" - }, - "dependencies": { - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - } } }, "ret": { @@ -8138,18 +8459,108 @@ "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "requires": { "glob": "^7.1.3" } }, + "rollup": { + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.27.0.tgz", + "integrity": "sha512-1WlbhNdzhLjdhh2wsf6CDxmuBAYG+5O53fYqCcGv8aJOoX/ymCfCY6oZnvllXZzaC/Ng+lPPwq9EMbHOKc5ozA==", + "requires": { + "fsevents": "~2.1.2" + } + }, + "rollup-plugin-babel": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz", + "integrity": "sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-css-only": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-2.1.0.tgz", + "integrity": "sha512-pfdcqAWEmRMFy+ABXAQPA/DKyPqLuBTOf+lWSOgtrVs1v/q7DSXzYa9QZg4myd8/1F7NHcdvPkWnfWqMxq9vrw==", + "requires": { + "@rollup/pluginutils": "^3.0.0", + "fs-extra": "^9.0.0" + } + }, + "rollup-plugin-delete": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-delete/-/rollup-plugin-delete-2.0.0.tgz", + "integrity": "sha512-/VpLMtDy+8wwRlDANuYmDa9ss/knGsAgrDhM+tEwB1npHwNu4DYNmDfUL55csse/GHs9Q+SMT/rw9uiaZ3pnzA==", + "requires": { + "del": "^5.1.0" + } + }, + "rollup-plugin-external-globals": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-external-globals/-/rollup-plugin-external-globals-0.5.0.tgz", + "integrity": "sha512-v3qjync/2wcqdSesNP3qPnYeOnnV39ydCU+2fTxjlmux8uA1VqM4cUVffkgzoDh3TBOEhN8JWAHrN7Hs9ZD0Sg==", + "requires": { + "estree-walker": "^1.0.0", + "is-reference": "^1.1.4", + "magic-string": "^0.25.4", + "rollup-pluginutils": "^2.8.2" + } + }, + "rollup-plugin-multi-input": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-multi-input/-/rollup-plugin-multi-input-1.1.1.tgz", + "integrity": "sha512-q/sFiS7h7AQk0V/fFREt5Gizewov01V1RZgORFmXL6W9emkJOPu94GFJ21KYtSob4bmEmDq9Hpr+3ukKNi84CA==", + "requires": { + "@babel/runtime": "^7.0.0-beta.55", + "core-js": "^3.1.3", + "fast-glob": "^3.0.0", + "lodash": "^4.17.11" + } + }, + "rollup-plugin-svelte": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-6.0.1.tgz", + "integrity": "sha512-kS9/JZMBNgpKTqVKlwV8mhmGwxu8NiNf6+n5ZzdZ8yDp3+ADqjf8Au+JNEpoOn6kLlh1hLS2Gsa76k9RP57HDQ==", + "requires": { + "require-relative": "^0.8.7", + "rollup-pluginutils": "^2.8.2", + "sourcemap-codec": "^1.4.8" + } + }, + "rollup-plugin-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-6.1.0.tgz", + "integrity": "sha512-4fB3M9nuoWxrwm39habpd4hvrbrde2W2GG4zEGPQg1YITNkM3Tqur5jSuXlWNzbv/2aMLJ+dZJaySc3GCD8oDw==", + "requires": { + "@babel/code-frame": "^7.8.3", + "jest-worker": "^26.0.0", + "serialize-javascript": "^3.0.0", + "terser": "^4.7.0" + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "requires": { + "estree-walker": "^0.6.1" + }, + "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==" + } + } + }, "rsvp": { "version": "4.8.5", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", @@ -8165,23 +8576,21 @@ "run-parallel": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==" }, "rxjs": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz", - "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==", + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", "dev": true, "requires": { "tslib": "^1.9.0" } }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "safe-regex": { "version": "1.1.0", @@ -8354,6 +8763,14 @@ "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true }, + "serialize-javascript": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz", + "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==", + "requires": { + "randombytes": "^2.1.0" + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -8420,8 +8837,7 @@ "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" }, "slice-ansi": { "version": "2.1.0", @@ -8573,8 +8989,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-resolve": { "version": "0.5.3", @@ -8593,7 +9008,6 @@ "version": "0.5.19", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -8605,6 +9019,11 @@ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, "spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -8741,6 +9160,27 @@ "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "string.prototype.trimstart": { @@ -8751,6 +9191,27 @@ "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "strip-ansi": { @@ -8762,9 +9223,9 @@ } }, "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, "strip-eof": { @@ -8780,9 +9241,9 @@ "dev": true }, "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", "dev": true }, "supports-color": { @@ -8820,6 +9281,11 @@ } } }, + "svelte": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.25.1.tgz", + "integrity": "sha512-IbrVKTmuR0BvDw4ii8/gBNy8REu7nWTRy9uhUz+Yuae5lIjWgSGwKlWtJGC2Vg95s+UnXPqDu0Kk/sUwe0t2GQ==" + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -8832,9 +9298,9 @@ "integrity": "sha512-R9N6uDkVsghHePKh1TEqbnLddO2IY25OcsksyFp/qBe7XYd0PVbKEWxhcdMhpLzE1I6skj5l4aEZ3CRxcbArlA==" }, "systemjs": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-6.5.0.tgz", - "integrity": "sha512-B+NzKJD1srC/URfNVBdDExAUAsAVXpVQxZxX54AtqU0xiK9imkqurQu3qi6JdyA2GBAw2ssjolYIa7kh+xY1uw==" + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-6.6.1.tgz", + "integrity": "sha512-Niw/DZwTPmdLGC0CCe+n/MdRu927XyN/jzxKZyU6tUfeNqGQlxO5oVXuVMsJHxPO2cnXyHh0/zIGdXaocOMLVQ==" }, "table": { "version": "5.4.6", @@ -8896,6 +9362,33 @@ "requires": { "ansi-escapes": "^4.2.1", "supports-hyperlinks": "^2.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + } + }, + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + } + } + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" } }, "test-exclude": { @@ -8945,8 +9438,7 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, "to-object-path": { "version": "0.3.0", @@ -8984,7 +9476,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "requires": { "is-number": "^7.0.0" } @@ -9073,6 +9564,14 @@ "json5": "^1.0.1", "minimist": "^1.2.0", "strip-bom": "^3.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } } }, "tslib": { @@ -9199,9 +9698,9 @@ } }, "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", "dev": true, "requires": { "punycode": "^2.1.0" @@ -9321,9 +9820,9 @@ "dev": true }, "whatwg-url": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.2.1.tgz", - "integrity": "sha512-ZmVCr6nfBeaMxEHALLEGy0LszYjpJqf6PVNQUQ1qd9Et+q7Jpygd4rGGDXgHjD8e99yLFseD69msHDM4YwPZ4A==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-PcVnO6NiewhkmzV0qn7A+UZ9Xx4maNTI+O+TShmfE4pqjoCMwUMjkvoNhNHPTvgR7QH9Xt3R13iHuWy2sToFxQ==", "dev": true, "requires": { "lodash.sortby": "^4.7.0", @@ -9332,9 +9831,9 @@ } }, "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" diff --git a/package.json b/package.json index 485e02c1..bd0df050 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,25 @@ "cosmiconfig": "^7.0.0", "fs-extra": "^9.0.1", "glob": "^7.1.6", - "intersection-observer": "^0.11.0", "lodash.defaultsdeep": "^4.6.1", "@elderjs/shortcodes": "^1.0.6", "nanoid": "^3.1.12", "systemjs": "^6.5.0", - "yup": "^0.29.3" + "yup": "^0.29.3", + "del": "^5.1.0", + "rollup-plugin-babel": "^4.4.0", + "rollup-plugin-css-only": "^2.1.0", + "rollup-plugin-delete": "^2.0.0", + "rollup-plugin-external-globals": "^0.5.0", + "rollup-plugin-multi-input": "^1.1.1", + "rollup-plugin-svelte": "^6.0.1", + "rollup-plugin-terser": "^6.1.0", + "@rollup/plugin-commonjs": "^14.0.0", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^8.4.0", + "@rollup/plugin-replace": "^2.3.3", + "intersection-observer": "^0.11.0", + "svelte": "^3.25.1" }, "devDependencies": { "@types/fs-extra": "^9.0.1", diff --git a/src/utils/getRollupConfig.ts b/src/utils/getRollupConfig.ts new file mode 100644 index 00000000..b235b1e6 --- /dev/null +++ b/src/utils/getRollupConfig.ts @@ -0,0 +1,256 @@ +// require('dotenv').config(); +import svelte from 'rollup-plugin-svelte'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import { terser } from 'rollup-plugin-terser'; +import babel from 'rollup-plugin-babel'; +import css from 'rollup-plugin-css-only'; +import multiInput from 'rollup-plugin-multi-input'; +import externalGlobals from 'rollup-plugin-external-globals'; +import replace from '@rollup/plugin-replace'; +import json from '@rollup/plugin-json'; +import glob from 'glob'; +import path from 'path'; +import fs from 'fs-extra'; +import del from 'del'; +import { getElderConfig, partialHydration } from '../Elder'; + +const production = process.env.NODE_ENV === 'production' || !process.env.ROLLUP_WATCH; + +function createBrowserConfig({ input, output, multiInputConfig = false, svelteConfig }) { + const config = { + cache: true, + treeshake: true, + input, + output, + plugins: [ + replace({ + 'process.env.componentType': 'browser', + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), + }), + json(), + svelte({ + ...svelteConfig, + dev: !production, + immutable: true, + hydratable: true, + css: false, + }), + externalGlobals({ + systemjs: 'System', + }), + nodeResolve({ + browser: true, + dedupe: ['svelte'], + preferBuiltins: true, + }), + commonjs(), + ], + }; + // bundle splitting. + if (multiInputConfig) { + config.plugins.unshift(multiInputConfig); + } + // if is production let's babelify everything and minify it. + if (production) { + config.plugins.push( + babel({ + extensions: ['.js', '.mjs', '.cjs', '.html', '.svelte'], + include: ['node_modules/**', 'src/**'], + exclude: ['node_modules/@babel/**'], + runtimeHelpers: true, + }), + ); + config.plugins.push(terser()); + } + return config; +} + +function createSSRConfig({ input, output, svelteConfig, multiInputConfig = false }) { + const config = { + cache: true, + treeshake: true, + input, + output, + plugins: [ + replace({ + 'process.env.componentType': 'server', + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), + }), + json(), + svelte({ + ...svelteConfig, + dev: !production, + hydratable: true, + generate: 'ssr', + css: true, + extensions: '.svelte', + preprocess: [...svelteConfig.preprocess, partialHydration], + }), + + nodeResolve({ + browser: false, + dedupe: ['svelte'], + }), + commonjs({ sourceMap: false }), + css({ + ignore: true, + }), + production && terser(), + ], + }; + // if we are bundle splitting include them. + if (multiInputConfig) { + config.plugins.unshift(multiInputConfig); + } + + return config; +} + +export default function getRollupConfig({ svelteConfig }) { + const { locations } = getElderConfig(); + const { ssrComponents, clientComponents } = locations.svelte; + + console.log( + `rollup production === ${production}. ${!process.env.ROLLUP_WATCH ? 'Because watch is undefined' : ''}. ${ + process.env.NODE_ENV === 'production' ? 'Because NODE_ENV === Production' : '' + }`, + ); + + let configs = []; + + // clear out components so there are no conflicts due to hashing. + del.sync([`${ssrComponents}*`, `${clientComponents}*`]); + + // Add ElderJs Peer deps to public if they exist. + const elderJsPeerDeps = [ + ['./node_modules/intersection-observer/intersection-observer.js', 'intersectionObserverPoly'], + ['./node_modules/systemjs/dist/s.min.js', 'systemJs'], + ] + .filter((dep) => fs.existsSync(path.resolve(process.cwd(), dep[0]))) + .map((dep) => { + return { + input: dep[0], + output: [ + { + file: path.resolve(process.cwd(), `${locations.public}${locations[dep[1]]}`), + format: 'iife', + name: dep[1], + plugins: [terser()], + }, + ], + }; + }); + + configs = [...configs, ...elderJsPeerDeps]; + + // SSR /routes/ Svelte files. + const templates = glob.sync('./src/routes/*/*.svelte').reduce((out, cv) => { + const file = cv.replace(`${__dirname}/`, ''); + out.push( + createSSRConfig({ + input: file, + output: { + dir: ssrComponents, + format: 'cjs', + exports: 'auto', + }, + svelteConfig, + }), + ); + return out; + }, []); + + // SSR /layouts/ Svelte files. + const layouts = glob.sync('./src/layouts/*.svelte').reduce((out, cv) => { + const file = cv.replace(`${__dirname}/`, ''); + out.push( + createSSRConfig({ + input: file, + output: { + dir: ssrComponents, + format: 'cjs', + exports: 'auto', + }, + svelteConfig, + }), + ); + + return out; + }, []); + + if (production) { + // production build does bundle splitting, minification, and babel + configs = [...configs, ...templates, ...layouts]; + if (fs.existsSync(path.resolve(`./src/components/`))) { + configs.push( + createBrowserConfig({ + input: ['src/components/*/*.svelte'], + output: { + dir: clientComponents, + entryFileNames: 'entry[name]-[hash].js', + sourcemap: !production, + format: 'system', + }, + multiInputConfig: multiInput({ + relative: 'src/components/', + transformOutputPath: (output, input) => `${path.basename(output)}`, + }), + svelteConfig, + }), + ); + configs.push( + createSSRConfig({ + input: ['src/components/*/*.svelte'], + output: { + dir: ssrComponents, + format: 'cjs', + exports: 'auto', + }, + multiInputConfig: multiInput({ + relative: 'src/components/', + transformOutputPath: (output, input) => `${path.basename(output)}`, + }), + svelteConfig, + }), + ); + } + } else { + // watch/dev build bundles each component individually for faster reload times during dev. + let sharedComponents = []; + if (fs.existsSync(path.resolve(`./src/components/`))) { + sharedComponents = glob.sync(path.resolve(__dirname, './src/components/*/*.svelte')).reduce((out, cv) => { + const file = cv.replace(`${__dirname}/`, ''); + // console.log(file, cv);; + out.push( + createBrowserConfig({ + input: file, + output: { + dir: clientComponents, + entryFileNames: 'entry[name].js', + sourcemap: !production, + format: 'system', + }, + svelteConfig, + }), + ); + out.push( + createSSRConfig({ + input: file, + output: { + dir: ssrComponents, + format: 'cjs', + exports: 'auto', + }, + svelteConfig, + }), + ); + + return out; + }, []); + } + configs = [...configs, ...templates, ...layouts, ...sharedComponents]; + } + + return configs; +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 64c45046..2c600e9e 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -16,6 +16,7 @@ import { prepareServer } from './prepareServer'; import { validateHook, validateRoute, validatePlugin, validateShortcode } from './validations'; import prepareProcessStack from './prepareProcessStack'; import getConfig from './getConfig'; +import getRollupConfig from './getRollupConfig'; export { asyncForEach, @@ -37,4 +38,5 @@ export { prepareServer, prepareProcessStack, getConfig, + getRollupConfig, }; From 7ef13bc2513afa51e12e2701a4f0342ae3bf31a9 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Wed, 16 Sep 2020 15:03:57 -0400 Subject: [PATCH 18/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20start=20refactorin?= =?UTF-8?q?g=20elder.config.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Elder.ts | 100 +++--------------- src/externalHelpers.ts | 34 +----- src/hooks.ts | 86 ++++++--------- src/routes/routes.ts | 24 ++--- src/utils/getConfig.ts | 48 ++------- src/utils/getHashedSvelteComponents.ts | 4 +- src/utils/getRollupConfig.ts | 53 +++++----- src/utils/svelteComponent.ts | 14 +-- src/utils/tsConfigExist.ts | 16 --- src/utils/types.ts | 39 ++++--- src/utils/validations.ts | 138 ++++++++++++++----------- 11 files changed, 208 insertions(+), 348 deletions(-) delete mode 100644 src/utils/tsConfigExist.ts diff --git a/src/Elder.ts b/src/Elder.ts index bbbca11a..9c522606 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -82,8 +82,6 @@ class Elder { const config = getConfig(context); - const { srcFolder, buildFolder } = config.locations; - this.settings = { ...config, server: context === 'server' && config[context], @@ -118,22 +116,15 @@ class Elder { let plugin: PluginOptions | undefined; const pluginPath = `./plugins/${pluginName}/index.js`; - const srcPlugin = path.resolve(process.cwd(), srcFolder, pluginPath); + const srcPlugin = path.resolve(this.settings.srcDir, pluginPath); if (fs.existsSync(srcPlugin)) { // eslint-disable-next-line import/no-dynamic-require - plugin = require(srcPlugin).default || require(srcPlugin); - } - - if (!plugin && buildFolder.length > 0) { - const buildPlugin = path.resolve(process.cwd(), buildFolder, pluginPath); - if (fs.existsSync(buildPlugin)) { - // eslint-disable-next-line import/no-dynamic-require - plugin = require(buildPlugin).default || require(buildPlugin); - } + const pluginReq = require(srcPlugin); + plugin = pluginReq.default || pluginReq; } if (!plugin) { - const pkgPath = path.resolve(process.cwd(), './node_modules/', pluginName); + const pkgPath = path.resolve(this.settings.paths.rootDir, './node_modules/', pluginName); if (fs.existsSync(pkgPath)) { // eslint-disable-next-line import/no-dynamic-require const pluginPackageJson = require(path.resolve(pkgPath, './package.json')); @@ -224,15 +215,11 @@ class Elder { plugin.routes[routeName].template.endsWith('.svelte') ) { const templateName = plugin.routes[routeName].template.replace('.svelte', ''); - const ssrComponent = path.resolve( - process.cwd(), - this.settings.locations.svelte.ssrComponents, - `${templateName}.js`, - ); + const ssrComponent = path.resolve(this.settings.paths.ssrComponents, `${templateName}.js`); if (!fs.existsSync(ssrComponent)) { console.warn( - `Plugin Route: ${routeName} has an error. No SSR svelte compontent found ${templateName} which was added by ${pluginName}. This may cause unexpected outcomes. If you believe this should be working, make sure rollup has run before this file is initialized. If the issue persists, please contact the plugin author. Expected location \`${ssrComponent}\``, + `Plugin Route: ${routeName} has an error. No SSR svelte component found ${templateName} which was added by ${pluginName}. This may cause unexpected outcomes. If you believe this should be working, make sure rollup has run before this file is initialized. If the issue persists, please contact the plugin author. Expected location \`${ssrComponent}\``, ); } @@ -304,19 +291,11 @@ class Elder { */ let hooksJs: Array = []; - const hookSrcPath = path.resolve(process.cwd(), srcFolder, './hooks.js'); - const hookBuildPath = path.resolve(process.cwd(), buildFolder, './hooks.js'); - - if (this.settings.debug.automagic) { - console.log( - `debug.automagic::Attempting to automagically pull in hooks from your ${hookSrcPath} ${ - buildFolder ? `with a fallback to ${hookBuildPath}` : '' - }`, - ); - } - try { - const hookSrcFile: Array = config.typescript ? require(hookSrcPath).default : require(hookSrcPath); + const hookSrcPath = path.resolve(this.settings.srcDir, './hooks.js'); + try { + const hooksReq = require(hookSrcPath); + const hookSrcFile: Array = hooksReq.default || hooksReq; hooksJs = hookSrcFile.map((hook) => ({ ...hook, $$meta: { @@ -326,26 +305,7 @@ class Elder { })); } catch (err) { if (err.code === 'MODULE_NOT_FOUND') { - if (buildFolder && buildFolder.length > 0) { - try { - const hookBuildFile: Array = config.typescript - ? require(hookBuildPath).default - : require(hookBuildPath); - hooksJs = hookBuildFile.map((hook) => ({ - ...hook, - $$meta: { - type: 'hooks.js', - addedBy: 'hooks.js', - }, - })); - } catch (err2) { - if (err2.code !== 'MODULE_NOT_FOUND') { - console.error(err); - } - } - } else if (this.settings.debug.automagic) { - console.log(`No luck finding that hooks file. You can add one at ${hookSrcPath}`); - } + console.error(`Could not load hooks file from ${hookSrcPath}.`); } else { console.error(err); } @@ -376,20 +336,11 @@ class Elder { */ let shortcodesJs: ShortcodeDefs = []; - const shortcodeSrcPath = path.resolve(process.cwd(), srcFolder, './shortcodes.js'); - const shortcodeBuildPath = path.resolve(process.cwd(), buildFolder, './shortcodes.js'); - - if (this.settings.debug.automagic) { - console.log( - `debug.automagic::Attempting to automagically pull in shortcodes from your ${shortcodeSrcPath} ${ - buildFolder ? `with a fallback to ${shortcodeBuildPath}` : '' - }`, - ); - } + const shortcodeSrcPath = path.resolve(this.settings.srcDir, './shortcodes.js'); + try { - const shortcodes: ShortcodeDefs = config.typescript - ? require(shortcodeSrcPath).default - : require(shortcodeSrcPath); + const shortcodeReq = require(shortcodeSrcPath); + const shortcodes: ShortcodeDefs = shortcodeReq.default || shortcodeReq; shortcodesJs = shortcodes.map((shortcode) => ({ ...shortcode, $$meta: { @@ -399,26 +350,7 @@ class Elder { })); } catch (err) { if (err.code === 'MODULE_NOT_FOUND') { - if (buildFolder && buildFolder.length > 0) { - try { - const shortcodeBuildFile: ShortcodeDefs = config.typescript - ? require(shortcodeBuildPath).default - : require(shortcodeBuildPath); - shortcodesJs = shortcodeBuildFile.map((shortcode) => ({ - ...shortcode, - $$meta: { - type: 'shortcodes.js', - addedBy: 'shortcodes.js', - }, - })); - } catch (err2) { - if (err2.code !== 'MODULE_NOT_FOUND') { - console.error(err); - } - } - } else if (this.settings.debug.automagic) { - console.log(`No luck finding that hooks file. You can add one at ${shortcodeBuildPath}`); - } + console.error(`Could not load hooks file from ${shortcodeSrcPath}.`); } else { console.error(err); } diff --git a/src/externalHelpers.ts b/src/externalHelpers.ts index db267c95..57c4c508 100644 --- a/src/externalHelpers.ts +++ b/src/externalHelpers.ts @@ -7,16 +7,11 @@ import { ExternalHelperRequestOptions } from './utils/types'; let userHelpers; -const cache = {}; +let cache; async function externalHelpers({ settings, query, helpers }: ExternalHelperRequestOptions) { - const srcFolder = path.join(process.cwd(), settings.locations.srcFolder); - const buildFolder = path.join(process.cwd(), settings.locations.buildFolder); - const helperFilePath = `helpers/index.js`; - - const srcHelpers = path.join(srcFolder, helperFilePath); - const buildHelpers = path.join(buildFolder, helperFilePath); - if (!cache[helperFilePath]) { + const srcHelpers = path.join(settings.srcDir, 'helpers/index.js'); + if (!cache) { try { fs.statSync(srcHelpers); userHelpers = require(srcHelpers); @@ -24,21 +19,8 @@ async function externalHelpers({ settings, query, helpers }: ExternalHelperReque if (typeof userHelpers === 'function') { userHelpers = await userHelpers({ settings, query, helpers }); } - cache[helperFilePath] = userHelpers; + cache = userHelpers; } catch (err) { - if (settings.locations.buildFolder && settings.locations.buildFolder.length > 0) { - try { - fs.statSync(buildHelpers); - userHelpers = require(buildHelpers); - if (typeof userHelpers === 'function') { - userHelpers = await userHelpers({ settings, query, helpers }); - } - cache[helperFilePath] = userHelpers; - } catch (e) { - console.error(e); - } - } - if (err.code === 'ENOENT') { if (settings.debug.automagic) { console.log( @@ -48,13 +30,7 @@ async function externalHelpers({ settings, query, helpers }: ExternalHelperReque } } } else { - userHelpers = cache[helperFilePath]; - } - - if (userHelpers && Object.keys(userHelpers).length > 0) { - if (settings.debug.automagic) { - console.log(`debug.automagic:: We're add in helpers to the helpers object from the file at: ${helperFilePath}.`); - } + userHelpers = cache; } return userHelpers; diff --git a/src/hooks.ts b/src/hooks.ts index af79683d..0bce1edc 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -2,7 +2,7 @@ import path from 'path'; import fs from 'fs-extra'; import { parseBuildPerf } from './utils'; import externalHelpers from './externalHelpers'; -import { HookOptions } from './hookInterface/types'; +import { HookOptions, Hook } from './hookInterface/types'; import prepareShortcodeParser from './utils/prepareShortcodeParser'; const hooks: Array = [ @@ -112,32 +112,23 @@ const hooks: Array = [ name: 'elderAddDefaultIntersectionObserver', description: 'Sets up the default polyfill for the intersection observer', priority: 100, - run: async ({ beforeHydrateStack, settings }) => { - if (settings && settings.locations && {}.hasOwnProperty.call(settings.locations, 'intersectionObserverPoly')) { - if (settings.locations.intersectionObserverPoly) { - return { - beforeHydrateStack: [ - { - source: 'elderAddDefaultIntersectionObserver', - string: ``, - priority: 100, - }, - ...beforeHydrateStack, - ], - }; - } - } else { - console.log( - 'Not injecting intersection observer polyfill. To not see this warning set locations.intersectionObserverPoly = false in elder.config.js.', - ); - } - return null; + priority: 100, + }, + ...beforeHydrateStack, + ], + }; }, }, { @@ -145,35 +136,26 @@ const hooks: Array = [ name: 'elderAddSystemJs', description: 'AddsSystemJs to beforeHydrateStack also add preloading of systemjs to the headStack.', priority: 1, - run: async ({ beforeHydrateStack, headStack, settings }) => { - if (settings && settings.locations && {}.hasOwnProperty.call(settings.locations, 'systemJs')) { - if (settings.locations.systemJs) { - return { - beforeHydrateStack: [ - { - source: 'elderAddSystemJs', - string: ``, - priority: 99, - }, - ...beforeHydrateStack, - ], + run: async ({ beforeHydrateStack, headStack }) => { + return { + beforeHydrateStack: [ + { + source: 'elderAddSystemJs', + string: ``, + priority: 99, + }, + ...beforeHydrateStack, + ], - headStack: [ - { - source: 'elderAddSystemJs', - string: ``, - priority: 99, - }, - ...headStack, - ], - }; - } - } else { - console.log( - 'Not injecting systemjs. To not see this warning set locations.systemJs = false in elder.config.js.', - ); - } - return null; + headStack: [ + { + source: 'elderAddSystemJs', + string: ``, + priority: 99, + }, + ...headStack, + ], + }; }, }, { @@ -204,7 +186,7 @@ const hooks: Array = [ priority: 1, run: async ({ settings, request, htmlString, errors }) => { if (settings.build) { - const file = path.resolve(process.cwd(), `${settings.locations.public}${request.permalink}/index.html`); + const file = path.resolve(settings.paths.distDir, `.${request.permalink}/index.html`); try { fs.outputFileSync(file, htmlString); } catch (e) { @@ -253,7 +235,7 @@ const hooks: Array = [ priority: 50, run: async ({ errors, settings }) => { if (errors && errors.length > 0) { - const buildOutputLocation = path.resolve(process.cwd(), `./___ELDER___/build-${Date.now()}.json`); + const buildOutputLocation = path.resolve(settings.paths.rootDir, `./___ELDER___/build-${Date.now()}.json`); console.log(`Writing details on the ${errors.length} build errors to: ${buildOutputLocation}`); fs.writeJSONSync(buildOutputLocation, { errors, settings }); } diff --git a/src/routes/routes.ts b/src/routes/routes.ts index 0c18c14b..43df85dc 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -1,7 +1,6 @@ /* eslint-disable global-require */ /* eslint-disable import/no-dynamic-require */ import glob from 'glob'; -import path from 'path'; import type { RouteOptions } from './types'; import { svelteComponent, capitalizeFirstLetter } from '../utils'; @@ -15,14 +14,9 @@ function routes(settings: ConfigOptions) { `, ); - const srcFolder = path.join(process.cwd(), settings.locations.srcFolder); - const buildFolder = path.join(process.cwd(), settings.locations.buildFolder); - let files = glob.sync(`${srcFolder}/routes/*/+(*.js|*.svelte)`); - if (settings.locations.buildFolder && settings.locations.buildFolder.length > 0) { - files = [...files, ...glob.sync(`${buildFolder}/routes/*/+(*.js|*.svelte)`)]; - } + const files = glob.sync(`${settings.paths.srcDir}/routes/*/+(*.js|*.svelte)`); - const ssrFolder = path.resolve(process.cwd(), settings.locations.svelte.ssrComponents); + const ssrFolder = settings.paths.ssrComponents; const ssrComponents = glob.sync(`${ssrFolder}/*.js`); @@ -31,8 +25,9 @@ function routes(settings: ConfigOptions) { const output = routejsFiles.reduce((out, cv) => { const routeName = cv.replace('/route.js', '').split('/').pop(); const capitalizedRoute = capitalizeFirstLetter(routeName); - // we need to look in the /build/ folder for all /src/ when it is typescript - const route: RouteOptions = settings.typescript ? require(cv).default : require(cv); + + const routeReq = require(cv); + const route: RouteOptions = routeReq.default || routeReq; const filesForThisRoute = files .filter((r) => r.includes(`/routes/${routeName}`)) .filter((r) => !r.includes('route.js')); @@ -51,7 +46,7 @@ function routes(settings: ConfigOptions) { const ssrComponent = ssrComponents.find((f) => f.endsWith(`${componentName}.js`)); if (!ssrComponent) { console.error( - `We see you want to load ${route.template}, but we don't see a compiled template in ${settings.locations.svelte.ssrComponents}. You'll probably see more errors in a second. Make sure you've run rollup.`, + `We see you want to load ${route.template}, but we don't see a compiled template in ${settings.paths.ssrComponents}. You'll probably see more errors in a second. Make sure you've run rollup.`, ); } @@ -74,7 +69,7 @@ function routes(settings: ConfigOptions) { const ssrComponent = ssrComponents.find((f) => f.endsWith(`${capitalizedRoute}.js`)); if (!ssrComponent) { console.error( - `We see you want to load ${route.template}, but we don't see a compiled template in ${settings.locations.svelte.ssrComponents}. You'll probably see more errors in a second. Make sure you've run rollup.`, + `We see you want to load ${route.template}, but we don't see a compiled template in ${settings.paths.ssrComponents}. You'll probably see more errors in a second. Make sure you've run rollup.`, ); } } else { @@ -98,9 +93,10 @@ function routes(settings: ConfigOptions) { const dataFile = filesForThisRoute.find((f) => f.endsWith(`data.js`)); if (dataFile) { // TODO: v1 removal - route.data = settings.typescript ? require(dataFile).default : require(dataFile); + const dataReq = require(dataFile); + route.data = dataReq.default || dataReq; console.warn( - `WARN: Loading your /routes/${routeName}/data.js file. This functionality is depricated. Please include your data function in your /routes/${routeName}/route.js object under the 'data' key. As a quick fix you can just import the existing data file and include it as "data" key.`, + `WARN: Loading your /routes/${routeName}/data.js file. This functionality is deprecated. Please include your data function in your /routes/${routeName}/route.js object under the 'data' key. As a quick fix you can just import the existing data file and include it as "data" key.`, ); } else { route.data = (page) => { diff --git a/src/utils/getConfig.ts b/src/utils/getConfig.ts index cb6364b6..49c9ab85 100644 --- a/src/utils/getConfig.ts +++ b/src/utils/getConfig.ts @@ -3,9 +3,7 @@ import defaultsDeep from 'lodash.defaultsdeep'; import path from 'path'; import fs from 'fs'; import { ConfigOptions } from './types'; -import { getDefaultConfig, validateShortcode } from './validations'; -import tsConfigExist from './tsConfigExist'; -import shortcodes from '../shortcodes'; +import { getDefaultConfig } from './validations'; function getConfig(context?: string): ConfigOptions { const explorerSync = cosmiconfigSync('elder'); @@ -18,47 +16,21 @@ function getConfig(context?: string): ConfigOptions { const defaultConfig = getDefaultConfig(); const config: ConfigOptions = defaultsDeep(loadedConfig, defaultConfig); + const rootDir = config.rootDir === 'process.cwd()' ? process.cwd() : path.resolve(config.rootDir); + config.paths = { + rootDir, + srcDir: path.resolve(rootDir, config.srcDir), + distDir: path.resolve(rootDir, config.distDir), + ssrComponents: path.resolve(rootDir, './___ELDER___/compiled/'), + clientComponents: path.resolve(config.distDir, './svelte/'), + }; + if (config.debug.automagic && (!context || context !== 'build')) { console.log( `debug.automagic:: Your elder.config.js has debug.automagic = true. We call this chatty mode, but it is designed to show you the things we're doing automatically so you're aware. To turn it off set debug.automagic = 'false'`, ); } - if (!config.typescript) { - config.typescript = tsConfigExist(); - } - - if (config.typescript) { - if (config.locations.buildFolder === '') { - try { - const tsConfigLocation = path.resolve(process.cwd(), './tsconfig.json'); - const tsConfig = JSON.parse(fs.readFileSync(tsConfigLocation, { encoding: 'utf-8' })); - - if (tsConfig.compilerOptions.outDir) { - if (!tsConfig.compilerOptions.outDir.includes('/')) { - config.locations.buildFolder = `./${tsConfig.compilerOptions.outDir}/`; - if (config.debug.automagic && (!context || context !== 'build')) { - console.log( - `debug.automagic:: Automatically setting your location.buildFolder = "${config.locations.buildFolder} 'in your elder.config.js file as we detected it from your tsconfig.json`, - ); - } - } else if (config.debug.automagic && (!context || context !== 'build')) { - console.log( - `debug.automagic:: Unable to automatically set your build folder from your tsconfig. Please add it to your elder.config.js. We saw ${tsConfig.compilerOptions.outDir} and didn't know how to parse it as we're still typescript newbies. Want to help us? We'd love a PR to make this more robust.`, - ); - } - } - } catch (e) { - if (config.debug.automagic && (!context || context !== 'build')) { - console.log( - `debug.automagic:: Tried to read ./tsconfig.json to set srcDirectory in your elder.config.js file, but something went wrong. This often happens if there is a // in your file to comment out a setting. If you are using typescript and are building to a separate folder please define where your javascript files can be found by defining 'locations.buildFolder'. Here is the error: `, - e, - ); - } - } - } - } - return config; } diff --git a/src/utils/getHashedSvelteComponents.ts b/src/utils/getHashedSvelteComponents.ts index 54f943d8..648aac43 100644 --- a/src/utils/getHashedSvelteComponents.ts +++ b/src/utils/getHashedSvelteComponents.ts @@ -15,8 +15,8 @@ const getHashedSvelteComponents = (config) => { if (!ready) { ready = true; - const ssrFiles = glob.sync(`${path.resolve(process.cwd(), config.locations.svelte.ssrComponents)}/*.js`, {}); - const clientFiles = glob.sync(`${path.resolve(process.cwd(), config.locations.svelte.clientComponents)}/*.js`, {}); + const ssrFiles = glob.sync(`${config.paths.ssrComponents}/*.js`, {}); + const clientFiles = glob.sync(`${config.paths.clientComponents}/*.js`, {}); // get an array with jus the file name before .js; // CityResults.js => CityResults diff --git a/src/utils/getRollupConfig.ts b/src/utils/getRollupConfig.ts index b235b1e6..c0ddde3a 100644 --- a/src/utils/getRollupConfig.ts +++ b/src/utils/getRollupConfig.ts @@ -108,8 +108,10 @@ function createSSRConfig({ input, output, svelteConfig, multiInputConfig = false } export default function getRollupConfig({ svelteConfig }) { - const { locations } = getElderConfig(); - const { ssrComponents, clientComponents } = locations.svelte; + const elderConfig = getElderConfig(); + const { ssrComponents, clientComponents, distDir, srcDir, rootDir } = elderConfig.paths; + + console.log(ssrComponents, clientComponents); console.log( `rollup production === ${production}. ${!process.env.ROLLUP_WATCH ? 'Because watch is undefined' : ''}. ${ @@ -123,30 +125,28 @@ export default function getRollupConfig({ svelteConfig }) { del.sync([`${ssrComponents}*`, `${clientComponents}*`]); // Add ElderJs Peer deps to public if they exist. - const elderJsPeerDeps = [ - ['./node_modules/intersection-observer/intersection-observer.js', 'intersectionObserverPoly'], - ['./node_modules/systemjs/dist/s.min.js', 'systemJs'], + [ + ['./node_modules/intersection-observer/intersection-observer.js', './static/intersection-observer.js'], + ['./node_modules/systemjs/dist/s.min.js', './static/s.min.js'], ] - .filter((dep) => fs.existsSync(path.resolve(process.cwd(), dep[0]))) - .map((dep) => { - return { + .filter((dep) => fs.existsSync(path.resolve(rootDir, dep[0]))) + .forEach((dep) => { + configs.push({ input: dep[0], output: [ { - file: path.resolve(process.cwd(), `${locations.public}${locations[dep[1]]}`), + file: path.resolve(distDir, dep[1]), format: 'iife', name: dep[1], plugins: [terser()], }, ], - }; + }); }); - configs = [...configs, ...elderJsPeerDeps]; - // SSR /routes/ Svelte files. - const templates = glob.sync('./src/routes/*/*.svelte').reduce((out, cv) => { - const file = cv.replace(`${__dirname}/`, ''); + const templates = glob.sync(`${elderConfig.srcDir}/routes/*/*.svelte`).reduce((out, cv) => { + const file = cv.replace(`${rootDir}/`, ''); out.push( createSSRConfig({ input: file, @@ -162,8 +162,8 @@ export default function getRollupConfig({ svelteConfig }) { }, []); // SSR /layouts/ Svelte files. - const layouts = glob.sync('./src/layouts/*.svelte').reduce((out, cv) => { - const file = cv.replace(`${__dirname}/`, ''); + const layouts = glob.sync(`${elderConfig.srcDir}/layouts/*.svelte`).reduce((out, cv) => { + const file = cv.replace(`${rootDir}/`, ''); out.push( createSSRConfig({ input: file, @@ -182,10 +182,10 @@ export default function getRollupConfig({ svelteConfig }) { if (production) { // production build does bundle splitting, minification, and babel configs = [...configs, ...templates, ...layouts]; - if (fs.existsSync(path.resolve(`./src/components/`))) { + if (fs.existsSync(path.resolve(srcDir, `./components/`))) { configs.push( createBrowserConfig({ - input: ['src/components/*/*.svelte'], + input: [`${elderConfig.srcDir}/components/*/*.svelte`], output: { dir: clientComponents, entryFileNames: 'entry[name]-[hash].js', @@ -193,23 +193,23 @@ export default function getRollupConfig({ svelteConfig }) { format: 'system', }, multiInputConfig: multiInput({ - relative: 'src/components/', - transformOutputPath: (output, input) => `${path.basename(output)}`, + relative: `${elderConfig.srcDir}/components`, + transformOutputPath: (output) => `${path.basename(output)}`, }), svelteConfig, }), ); configs.push( createSSRConfig({ - input: ['src/components/*/*.svelte'], + input: [`${elderConfig.srcDir}/components/*/*.svelte`], output: { dir: ssrComponents, format: 'cjs', exports: 'auto', }, multiInputConfig: multiInput({ - relative: 'src/components/', - transformOutputPath: (output, input) => `${path.basename(output)}`, + relative: `${elderConfig.srcDir}/components`, + transformOutputPath: (output) => `${path.basename(output)}`, }), svelteConfig, }), @@ -218,10 +218,9 @@ export default function getRollupConfig({ svelteConfig }) { } else { // watch/dev build bundles each component individually for faster reload times during dev. let sharedComponents = []; - if (fs.existsSync(path.resolve(`./src/components/`))) { - sharedComponents = glob.sync(path.resolve(__dirname, './src/components/*/*.svelte')).reduce((out, cv) => { - const file = cv.replace(`${__dirname}/`, ''); - // console.log(file, cv);; + if (fs.existsSync(path.resolve(srcDir, `./components/`))) { + sharedComponents = glob.sync(path.resolve(srcDir, './components/*/*.svelte')).reduce((out, cv) => { + const file = cv.replace(`${rootDir}/`, ''); out.push( createBrowserConfig({ input: file, diff --git a/src/utils/svelteComponent.ts b/src/utils/svelteComponent.ts index 02e6ae19..505d5a7f 100644 --- a/src/utils/svelteComponent.ts +++ b/src/utils/svelteComponent.ts @@ -29,21 +29,17 @@ const svelteComponent = (componentName) => ({ page, props, hydrateOptions }: Com if (!componentCache[cleanComponentName]) { const clientComponents = page.settings.$$internal.hashedComponents; - const ssrComponent = path.resolve( - process.cwd(), - `./${page.settings.locations.svelte.ssrComponents}${cleanComponentName}.js`, - ); - let clientSvelteFolder = page.settings.locations.svelte.clientComponents.replace( - page.settings.locations.public, - '/', - ); + const ssrComponent = path.resolve(page.settings.paths.ssrComponents, `./${cleanComponentName}.js`); + let clientSvelteFolder = page.settings.paths.clientComponents.replace(page.settings.paths.distDir, ''); if (clientSvelteFolder.indexOf('.') === 0) clientSvelteFolder = clientSvelteFolder.substring(1); + console.log(clientComponents, cleanComponentName); + // eslint-disable-next-line global-require, import/no-dynamic-require const { render } = require(ssrComponent); componentCache[cleanComponentName] = { render, - clientSrc: `${clientSvelteFolder}${clientComponents[cleanComponentName]}.js`, + clientSrc: `${clientSvelteFolder}/${clientComponents[cleanComponentName]}.js`, }; } diff --git a/src/utils/tsConfigExist.ts b/src/utils/tsConfigExist.ts deleted file mode 100644 index bc9b7029..00000000 --- a/src/utils/tsConfigExist.ts +++ /dev/null @@ -1,16 +0,0 @@ -import path from 'path'; -import fs from 'fs'; - -export default function tsConfigExist() { - const tsConfigPath = path.join(process.cwd(), 'tsconfig.json'); - try { - fs.statSync(tsConfigPath); - return true; - } catch (err) { - if (err.code === 'ENOENT') { - return false; - } - // unexpected error - throw err; - } -} diff --git a/src/utils/types.ts b/src/utils/types.ts index b38a63c2..cc5716af 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -10,10 +10,10 @@ type BuildOptions = { shuffleRequests: boolean; }; -type SvelteOptions = { - ssrComponents: string; - clientComponents: string; -}; +// type SvelteOptions = { +// ssrComponents: string; +// clientComponents: string; +// }; type DebugOptions = { stacks: boolean; @@ -23,31 +23,40 @@ type DebugOptions = { automagic: boolean; }; -type LocationOptions = { - assets: string; - public: string; - svelte: SvelteOptions; - systemJs: string; - intersectionObserverPoly: string; - srcFolder: string; - buildFolder: string; +type PathOptions = { + // assets: string; + // public: string; + // svelte: SvelteOptions; + // systemJs: string; + // intersectionObserverPoly: string; + // srcFolder: string; + // buildFolder: string; + + ssrComponents: string; + clientComponents: string; + distDir: string; + srcDir: string; + rootDir: string; }; export type ConfigOptions = { + distDir: string; + srcDir: string; + rootDir: string; + server: ServerOptions; build: BuildOptions; - locations: LocationOptions; + paths: PathOptions; debug: DebugOptions; plugins?: any; hooks: { disable?: string[]; }; - typescript: boolean; + // typescript: boolean; worker: boolean; shortcodes: { openPattern: string; closePattern: string; - customShortcodes: ShortcodeDefs; }; }; diff --git a/src/utils/validations.ts b/src/utils/validations.ts index b8ca4df2..9713cdf0 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -1,4 +1,5 @@ import * as yup from 'yup'; +import path from 'path'; import type { ConfigOptions, PluginOptions, ShortcodeDef } from './types'; import type { RouteOptions } from '../routes/types'; import type { HookOptions } from '../hookInterface/types'; @@ -19,70 +20,83 @@ const shortcodeSchema = yup.object({ const configSchema = yup.object({ siteUrl: yup.string().notRequired().default('').label(`The domain your site is hosted on. https://yourdomain.com.`), - locations: yup - .object({ - assets: yup - .string() - .notRequired() - .default('./public/dist/static/') - .label( - 'Where your site\'s assets files should be written to if you are using the Elder.js template. (Include ./public/)"', - ), - public: yup - .string() - .notRequired() - .default('./public/') - .label( - 'Where should files be written? This represents the "root" of your site and where your html will be built.', - ), - svelte: yup - .object() - .shape({ - ssrComponents: yup - .string() - .notRequired() - .default('./___ELDER___/compiled/') - .label('Location where should SSR components be stored.'), - clientComponents: yup - .string() - .notRequired() - .default('./public/dist/svelte/') - .label( - 'Location where Svelte components that are bundled for the client should be saved. (Include ./public/)', - ), - }) - .notRequired(), - systemJs: yup - .string() - .notRequired() - .default('/dist/static/s.min.js') - .label( - 'If you are using the recommended Elder.js rollup file it is using Systemjs. This defines is where the systemjs file will be found on your site. (exclude /public/)', - ), - srcFolder: yup - .string() - .notRequired() - .default('./src/') - .label('Elder.js and plugins use this to resolve where things should be in the expected file structure.'), + rootDir: yup.string().notRequired().default('process.cwd()').label('Here your package.json lives.'), + distDir: yup + .string() + .notRequired() + .default('public') + .label('Where should files be written? This represents the "root" of your site and where your html will be built.'), + srcDir: yup + .string() + .notRequired() + .default('src') + .label( + "Where Elder.js should find it's expected file structure. If you are using a build step such as typescript on your project, you may need to edit this. ", + ), + // locations: yup + // .object({ + // // assets: yup + // // .string() + // // .notRequired() + // // .default('./public/dist/static/') + // // .label( + // // 'Where your site\'s assets files should be written to if you are using the Elder.js template. (Include ./public/)"', + // // ), + // // public: yup + // // .string() + // // .notRequired() + // // .default('./public/') + // // .label( + // // 'Where should files be written? This represents the "root" of your site and where your html will be built.', + // // ), + // svelte: yup + // .object() + // .shape({ + // ssrComponents: yup + // .string() + // .notRequired() + // .default('./___ELDER___/compiled/') + // .label('Location where should SSR components be stored.'), + // clientComponents: yup + // .string() + // .notRequired() + // .default('./public/dist/svelte/') + // .label( + // 'Location where Svelte components that are bundled for the client should be saved. (Include ./public/)', + // ), + // }) + // .notRequired(), + // systemJs: yup + // .string() + // .notRequired() + // .default('/dist/static/s.min.js') + // .label( + // 'If you are using the recommended Elder.js rollup file it is using Systemjs. This defines is where the systemjs file will be found on your site. (exclude /public/)', + // ), + // srcFolder: yup + // .string() + // .notRequired() + // .default('./src/') + // .label('Elder.js and plugins use this to resolve where things should be in the expected file structure.'), - buildFolder: yup - .string() - .notRequired() - .default('') - .label( - `If Elder.js doesn't find the files it is looking for in the src folder, it will look in the build folder. (used for typescript)`, - ), + // buildFolder: yup + // .string() + // .notRequired() + // .default('') + // .label( + // `If Elder.js doesn't find the files it is looking for in the src folder, it will look in the build folder. (used for typescript)`, + // ), - intersectionObserverPoly: yup - .string() - .notRequired() - .default('/dist/static/intersection-observer.js') - .label( - 'Elder.js uses a poly fill for the intersection observer. This is where it will be found on your site. (exclude /public/)', - ), - }) - .notRequired() - .label('Where various files are written and read from.'), + // intersectionObserverPoly: yup + // .string() + // .notRequired() + // .default('/dist/static/intersection-observer.js') + // .label( + // 'Elder.js uses a poly fill for the intersection observer. This is where it will be found on your site. (exclude /public/)', + // ), + // }) + // .notRequired() + // .label('Where various files are written and read from.'), debug: yup .object() .shape({ From a35db24588e1a2f977dfb3c50f46a572f396ea1c Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Wed, 16 Sep 2020 15:30:02 -0400 Subject: [PATCH 19/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20further=20simplify?= =?UTF-8?q?=20the=20settings/config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Elder.ts | 7 ++----- src/hooks.ts | 4 ++-- src/routes/routes.ts | 8 ++++---- src/utils/getConfig.ts | 18 ++++++++++++------ src/utils/getHashedSvelteComponents.ts | 6 +++--- src/utils/getRollupConfig.ts | 24 +++++++++++------------- src/utils/svelteComponent.ts | 6 ++---- src/utils/types.ts | 10 +++++----- 8 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/Elder.ts b/src/Elder.ts index 9c522606..9b60dcd6 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -86,9 +86,6 @@ class Elder { ...config, server: context === 'server' && config[context], build: context === 'build' && config[context], - $$internal: { - hashedComponents: getHashedSvelteComponents(config), - }, }; if (context === 'build' && worker) { @@ -124,7 +121,7 @@ class Elder { } if (!plugin) { - const pkgPath = path.resolve(this.settings.paths.rootDir, './node_modules/', pluginName); + const pkgPath = path.resolve(this.settings.rootDir, './node_modules/', pluginName); if (fs.existsSync(pkgPath)) { // eslint-disable-next-line import/no-dynamic-require const pluginPackageJson = require(path.resolve(pkgPath, './package.json')); @@ -215,7 +212,7 @@ class Elder { plugin.routes[routeName].template.endsWith('.svelte') ) { const templateName = plugin.routes[routeName].template.replace('.svelte', ''); - const ssrComponent = path.resolve(this.settings.paths.ssrComponents, `${templateName}.js`); + const ssrComponent = path.resolve(this.settings.$$internal.ssrComponents, `${templateName}.js`); if (!fs.existsSync(ssrComponent)) { console.warn( diff --git a/src/hooks.ts b/src/hooks.ts index 0bce1edc..c4c8f1fb 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -186,7 +186,7 @@ const hooks: Array = [ priority: 1, run: async ({ settings, request, htmlString, errors }) => { if (settings.build) { - const file = path.resolve(settings.paths.distDir, `.${request.permalink}/index.html`); + const file = path.resolve(settings.distDir, `.${request.permalink}/index.html`); try { fs.outputFileSync(file, htmlString); } catch (e) { @@ -235,7 +235,7 @@ const hooks: Array = [ priority: 50, run: async ({ errors, settings }) => { if (errors && errors.length > 0) { - const buildOutputLocation = path.resolve(settings.paths.rootDir, `./___ELDER___/build-${Date.now()}.json`); + const buildOutputLocation = path.resolve(settings.rootDir, `./___ELDER___/build-${Date.now()}.json`); console.log(`Writing details on the ${errors.length} build errors to: ${buildOutputLocation}`); fs.writeJSONSync(buildOutputLocation, { errors, settings }); } diff --git a/src/routes/routes.ts b/src/routes/routes.ts index 43df85dc..225f9963 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -14,9 +14,9 @@ function routes(settings: ConfigOptions) { `, ); - const files = glob.sync(`${settings.paths.srcDir}/routes/*/+(*.js|*.svelte)`); + const files = glob.sync(`${settings.srcDir}/routes/*/+(*.js|*.svelte)`); - const ssrFolder = settings.paths.ssrComponents; + const ssrFolder = settings.$$internal.ssrComponents; const ssrComponents = glob.sync(`${ssrFolder}/*.js`); @@ -46,7 +46,7 @@ function routes(settings: ConfigOptions) { const ssrComponent = ssrComponents.find((f) => f.endsWith(`${componentName}.js`)); if (!ssrComponent) { console.error( - `We see you want to load ${route.template}, but we don't see a compiled template in ${settings.paths.ssrComponents}. You'll probably see more errors in a second. Make sure you've run rollup.`, + `We see you want to load ${route.template}, but we don't see a compiled template in ${settings.$$internal.ssrComponents}. You'll probably see more errors in a second. Make sure you've run rollup.`, ); } @@ -69,7 +69,7 @@ function routes(settings: ConfigOptions) { const ssrComponent = ssrComponents.find((f) => f.endsWith(`${capitalizedRoute}.js`)); if (!ssrComponent) { console.error( - `We see you want to load ${route.template}, but we don't see a compiled template in ${settings.paths.ssrComponents}. You'll probably see more errors in a second. Make sure you've run rollup.`, + `We see you want to load ${route.template}, but we don't see a compiled template in ${settings.$$internal.ssrComponents}. You'll probably see more errors in a second. Make sure you've run rollup.`, ); } } else { diff --git a/src/utils/getConfig.ts b/src/utils/getConfig.ts index 49c9ab85..bcb2dcd1 100644 --- a/src/utils/getConfig.ts +++ b/src/utils/getConfig.ts @@ -4,6 +4,7 @@ import path from 'path'; import fs from 'fs'; import { ConfigOptions } from './types'; import { getDefaultConfig } from './validations'; +import getHashedSvelteComponents from './getHashedSvelteComponents'; function getConfig(context?: string): ConfigOptions { const explorerSync = cosmiconfigSync('elder'); @@ -17,12 +18,17 @@ function getConfig(context?: string): ConfigOptions { const config: ConfigOptions = defaultsDeep(loadedConfig, defaultConfig); const rootDir = config.rootDir === 'process.cwd()' ? process.cwd() : path.resolve(config.rootDir); - config.paths = { - rootDir, - srcDir: path.resolve(rootDir, config.srcDir), - distDir: path.resolve(rootDir, config.distDir), - ssrComponents: path.resolve(rootDir, './___ELDER___/compiled/'), - clientComponents: path.resolve(config.distDir, './svelte/'), + config.rootDir = rootDir; + config.srcDir = path.resolve(rootDir, config.srcDir); + config.distDir = path.resolve(rootDir, config.distDir); + + const ssrComponents = path.resolve(config.rootDir, './___ELDER___/compiled/'); + const clientComponents = path.resolve(config.distDir, './svelte/'); + + config.$$internal = { + ssrComponents, + clientComponents, + hashedComponents: getHashedSvelteComponents({ ssrComponents, clientComponents }), }; if (config.debug.automagic && (!context || context !== 'build')) { diff --git a/src/utils/getHashedSvelteComponents.ts b/src/utils/getHashedSvelteComponents.ts index 648aac43..ae5b270b 100644 --- a/src/utils/getHashedSvelteComponents.ts +++ b/src/utils/getHashedSvelteComponents.ts @@ -11,12 +11,12 @@ let ready = false; * * @returns {Object} */ -const getHashedSvelteComponents = (config) => { +const getHashedSvelteComponents = ({ ssrComponents, clientComponents }) => { if (!ready) { ready = true; - const ssrFiles = glob.sync(`${config.paths.ssrComponents}/*.js`, {}); - const clientFiles = glob.sync(`${config.paths.clientComponents}/*.js`, {}); + const ssrFiles = glob.sync(`${ssrComponents}/*.js`, {}); + const clientFiles = glob.sync(`${clientComponents}/*.js`, {}); // get an array with jus the file name before .js; // CityResults.js => CityResults diff --git a/src/utils/getRollupConfig.ts b/src/utils/getRollupConfig.ts index c0ddde3a..32171bd3 100644 --- a/src/utils/getRollupConfig.ts +++ b/src/utils/getRollupConfig.ts @@ -109,15 +109,12 @@ function createSSRConfig({ input, output, svelteConfig, multiInputConfig = false export default function getRollupConfig({ svelteConfig }) { const elderConfig = getElderConfig(); - const { ssrComponents, clientComponents, distDir, srcDir, rootDir } = elderConfig.paths; + const { $$internal, distDir, srcDir, rootDir } = elderConfig; + const { ssrComponents, clientComponents } = $$internal; - console.log(ssrComponents, clientComponents); + const relSrcDir = srcDir.replace(rootDir, '').substr(1); - console.log( - `rollup production === ${production}. ${!process.env.ROLLUP_WATCH ? 'Because watch is undefined' : ''}. ${ - process.env.NODE_ENV === 'production' ? 'Because NODE_ENV === Production' : '' - }`, - ); + console.log(`Elder.js using rollup in ${production ? 'production' : 'development'} mode.`); let configs = []; @@ -145,7 +142,7 @@ export default function getRollupConfig({ svelteConfig }) { }); // SSR /routes/ Svelte files. - const templates = glob.sync(`${elderConfig.srcDir}/routes/*/*.svelte`).reduce((out, cv) => { + const templates = glob.sync(`${relSrcDir}/routes/*/*.svelte`).reduce((out, cv) => { const file = cv.replace(`${rootDir}/`, ''); out.push( createSSRConfig({ @@ -162,7 +159,7 @@ export default function getRollupConfig({ svelteConfig }) { }, []); // SSR /layouts/ Svelte files. - const layouts = glob.sync(`${elderConfig.srcDir}/layouts/*.svelte`).reduce((out, cv) => { + const layouts = glob.sync(`${relSrcDir}/layouts/*.svelte`).reduce((out, cv) => { const file = cv.replace(`${rootDir}/`, ''); out.push( createSSRConfig({ @@ -183,9 +180,10 @@ export default function getRollupConfig({ svelteConfig }) { // production build does bundle splitting, minification, and babel configs = [...configs, ...templates, ...layouts]; if (fs.existsSync(path.resolve(srcDir, `./components/`))) { + console.log(`${relSrcDir}/components/*/*.svelte`); configs.push( createBrowserConfig({ - input: [`${elderConfig.srcDir}/components/*/*.svelte`], + input: [`${relSrcDir}/components/*/*.svelte`], output: { dir: clientComponents, entryFileNames: 'entry[name]-[hash].js', @@ -193,7 +191,7 @@ export default function getRollupConfig({ svelteConfig }) { format: 'system', }, multiInputConfig: multiInput({ - relative: `${elderConfig.srcDir}/components`, + relative: `${relSrcDir}/components`, transformOutputPath: (output) => `${path.basename(output)}`, }), svelteConfig, @@ -201,14 +199,14 @@ export default function getRollupConfig({ svelteConfig }) { ); configs.push( createSSRConfig({ - input: [`${elderConfig.srcDir}/components/*/*.svelte`], + input: [`${relSrcDir}/components/*/*.svelte`], output: { dir: ssrComponents, format: 'cjs', exports: 'auto', }, multiInputConfig: multiInput({ - relative: `${elderConfig.srcDir}/components`, + relative: `${relSrcDir}/components`, transformOutputPath: (output) => `${path.basename(output)}`, }), svelteConfig, diff --git a/src/utils/svelteComponent.ts b/src/utils/svelteComponent.ts index 505d5a7f..1d4ab708 100644 --- a/src/utils/svelteComponent.ts +++ b/src/utils/svelteComponent.ts @@ -29,12 +29,10 @@ const svelteComponent = (componentName) => ({ page, props, hydrateOptions }: Com if (!componentCache[cleanComponentName]) { const clientComponents = page.settings.$$internal.hashedComponents; - const ssrComponent = path.resolve(page.settings.paths.ssrComponents, `./${cleanComponentName}.js`); - let clientSvelteFolder = page.settings.paths.clientComponents.replace(page.settings.paths.distDir, ''); + const ssrComponent = path.resolve(page.settings.$$internal.ssrComponents, `./${cleanComponentName}.js`); + let clientSvelteFolder = page.settings.$$internal.clientComponents.replace(page.settings.distDir, ''); if (clientSvelteFolder.indexOf('.') === 0) clientSvelteFolder = clientSvelteFolder.substring(1); - console.log(clientComponents, cleanComponentName); - // eslint-disable-next-line global-require, import/no-dynamic-require const { render } = require(ssrComponent); componentCache[cleanComponentName] = { diff --git a/src/utils/types.ts b/src/utils/types.ts index cc5716af..347ac958 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -32,8 +32,6 @@ type PathOptions = { // srcFolder: string; // buildFolder: string; - ssrComponents: string; - clientComponents: string; distDir: string; srcDir: string; rootDir: string; @@ -46,7 +44,7 @@ export type ConfigOptions = { server: ServerOptions; build: BuildOptions; - paths: PathOptions; + // paths: PathOptions; debug: DebugOptions; plugins?: any; hooks: { @@ -58,16 +56,18 @@ export type ConfigOptions = { openPattern: string; closePattern: string; }; + $$internal: Internal; }; type Internal = { - hashedComponents: {}; + hashedComponents?: {}; + ssrComponents: string; + clientComponents: string; }; export type SettingOptions = { server: boolean; build: boolean; - $$internal: Internal; }; export type QueryOptions = { From b2dd3b2d4e198ffac676a0e0745f3b87ab8042c2 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Wed, 16 Sep 2020 17:58:29 -0400 Subject: [PATCH 20/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20update=20all=20tes?= =?UTF-8?q?ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 14 + package-lock.json | 25 +- package.json | 21 +- src/Elder.ts | 6 +- src/__tests__/Elder.spec.ts | 42 +- .../__snapshots__/Elder.spec.ts.snap | 856 +++++++++++++++++- .../externalHelpers.spec.ts.snap | 24 +- .../__snapshots__/hooks.spec.ts.snap | 28 +- src/__tests__/hooks.spec.ts | 11 +- src/hooks.ts | 2 +- src/routes/__tests__/routes.spec.ts | 19 +- src/routes/routes.ts | 2 +- .../__tests__/__snapshots__/Page.spec.ts.snap | 1 + .../__snapshots__/validations.spec.ts.snap | 325 +------ src/utils/__tests__/getConfig.spec.ts | 32 +- src/utils/__tests__/index.spec.ts | 1 + src/utils/__tests__/svelteComponent.spec.ts | 14 +- src/utils/__tests__/tsConfigExist.spec.ts | 39 - src/utils/__tests__/validations.spec.ts | 16 +- src/utils/getConfig.ts | 7 +- src/utils/getHashedSvelteComponents.ts | 1 - src/utils/getRollupConfig.ts | 29 +- src/utils/svelteComponent.ts | 3 +- src/utils/validations.ts | 1 - 24 files changed, 988 insertions(+), 531 deletions(-) create mode 100644 .vscode/launch.json delete mode 100644 src/utils/__tests__/tsConfigExist.spec.ts diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..231838c4 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug Jest Tests", + "type": "node", + "request": "launch", + "runtimeArgs": ["--inspect-brk", "${workspaceRoot}/node_modules/.bin/jest", "--runInBand"], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "port": 9229 + } + ] +} diff --git a/package-lock.json b/package-lock.json index 569945bb..e90ae4dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1685,9 +1685,9 @@ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" }, "@types/node": { - "version": "14.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.10.2.tgz", - "integrity": "sha512-IzMhbDYCpv26pC2wboJ4MMOa9GKtjplXfcAqrMeNJpUUwpM/2ATt2w1JPUXwS6spu856TvKZL2AOmeU2rAxskw==" + "version": "14.10.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.10.3.tgz", + "integrity": "sha512-zdN0hor7TLkjAdKTnYW+Y22oIhUUpil5ZD1V1OFq0CR0CLKw+NdR6dkziTfkWRLo6sKzisayoj/GNpNbe4LY9Q==" }, "@types/normalize-package-data": { "version": "2.4.0", @@ -4142,6 +4142,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, "optional": true }, "function-bind": { @@ -4627,11 +4628,6 @@ } } }, - "intersection-observer": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.11.0.tgz", - "integrity": "sha512-KZArj2QVnmdud9zTpKf279m2bbGfG+4/kn16UU0NL3pTVl52ZHiJ9IRNSsnn6jaHrL9EGLFM5eWjTx2fz/+zoQ==" - }, "ip-regex": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", @@ -8469,14 +8465,6 @@ "glob": "^7.1.3" } }, - "rollup": { - "version": "2.27.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.27.0.tgz", - "integrity": "sha512-1WlbhNdzhLjdhh2wsf6CDxmuBAYG+5O53fYqCcGv8aJOoX/ymCfCY6oZnvllXZzaC/Ng+lPPwq9EMbHOKc5ozA==", - "requires": { - "fsevents": "~2.1.2" - } - }, "rollup-plugin-babel": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz", @@ -9297,11 +9285,6 @@ "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.13.tgz", "integrity": "sha512-R9N6uDkVsghHePKh1TEqbnLddO2IY25OcsksyFp/qBe7XYd0PVbKEWxhcdMhpLzE1I6skj5l4aEZ3CRxcbArlA==" }, - "systemjs": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-6.6.1.tgz", - "integrity": "sha512-Niw/DZwTPmdLGC0CCe+n/MdRu927XyN/jzxKZyU6tUfeNqGQlxO5oVXuVMsJHxPO2cnXyHh0/zIGdXaocOMLVQ==" - }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", diff --git a/package.json b/package.json index bd0df050..5d30d7a5 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,9 @@ "build/**/*" ], "peerDependencies": { - "svelte": "^3.24.1" + "svelte": "^3.24.1", + "intersection-observer": "^0.11.0", + "systemjs": "^6.5.0" }, "dependencies": { "cli-progress": "^3.8.2", @@ -31,7 +33,6 @@ "lodash.defaultsdeep": "^4.6.1", "@elderjs/shortcodes": "^1.0.6", "nanoid": "^3.1.12", - "systemjs": "^6.5.0", "yup": "^0.29.3", "del": "^5.1.0", "rollup-plugin-babel": "^4.4.0", @@ -45,24 +46,24 @@ "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^8.4.0", "@rollup/plugin-replace": "^2.3.3", - "intersection-observer": "^0.11.0", - "svelte": "^3.25.1" + "svelte": "^3.25.1", + "rollup": "^2.21.0" }, "devDependencies": { "@types/fs-extra": "^9.0.1", - "@types/jest": "^26.0.12", - "@types/node": "^14.10.1", - "@typescript-eslint/eslint-plugin": "^4.0.1", - "@typescript-eslint/parser": "^4.0.1", + "@types/jest": "^26.0.14", + "@types/node": "^14.10.3", + "@typescript-eslint/eslint-plugin": "^4.1.1", + "@typescript-eslint/parser": "^4.1.1", "cz-conventional-changelog": "^3.3.0", - "eslint": "^7.8.0", + "eslint": "^7.9.0", "eslint-config-airbnb-base": "^14.2.0", "eslint-config-prettier": "^6.11.0", "eslint-plugin-import": "^2.22.0", "eslint-plugin-jest": "^23.20.0", "eslint-plugin-prettier": "^3.1.4", "jest": "^26.4.2", - "prettier": "^2.1.1", + "prettier": "^2.1.2", "rimraf": "^3.0.2", "ts-jest": "^26.3.0", "ts-node": "^9.0.0", diff --git a/src/Elder.ts b/src/Elder.ts index 9b60dcd6..afafbebb 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -88,6 +88,8 @@ class Elder { build: context === 'build' && config[context], }; + this.settings.$$internal.hashedComponents = getHashedSvelteComponents({ ...config.$$internal }); + if (context === 'build' && worker) { this.settings.worker = worker; } @@ -114,6 +116,7 @@ class Elder { let plugin: PluginOptions | undefined; const pluginPath = `./plugins/${pluginName}/index.js`; const srcPlugin = path.resolve(this.settings.srcDir, pluginPath); + if (fs.existsSync(srcPlugin)) { // eslint-disable-next-line import/no-dynamic-require const pluginReq = require(srcPlugin); @@ -128,7 +131,8 @@ class Elder { const pluginPkgPath = path.resolve(pkgPath, pluginPackageJson.main); // eslint-disable-next-line import/no-dynamic-require - plugin = require(pluginPkgPath).default || require(pluginPkgPath); + const nmPluginReq = require(pluginPkgPath); + plugin = nmPluginReq.default || nmPluginReq; } } diff --git a/src/__tests__/Elder.spec.ts b/src/__tests__/Elder.spec.ts index 4ea3a714..feafa679 100644 --- a/src/__tests__/Elder.spec.ts +++ b/src/__tests__/Elder.spec.ts @@ -1,9 +1,12 @@ process.cwd = () => 'test'; -jest.mock('path', () => ({ - resolve: (...strings) => strings.join('/').replace('./', '').replace('//', '/').replace('/./', '/'), - join: (...strings) => strings.join('/').replace('./', '').replace('//', '/').replace('/./', '/'), -})); +jest.mock('path', () => { + return { + resolve: (...strings) => strings.join('/').replace('./', '').replace('//', '/').replace('/./', '/'), + join: (...strings) => strings.join('/').replace('./', '').replace('//', '/').replace('/./', '/'), + posix: () => ({ dirname: () => '' }), + }; +}); jest.mock('../routes/routes', () => () => ({ 'route-a': { @@ -20,17 +23,16 @@ jest.mock('../routes/routes', () => () => ({ })); jest.mock('../utils/getConfig', () => () => ({ + $$internal: { + clientComponents: 'test/public/svelte', + ssrComponents: 'test/___ELDER___/compiled', + }, debug: { automagic: true, }, - locations: { - srcFolder: './src/', - buildFolder: './__ELDER__/', - svelte: { - ssrComponents: './___ELDER___/compiled/', - clientComponents: './public/dist/svelte/', - }, - }, + distDir: 'test/public', + rootDir: 'test', + srcDir: 'test/src', server: { prefix: '/dev', }, @@ -38,7 +40,6 @@ jest.mock('../utils/getConfig', () => () => ({ shuffleRequests: false, numberOfWorkers: 4, }, - typescript: true, plugins: { 'elder-plugin-upload-s3': { dataBucket: 'elderguide.com', @@ -152,15 +153,14 @@ describe('#Elder', () => { bootstrapComplete: Promise.resolve({}), markBootstrapComplete: expect.any(Function), settings: { - $$internal: { hashedComponents: { File1: 'entryFile1', File2: 'entryFile2' } }, + $$internal: { + clientComponents: 'test/public/svelte', + ssrComponents: 'test/___ELDER___/compiled', + hashedComponents: { File1: 'entryFile1', File2: 'entryFile2' }, + }, build: false, debug: { automagic: true }, hooks: { disable: ['randomHook'] }, - locations: { - buildFolder: './__ELDER__/', - srcFolder: './src/', - svelte: { clientComponents: './public/dist/svelte/', ssrComponents: './___ELDER___/compiled/' }, - }, plugins: { 'elder-plugin-upload-s3': { dataBucket: 'elderguide.com', @@ -169,7 +169,9 @@ describe('#Elder', () => { }, }, server: { prefix: '/dev' }, - typescript: true, + distDir: 'test/public', + rootDir: 'test', + srcDir: 'test/src', }, }); }); diff --git a/src/__tests__/__snapshots__/Elder.spec.ts.snap b/src/__tests__/__snapshots__/Elder.spec.ts.snap index 20345939..60d374ca 100644 --- a/src/__tests__/__snapshots__/Elder.spec.ts.snap +++ b/src/__tests__/__snapshots__/Elder.spec.ts.snap @@ -14,6 +14,403 @@ Elder { "test-b": [Function], }, }, + "hookInterface": Array [ + Object { + "advanced": true, + "context": "Used to modify what hooks can mutate which properties all hooks.", + "experimental": true, + "hook": "customizeHooks", + "location": "Elder.ts", + "mutable": Array [ + "hookInterface", + "errors", + ], + "props": Array [ + "hookInterface", + "errors", + ], + "use": "

    This hook receives the hookInterface.ts file which defines all hook interactions. You can customize all 'props' and 'mutable' of + all hooks by using this hook. This is a power user hook and unless you know Elder.js internals don't mess with it.

    ", + }, + Object { + "advanced": false, + "context": "Routes, plugins, and hooks have been collected and validated.", + "experimental": false, + "hook": "bootstrap", + "location": "Elder.ts", + "mutable": Array [ + "errors", + "helpers", + "data", + "settings", + "query", + ], + "props": Array [ + "helpers", + "data", + "settings", + "routes", + "hooks", + "query", + "errors", + ], + "use": "
      +
    • Often used to populate the empty query object with a database or API connection as query is passed to the all() function which is used to generate request objects.
    • +
    • Internally used to automatically populate the helpers object with the helpers found in './src/helpers/index.js'.
    • +
    • Can be used to set information on the data object that is needed throughout the entire lifecycle. (sitewide settings)
    • +
    ", + }, + Object { + "advanced": false, + "context": "allRequests which represents all of the request objects have been collected from route and plugins. This makes the 'allRequests' array mutable.", + "experimental": false, + "hook": "allRequests", + "location": "Elder.ts", + "mutable": Array [ + "errors", + "allRequests", + ], + "props": Array [ + "helpers", + "data", + "settings", + "allRequests", + "routes", + "query", + "errors", + ], + "use": "

    The main use here is to allow users to adjust the requests that Elder.js is aware of.

    +
      +
    • This could be used for incremental builds. By filtering and overwriting the allRequests array building just a single route or even a single request is doable.
    • +
    • This hook is used by elderjs-plugin-random to register temporary requests that it later intercepts to redirect to a random page of a route.
    • +
    • This hook is used by elderjs-plugin-markdown to register processed markdown files and their slugs Elder.js
    • +
    + +

    NOTE: If you are modifying 'allRequests' you must set 'request.route' key for each request.

    ", + }, + Object { + "advanced": true, + "context": "Fired upon a request that originates from the express/polka middleware version of Elder.js. The hook has access to \\"req\\" and \\"next\\" common in express like middleware.", + "experimental": true, + "hook": "middleware", + "location": "prepareServer.ts", + "mutable": Array [ + "errors", + "request", + "query", + "helpers", + "data", + "route", + "settings", + "allRequests", + "routes", + "req", + "next", + "res", + ], + "props": Array [ + "errors", + "request", + "query", + "helpers", + "data", + "route", + "settings", + "allRequests", + "routes", + "req", + "next", + "res", + ], + "use": "

    If you're looking to use Elder.js with express/polka to build a server rendered website, then you'll be interested in this hook as it includes the familiar 'req' and 'next' objects as often used in Express middleware.

    +
      +
    • This hook could be used to set user or session information stored on the 'req' prop anywhere it is needed such as on the Elder.js 'request' object or 'data' object.
    • +
    • If you're looking to pass in details about the query string deeper into your application, you could use this hook to do so.
    • +
    • Anything you'd use an Express 'req' or 'next' for you can do and customize other parts of the Elder.js on this hook.
    • +
    ", + }, + Object { + "advanced": false, + "context": "This is executed at the beginning the request object being processed.", + "experimental": false, + "hook": "request", + "location": "Page.ts", + "mutable": Array [ + "errors", + "helpers", + "data", + "settings", + "request", + "route", + ], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "allRequests", + "query", + "errors", + "routes", + "route", + ], + "use": "

    This hook gives access to the entire state of a request lifecycle before it starts.

    +
      +
    • Primarily used to set 'request' specific data that is required by all routes so doesn't make sense to share across multiple 'data' functions.
    • +
    • If you have helper functions that need a closure isolated to a specific page generation lifecycle here is where you should attach them.
    • +
    • If you need to programmatically change the route, you can do so here. This is how the elderjs-plugin-random works.
    • +
    • This hook is commonly uses by plugins that need to add route level data that is dependent on the request to populate.
    • +
    + ", + }, + Object { + "advanced": true, + "context": "This hook is run after the route's \\"data\\" function has executed.", + "experimental": false, + "hook": "data", + "location": "Page.ts", + "mutable": Array [ + "errors", + "data", + "cssStack", + "headStack", + "beforeHydrateStack", + "hydrateStack", + "customJsStack", + "footerStack", + ], + "props": Array [ + "data", + "request", + "errors", + "helpers", + "query", + "routes", + "cssStack", + "headStack", + "beforeHydrateStack", + "hydrateStack", + "customJsStack", + "footerStack", + "settings", + ], + "use": "

    This hook is mainly used by plugins/hooks to offer functionality at the route level that is dependent on the route's \\"data\\" function has returning but isn't suitable to live in multiple data function across many routes due to code duplication.

    +

    Examples of things we (ElderGuide.com) have done or have seen users do:

    +
      +
    • LD+JSON: Plugins/hooks that add LD+JSON may need the a route's \\"data\\" function to be executed before they have the data needed to run.
    • +
    • Breadcrumbs: Plugins/hooks that add breadcrumbs may be dependent on the \\"data\\" function of a route.
    • +
    • Table Of Contents: Plugins/hooks that automatically generate a table of contents will be dependent on data from a route's data function.
    • +
    • Reference Plugins: Plugins/hooks that collect references from content and add them to the footer of the page content.
    • +
    • Last Updated Data: Determining the last updated date for a page is often better to do in a central place instead of in many \\"data\\" functions.
    • +
    +

    Stacks are made available here so that strings can be added to the head or footer of the page easily.

    + ", + }, + Object { + "advanced": true, + "context": "Executed after the route's html has been compiled, but before the layout html has been compiled.", + "experimental": false, + "hook": "shortcodes", + "location": "Page.ts", + "mutable": Array [ + "errors", + "routeHtml", + "cssStack", + "headStack", + "customJsStack", + ], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "query", + "errors", + "cssStack", + "headStack", + "customJsStack", + "routeHtml", + "shortcodes", + "allRequests", + ], + "use": "

    Elder.js uses this hook to process shortcodes. The vast majority of users won't need to use this hook, but if you were so inclined you could write your own shortcode parser or if you'd like to disable shortcodes completely, you can add 'elderProcessShortcodes' to hooks.disable in your elder.config.js file.

    +

    NOTE: Don't use this hook for anything besides shortcodes.

    ", + }, + Object { + "advanced": true, + "context": "Executed just before processing all of the stacks into strings.", + "experimental": false, + "hook": "stacks", + "location": "Page.ts", + "mutable": Array [ + "errors", + "cssStack", + "headStack", + "beforeHydrateStack", + "hydrateStack", + "customJsStack", + "footerStack", + ], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "query", + "errors", + "cssStack", + "headStack", + "beforeHydrateStack", + "hydrateStack", + "customJsStack", + "footerStack", + ], + "use": "

    Elder.js uses 'stacks' to manage it's string concatenation. If you are unfamiliar, stacks are basically an array of strings, with a priority, and some meta data. This hook let's you manipulate or view the stacks before they are written to the page and is designed for use by plugins.

    +

    This hook will mainly be used when you need to add arbitrary strings to the footer. In most cases, users should be using <svelte:head></svelte:head> to add content to the head.

    +
      +
    • headStack: Internally all content used in are added to the head stack. If you were looking to add ld+json to the page, you could do it here. If you're looking to write <title> tags, we recommend doing it within Svelte templates unless you are writing a plugin in which case you may want to also look at the 'head' hook.
    • +
    • cssStack: The 'cssStack' represents all of the css strings emitted by the SSR Svelte components. Plugins can add css here (such as critical path CSS), but we recommend users add them directly in Svelte files. Note: Do not wrap strings added to the stack in <style>.
    • +
    • beforeHydrateStack: default this stack includes a polyfill for intersection observer and systemjs for loading svelte. This stack is not run unless there are Svelte components to be hydrated.
    • +
    • hydrateStack: the hydrateStack contains strings which represent all of the root svelte components which will be hydrated.
    • +
    • customJsStack: Used to add custom JS to the site. This is done after the Svelte components are written to the page.
    • +
    • footerStack: the footerStack which is an array of html or html friendly strings that will be written to the footer. This is generally the ideal place for plugins to add Analytics scripts as it fires after all other JS.
    • +
    + ", + }, + Object { + "advanced": true, + "context": "Executed just before writing the tag to the page.", + "experimental": false, + "hook": "head", + "location": "Page.ts", + "mutable": Array [ + "errors", + "headString", + ], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "headString", + "query", + "errors", + ], + "use": "

    This hook's headSting represents everything that will be written to <head> tag.

    +

    There are many possible SEO uses to this hook, especially for plugins. That said, we recommend users who want to set common SEO elements such as tags <title> and meta descriptions programatically to do it from within Svelte templates using the <svelte:head></svelte:head> tag. Chances are you won't need this field unless you're a power user and need access to the raw head.

    ", + }, + Object { + "advanced": true, + "context": "This is where Elder.js merges the html from the Svelte layout with stacks and wraps it in an tag.", + "experimental": false, + "hook": "compileHtml", + "location": "Page.ts", + "mutable": Array [ + "errors", + "htmlString", + ], + "props": Array [ + "helpers", + "data", + "request", + "headString", + "footerString", + "layoutHtml", + "htmlString", + ], + "use": "

    This hook should only be used when you need to have full control over the <html> document. Make sure if you use this to add 'elderCompileHtml' to the 'hooks.disable' array in your elder.config.js or your template will be overwritten.

    ", + }, + Object { + "advanced": false, + "context": "Executed when all of the html has been compiled.", + "experimental": false, + "hook": "html", + "location": "Page.ts", + "mutable": Array [ + "errors", + "htmlString", + ], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "htmlString", + "query", + "errors", + ], + "use": "

    This hook receives the full html of the document. With great power comes great responsibility.

    +
      +
    • Can be used to compress the html/css/js.
    • +
    • Could be used to programmatically extract h2/h3 tags and build/inject a table of contents with something like Cheeriojs.
    • +
    • If you need to modify the final html output, here is where you can do it.
    • +
    ", + }, + Object { + "advanced": false, + "context": "This hook marks the end of the request lifecycle.", + "experimental": false, + "hook": "requestComplete", + "location": "Page.ts", + "mutable": Array [ + "errors", + ], + "props": Array [ + "request", + "htmlString", + "query", + "settings", + "errors", + "timings", + "data", + ], + "use": "

    This hook is triggered on an individual 'request object' completing whether Elder.js is being used in the \\"build\\" or a \\"server\\" mode.

    +
      +
    • Internally, Elder.js uses this hook to write html to the \\"public folder\\".
    • +
    • Useful for uploading static html to s3 or another source.
    • +
    • Could also be used to write the output of a route's \\"data\\" function file to help with client site routing if you were so inclined.
    • +
    • This hook may also be used by plugins to clean up any request specific 'state' they have stored.
    • +
    • By default Elder.js adds a hook here to all server requests that outputs how long the request took to generate. If you want to see detailed output from this hook set debug.speed = true in your config file.
    • +
    ", + }, + Object { + "advanced": false, + "context": "Executed only if the script has encountered errors and they are pushed to the errors array.", + "experimental": false, + "hook": "error", + "location": "Page.ts, build.ts", + "mutable": Array [], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "query", + "errors", + ], + "use": "

    As the script encounters errors, they are collected and presented on this hook at the end of a request and the end of an entire build.

    ", + }, + Object { + "advanced": false, + "context": "Executed after a build is complete", + "experimental": false, + "hook": "buildComplete", + "location": "build.ts", + "mutable": Array [], + "props": Array [ + "helpers", + "data", + "settings", + "timings", + "query", + "errors", + "routes", + ], + "use": "

    Contains whether the build was successful. If not it contains errors for the entire build. Also includes + average performance details, and a granular performance object. Could be used to fire off additional scripts such as generating a sitemap or copying asset files to the public folder.

    +

    Plugins: Because builds are split across processes, a plugin doesn't not have a shared memory space across all processes.

    ", + }, + ], "hooks": Array [ Object { "$$meta": Object { @@ -23,7 +420,7 @@ Elder { "description": "Adds external helpers to helpers object", "hook": "bootstrap", "name": "elderAddExternalHelpers", - "priority": 100, + "priority": 1, "run": [Function], }, Object { @@ -45,7 +442,7 @@ Elder { "description": "Adds to the head.", "hook": "stacks", "name": "elderAddMetaCharsetToHead", - "priority": 1, + "priority": 100, "run": [Function], }, Object { @@ -56,7 +453,7 @@ Elder { "description": "Adds to the head.", "hook": "stacks", "name": "elderAddMetaViewportToHead", - "priority": 10, + "priority": 90, "run": [Function], }, Object { @@ -67,7 +464,7 @@ Elder { "description": "Sets up the default polyfill for the intersection observer", "hook": "stacks", "name": "elderAddDefaultIntersectionObserver", - "priority": 1, + "priority": 100, "run": [Function], }, Object { @@ -100,7 +497,7 @@ Elder { "description": "Log any errors to the console.", "hook": "error", "name": "elderConsoleLogErrors", - "priority": 100, + "priority": 1, "run": [Function], }, Object { @@ -111,7 +508,7 @@ Elder { "description": "Write the html output to public.", "hook": "requestComplete", "name": "elderWriteHtmlFileToPublic", - "priority": 100, + "priority": 1, "run": [Function], }, Object { @@ -147,16 +544,6 @@ Elder { "priority": 50, "run": [Function], }, - Object { - "$$meta": Object { - "addedBy": "hooks.js", - "type": "hooks.js", - }, - "description": "just for testing", - "hook": "bootstrap", - "name": "test hook from file", - "run": [Function], - }, ], "markBootstrapComplete": [Function], "query": Object {}, @@ -198,28 +585,23 @@ Elder { "serverLookupObject": Object {}, "settings": Object { "$$internal": Object { + "clientComponents": "test/public/svelte", "hashedComponents": Object { "File1": "entryFile1", "File2": "entryFile2", }, + "ssrComponents": "test/___ELDER___/compiled", }, "build": false, "debug": Object { "automagic": true, }, + "distDir": "test/public", "hooks": Object { "disable": Array [ "randomHook", ], }, - "locations": Object { - "buildFolder": "./__ELDER__/", - "srcFolder": "./src/", - "svelte": Object { - "clientComponents": "./public/dist/svelte/", - "ssrComponents": "./___ELDER___/compiled/", - }, - }, "plugins": Object { "elder-plugin-upload-s3": Object { "dataBucket": "elderguide.com", @@ -227,10 +609,11 @@ Elder { "htmlBucket": "elderguide.com", }, }, + "rootDir": "test", "server": Object { "prefix": "/dev", }, - "typescript": true, + "srcDir": "test/src", }, "shortcodes": Array [ Object { @@ -266,6 +649,403 @@ Elder { "test-b": [Function], }, }, + "hookInterface": Array [ + Object { + "advanced": true, + "context": "Used to modify what hooks can mutate which properties all hooks.", + "experimental": true, + "hook": "customizeHooks", + "location": "Elder.ts", + "mutable": Array [ + "hookInterface", + "errors", + ], + "props": Array [ + "hookInterface", + "errors", + ], + "use": "

    This hook receives the hookInterface.ts file which defines all hook interactions. You can customize all 'props' and 'mutable' of + all hooks by using this hook. This is a power user hook and unless you know Elder.js internals don't mess with it.

    ", + }, + Object { + "advanced": false, + "context": "Routes, plugins, and hooks have been collected and validated.", + "experimental": false, + "hook": "bootstrap", + "location": "Elder.ts", + "mutable": Array [ + "errors", + "helpers", + "data", + "settings", + "query", + ], + "props": Array [ + "helpers", + "data", + "settings", + "routes", + "hooks", + "query", + "errors", + ], + "use": "
      +
    • Often used to populate the empty query object with a database or API connection as query is passed to the all() function which is used to generate request objects.
    • +
    • Internally used to automatically populate the helpers object with the helpers found in './src/helpers/index.js'.
    • +
    • Can be used to set information on the data object that is needed throughout the entire lifecycle. (sitewide settings)
    • +
    ", + }, + Object { + "advanced": false, + "context": "allRequests which represents all of the request objects have been collected from route and plugins. This makes the 'allRequests' array mutable.", + "experimental": false, + "hook": "allRequests", + "location": "Elder.ts", + "mutable": Array [ + "errors", + "allRequests", + ], + "props": Array [ + "helpers", + "data", + "settings", + "allRequests", + "routes", + "query", + "errors", + ], + "use": "

    The main use here is to allow users to adjust the requests that Elder.js is aware of.

    +
      +
    • This could be used for incremental builds. By filtering and overwriting the allRequests array building just a single route or even a single request is doable.
    • +
    • This hook is used by elderjs-plugin-random to register temporary requests that it later intercepts to redirect to a random page of a route.
    • +
    • This hook is used by elderjs-plugin-markdown to register processed markdown files and their slugs Elder.js
    • +
    + +

    NOTE: If you are modifying 'allRequests' you must set 'request.route' key for each request.

    ", + }, + Object { + "advanced": true, + "context": "Fired upon a request that originates from the express/polka middleware version of Elder.js. The hook has access to \\"req\\" and \\"next\\" common in express like middleware.", + "experimental": true, + "hook": "middleware", + "location": "prepareServer.ts", + "mutable": Array [ + "errors", + "request", + "query", + "helpers", + "data", + "route", + "settings", + "allRequests", + "routes", + "req", + "next", + "res", + ], + "props": Array [ + "errors", + "request", + "query", + "helpers", + "data", + "route", + "settings", + "allRequests", + "routes", + "req", + "next", + "res", + ], + "use": "

    If you're looking to use Elder.js with express/polka to build a server rendered website, then you'll be interested in this hook as it includes the familiar 'req' and 'next' objects as often used in Express middleware.

    +
      +
    • This hook could be used to set user or session information stored on the 'req' prop anywhere it is needed such as on the Elder.js 'request' object or 'data' object.
    • +
    • If you're looking to pass in details about the query string deeper into your application, you could use this hook to do so.
    • +
    • Anything you'd use an Express 'req' or 'next' for you can do and customize other parts of the Elder.js on this hook.
    • +
    ", + }, + Object { + "advanced": false, + "context": "This is executed at the beginning the request object being processed.", + "experimental": false, + "hook": "request", + "location": "Page.ts", + "mutable": Array [ + "errors", + "helpers", + "data", + "settings", + "request", + "route", + ], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "allRequests", + "query", + "errors", + "routes", + "route", + ], + "use": "

    This hook gives access to the entire state of a request lifecycle before it starts.

    +
      +
    • Primarily used to set 'request' specific data that is required by all routes so doesn't make sense to share across multiple 'data' functions.
    • +
    • If you have helper functions that need a closure isolated to a specific page generation lifecycle here is where you should attach them.
    • +
    • If you need to programmatically change the route, you can do so here. This is how the elderjs-plugin-random works.
    • +
    • This hook is commonly uses by plugins that need to add route level data that is dependent on the request to populate.
    • +
    + ", + }, + Object { + "advanced": true, + "context": "This hook is run after the route's \\"data\\" function has executed.", + "experimental": false, + "hook": "data", + "location": "Page.ts", + "mutable": Array [ + "errors", + "data", + "cssStack", + "headStack", + "beforeHydrateStack", + "hydrateStack", + "customJsStack", + "footerStack", + ], + "props": Array [ + "data", + "request", + "errors", + "helpers", + "query", + "routes", + "cssStack", + "headStack", + "beforeHydrateStack", + "hydrateStack", + "customJsStack", + "footerStack", + "settings", + ], + "use": "

    This hook is mainly used by plugins/hooks to offer functionality at the route level that is dependent on the route's \\"data\\" function has returning but isn't suitable to live in multiple data function across many routes due to code duplication.

    +

    Examples of things we (ElderGuide.com) have done or have seen users do:

    +
      +
    • LD+JSON: Plugins/hooks that add LD+JSON may need the a route's \\"data\\" function to be executed before they have the data needed to run.
    • +
    • Breadcrumbs: Plugins/hooks that add breadcrumbs may be dependent on the \\"data\\" function of a route.
    • +
    • Table Of Contents: Plugins/hooks that automatically generate a table of contents will be dependent on data from a route's data function.
    • +
    • Reference Plugins: Plugins/hooks that collect references from content and add them to the footer of the page content.
    • +
    • Last Updated Data: Determining the last updated date for a page is often better to do in a central place instead of in many \\"data\\" functions.
    • +
    +

    Stacks are made available here so that strings can be added to the head or footer of the page easily.

    + ", + }, + Object { + "advanced": true, + "context": "Executed after the route's html has been compiled, but before the layout html has been compiled.", + "experimental": false, + "hook": "shortcodes", + "location": "Page.ts", + "mutable": Array [ + "errors", + "routeHtml", + "cssStack", + "headStack", + "customJsStack", + ], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "query", + "errors", + "cssStack", + "headStack", + "customJsStack", + "routeHtml", + "shortcodes", + "allRequests", + ], + "use": "

    Elder.js uses this hook to process shortcodes. The vast majority of users won't need to use this hook, but if you were so inclined you could write your own shortcode parser or if you'd like to disable shortcodes completely, you can add 'elderProcessShortcodes' to hooks.disable in your elder.config.js file.

    +

    NOTE: Don't use this hook for anything besides shortcodes.

    ", + }, + Object { + "advanced": true, + "context": "Executed just before processing all of the stacks into strings.", + "experimental": false, + "hook": "stacks", + "location": "Page.ts", + "mutable": Array [ + "errors", + "cssStack", + "headStack", + "beforeHydrateStack", + "hydrateStack", + "customJsStack", + "footerStack", + ], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "query", + "errors", + "cssStack", + "headStack", + "beforeHydrateStack", + "hydrateStack", + "customJsStack", + "footerStack", + ], + "use": "

    Elder.js uses 'stacks' to manage it's string concatenation. If you are unfamiliar, stacks are basically an array of strings, with a priority, and some meta data. This hook let's you manipulate or view the stacks before they are written to the page and is designed for use by plugins.

    +

    This hook will mainly be used when you need to add arbitrary strings to the footer. In most cases, users should be using <svelte:head></svelte:head> to add content to the head.

    +
      +
    • headStack: Internally all content used in are added to the head stack. If you were looking to add ld+json to the page, you could do it here. If you're looking to write <title> tags, we recommend doing it within Svelte templates unless you are writing a plugin in which case you may want to also look at the 'head' hook.
    • +
    • cssStack: The 'cssStack' represents all of the css strings emitted by the SSR Svelte components. Plugins can add css here (such as critical path CSS), but we recommend users add them directly in Svelte files. Note: Do not wrap strings added to the stack in <style>.
    • +
    • beforeHydrateStack: default this stack includes a polyfill for intersection observer and systemjs for loading svelte. This stack is not run unless there are Svelte components to be hydrated.
    • +
    • hydrateStack: the hydrateStack contains strings which represent all of the root svelte components which will be hydrated.
    • +
    • customJsStack: Used to add custom JS to the site. This is done after the Svelte components are written to the page.
    • +
    • footerStack: the footerStack which is an array of html or html friendly strings that will be written to the footer. This is generally the ideal place for plugins to add Analytics scripts as it fires after all other JS.
    • +
    + ", + }, + Object { + "advanced": true, + "context": "Executed just before writing the tag to the page.", + "experimental": false, + "hook": "head", + "location": "Page.ts", + "mutable": Array [ + "errors", + "headString", + ], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "headString", + "query", + "errors", + ], + "use": "

    This hook's headSting represents everything that will be written to <head> tag.

    +

    There are many possible SEO uses to this hook, especially for plugins. That said, we recommend users who want to set common SEO elements such as tags <title> and meta descriptions programatically to do it from within Svelte templates using the <svelte:head></svelte:head> tag. Chances are you won't need this field unless you're a power user and need access to the raw head.

    ", + }, + Object { + "advanced": true, + "context": "This is where Elder.js merges the html from the Svelte layout with stacks and wraps it in an tag.", + "experimental": false, + "hook": "compileHtml", + "location": "Page.ts", + "mutable": Array [ + "errors", + "htmlString", + ], + "props": Array [ + "helpers", + "data", + "request", + "headString", + "footerString", + "layoutHtml", + "htmlString", + ], + "use": "

    This hook should only be used when you need to have full control over the <html> document. Make sure if you use this to add 'elderCompileHtml' to the 'hooks.disable' array in your elder.config.js or your template will be overwritten.

    ", + }, + Object { + "advanced": false, + "context": "Executed when all of the html has been compiled.", + "experimental": false, + "hook": "html", + "location": "Page.ts", + "mutable": Array [ + "errors", + "htmlString", + ], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "htmlString", + "query", + "errors", + ], + "use": "

    This hook receives the full html of the document. With great power comes great responsibility.

    +
      +
    • Can be used to compress the html/css/js.
    • +
    • Could be used to programmatically extract h2/h3 tags and build/inject a table of contents with something like Cheeriojs.
    • +
    • If you need to modify the final html output, here is where you can do it.
    • +
    ", + }, + Object { + "advanced": false, + "context": "This hook marks the end of the request lifecycle.", + "experimental": false, + "hook": "requestComplete", + "location": "Page.ts", + "mutable": Array [ + "errors", + ], + "props": Array [ + "request", + "htmlString", + "query", + "settings", + "errors", + "timings", + "data", + ], + "use": "

    This hook is triggered on an individual 'request object' completing whether Elder.js is being used in the \\"build\\" or a \\"server\\" mode.

    +
      +
    • Internally, Elder.js uses this hook to write html to the \\"public folder\\".
    • +
    • Useful for uploading static html to s3 or another source.
    • +
    • Could also be used to write the output of a route's \\"data\\" function file to help with client site routing if you were so inclined.
    • +
    • This hook may also be used by plugins to clean up any request specific 'state' they have stored.
    • +
    • By default Elder.js adds a hook here to all server requests that outputs how long the request took to generate. If you want to see detailed output from this hook set debug.speed = true in your config file.
    • +
    ", + }, + Object { + "advanced": false, + "context": "Executed only if the script has encountered errors and they are pushed to the errors array.", + "experimental": false, + "hook": "error", + "location": "Page.ts, build.ts", + "mutable": Array [], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "query", + "errors", + ], + "use": "

    As the script encounters errors, they are collected and presented on this hook at the end of a request and the end of an entire build.

    ", + }, + Object { + "advanced": false, + "context": "Executed after a build is complete", + "experimental": false, + "hook": "buildComplete", + "location": "build.ts", + "mutable": Array [], + "props": Array [ + "helpers", + "data", + "settings", + "timings", + "query", + "errors", + "routes", + ], + "use": "

    Contains whether the build was successful. If not it contains errors for the entire build. Also includes + average performance details, and a granular performance object. Could be used to fire off additional scripts such as generating a sitemap or copying asset files to the public folder.

    +

    Plugins: Because builds are split across processes, a plugin doesn't not have a shared memory space across all processes.

    ", + }, + ], "hooks": Array [ Object { "$$meta": Object { @@ -275,7 +1055,7 @@ Elder { "description": "Adds external helpers to helpers object", "hook": "bootstrap", "name": "elderAddExternalHelpers", - "priority": 100, + "priority": 1, "run": [Function], }, Object { @@ -297,7 +1077,7 @@ Elder { "description": "Adds to the head.", "hook": "stacks", "name": "elderAddMetaCharsetToHead", - "priority": 1, + "priority": 100, "run": [Function], }, Object { @@ -308,7 +1088,7 @@ Elder { "description": "Adds to the head.", "hook": "stacks", "name": "elderAddMetaViewportToHead", - "priority": 10, + "priority": 90, "run": [Function], }, Object { @@ -319,7 +1099,7 @@ Elder { "description": "Sets up the default polyfill for the intersection observer", "hook": "stacks", "name": "elderAddDefaultIntersectionObserver", - "priority": 1, + "priority": 100, "run": [Function], }, Object { @@ -352,7 +1132,7 @@ Elder { "description": "Log any errors to the console.", "hook": "error", "name": "elderConsoleLogErrors", - "priority": 100, + "priority": 1, "run": [Function], }, Object { @@ -363,7 +1143,7 @@ Elder { "description": "Write the html output to public.", "hook": "requestComplete", "name": "elderWriteHtmlFileToPublic", - "priority": 100, + "priority": 1, "run": [Function], }, Object { @@ -488,28 +1268,23 @@ Elder { }, "settings": Object { "$$internal": Object { + "clientComponents": "test/public/svelte", "hashedComponents": Object { "File1": "entryFile1", "File2": "entryFile2", }, + "ssrComponents": "test/___ELDER___/compiled", }, "build": false, "debug": Object { "automagic": true, }, + "distDir": "test/public", "hooks": Object { "disable": Array [ "randomHook", ], }, - "locations": Object { - "buildFolder": "./__ELDER__/", - "srcFolder": "./src/", - "svelte": Object { - "clientComponents": "./public/dist/svelte/", - "ssrComponents": "./___ELDER___/compiled/", - }, - }, "plugins": Object { "elder-plugin-upload-s3": Object { "dataBucket": "elderguide.com", @@ -517,10 +1292,11 @@ Elder { "htmlBucket": "elderguide.com", }, }, + "rootDir": "test", "server": Object { "prefix": "/dev", }, - "typescript": true, + "srcDir": "test/src", }, "shortcodes": Array [ Object { diff --git a/src/__tests__/__snapshots__/externalHelpers.spec.ts.snap b/src/__tests__/__snapshots__/externalHelpers.spec.ts.snap index dbffa5b4..a3b579ae 100644 --- a/src/__tests__/__snapshots__/externalHelpers.spec.ts.snap +++ b/src/__tests__/__snapshots__/externalHelpers.spec.ts.snap @@ -1,25 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`#externalHelpers works - buildHelpers 1`] = ` -Object { - "userHelper": [Function], -} -`; +exports[`#externalHelpers works - buildHelpers 1`] = `undefined`; -exports[`#externalHelpers works - buildHelpers 2`] = ` -Object { - "userHelper": [Function], -} -`; +exports[`#externalHelpers works - buildHelpers 2`] = `undefined`; -exports[`#externalHelpers works - userHelpers 1`] = ` -Object { - "srcHelper": [MockFunction], -} -`; +exports[`#externalHelpers works - userHelpers 1`] = `undefined`; -exports[`#externalHelpers works - userHelpers 2`] = ` -Object { - "srcHelper": [MockFunction], -} -`; +exports[`#externalHelpers works - userHelpers 2`] = `undefined`; diff --git a/src/__tests__/__snapshots__/hooks.spec.ts.snap b/src/__tests__/__snapshots__/hooks.spec.ts.snap index 7d3b90f2..793a14d4 100644 --- a/src/__tests__/__snapshots__/hooks.spec.ts.snap +++ b/src/__tests__/__snapshots__/hooks.spec.ts.snap @@ -4,12 +4,12 @@ exports[`#hooks elderAddDefaultIntersectionObserver 1`] = ` Object { "beforeHydrateStack": Array [ Object { - "priority": 1, + "priority": 100, "source": "elderAddDefaultIntersectionObserver", "string": "", @@ -31,7 +31,7 @@ exports[`#hooks elderAddMetaCharsetToHead 1`] = ` Object { "headStack": Array [ Object { - "priority": 1, + "priority": 100, "source": "elderAddMetaCharsetToHead", "string": "", }, @@ -43,7 +43,7 @@ exports[`#hooks elderAddMetaViewportToHead 1`] = ` Object { "headStack": Array [ Object { - "priority": 10, + "priority": 90, "source": "elderAddMetaViewportToHead", "string": "", }, @@ -55,16 +55,16 @@ exports[`#hooks elderAddSystemJs 1`] = ` Object { "beforeHydrateStack": Array [ Object { - "priority": 2, + "priority": 99, "source": "elderAddSystemJs", - "string": "", + "string": "", }, ], "headStack": Array [ Object { - "priority": 2, + "priority": 99, "source": "elderAddSystemJs", - "string": "", + "string": "", }, ], } @@ -85,7 +85,7 @@ Array [ "description": "Adds external helpers to helpers object", "hook": "bootstrap", "name": "elderAddExternalHelpers", - "priority": 100, + "priority": 1, "run": [Function], }, Object { @@ -99,21 +99,21 @@ Array [ "description": "Adds to the head.", "hook": "stacks", "name": "elderAddMetaCharsetToHead", - "priority": 1, + "priority": 100, "run": [Function], }, Object { "description": "Adds to the head.", "hook": "stacks", "name": "elderAddMetaViewportToHead", - "priority": 10, + "priority": 90, "run": [Function], }, Object { "description": "Sets up the default polyfill for the intersection observer", "hook": "stacks", "name": "elderAddDefaultIntersectionObserver", - "priority": 1, + "priority": 100, "run": [Function], }, Object { @@ -134,14 +134,14 @@ Array [ "description": "Log any errors to the console.", "hook": "error", "name": "elderConsoleLogErrors", - "priority": 100, + "priority": 1, "run": [Function], }, Object { "description": "Write the html output to public.", "hook": "requestComplete", "name": "elderWriteHtmlFileToPublic", - "priority": 100, + "priority": 1, "run": [Function], }, Object { diff --git a/src/__tests__/hooks.spec.ts b/src/__tests__/hooks.spec.ts index 0639552c..6c2db377 100644 --- a/src/__tests__/hooks.spec.ts +++ b/src/__tests__/hooks.spec.ts @@ -6,6 +6,7 @@ process.cwd = () => 'test'; jest.mock('path', () => ({ resolve: (...strings) => strings.join('/').replace('./', '').replace('//', '/'), + posix: () => ({ dirname: () => '' }), })); jest.mock('fs-extra', () => ({ @@ -45,17 +46,11 @@ describe('#hooks', () => { }); it('elderAddDefaultIntersectionObserver', async () => { const hook = hooks.find((h) => h.name === 'elderAddDefaultIntersectionObserver'); - expect( - await hook.run({ beforeHydrateStack: [], settings: { locations: { intersectionObserverPoly: 'foo' } } }), - ).toMatchSnapshot(); - expect(await hook.run({ beforeHydrateStack: [], settings: {} })).toBe(null); + expect(await hook.run({ beforeHydrateStack: [] })).toMatchSnapshot(); }); it('elderAddSystemJs', async () => { const hook = hooks.find((h) => h.name === 'elderAddSystemJs'); - expect( - await hook.run({ beforeHydrateStack: [], headStack: [], settings: { locations: { systemJs: 'foo' } } }), - ).toMatchSnapshot(); - expect(await hook.run({ beforeHydrateStack: [], settings: {} })).toBe(null); + expect(await hook.run({ beforeHydrateStack: [], headStack: [] })).toMatchSnapshot(); }); it('elderCompileHtml', async () => { diff --git a/src/hooks.ts b/src/hooks.ts index c4c8f1fb..d138bf90 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -2,7 +2,7 @@ import path from 'path'; import fs from 'fs-extra'; import { parseBuildPerf } from './utils'; import externalHelpers from './externalHelpers'; -import { HookOptions, Hook } from './hookInterface/types'; +import { HookOptions } from './hookInterface/types'; import prepareShortcodeParser from './utils/prepareShortcodeParser'; const hooks: Array = [ diff --git a/src/routes/__tests__/routes.spec.ts b/src/routes/__tests__/routes.spec.ts index 0c6e29f8..809d1145 100644 --- a/src/routes/__tests__/routes.spec.ts +++ b/src/routes/__tests__/routes.spec.ts @@ -3,6 +3,7 @@ process.cwd = () => 'test'; jest.mock('path', () => ({ resolve: (...strings) => strings.join('/').replace('./', '').replace('//', '/').slice(0, -1), join: (...strings) => strings.join('/').replace('./', '').replace('//', '/').slice(0, -1), + posix: () => ({ dirname: () => '' }), })); jest.mock('glob', () => ({ @@ -16,7 +17,6 @@ jest.mock('glob', () => ({ 'test/src/routes/Content/data.js', 'test/src/routes/Content/Layout.svelte', ]) - .mockImplementationOnce(() => []) .mockImplementationOnce(() => [ 'test/___ELDER___/compiled/Home.js', 'test/___ELDER___/compiled/AutoComplete.js', @@ -32,16 +32,15 @@ describe('#routes', () => { debug: { automagic: true, }, - locations: { - buildFolder: './___ELDER___/', - srcFolder: './src/', - svelte: { - ssrComponents: './___ELDER___/compiled/', - clientComponents: './public/dist/svelte/', - }, - }, - typescript: false, + siteUrl: '', + distDir: 'test/public', + rootDir: 'test', + srcDir: 'test/src', hooks: {}, + $$internal: { + clientComponents: 'test/public/svelte', + ssrComponents: 'test/___ELDER___/compiled', + }, }; it('throws error when no permalink function', () => { diff --git a/src/routes/routes.ts b/src/routes/routes.ts index 225f9963..db7e9cb3 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -32,7 +32,7 @@ function routes(settings: ConfigOptions) { .filter((r) => r.includes(`/routes/${routeName}`)) .filter((r) => !r.includes('route.js')); - if (!route.permalink && (typeof route.permalink !== 'string' || typeof route.permalink !== 'function')) { + if (typeof route.permalink !== 'string' && typeof route.permalink !== 'function') { throw new Error(`${cv} does not include a permalink attribute that is a string or function.`); } diff --git a/src/utils/__tests__/__snapshots__/Page.spec.ts.snap b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap index 13d724f8..90827167 100644 --- a/src/utils/__tests__/__snapshots__/Page.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap @@ -444,6 +444,7 @@ Page { "type": "build", }, "routeHTML": undefined, + "routeHtml": undefined, "settings": Object { "$$internal": Object { "hashedComponents": Object { diff --git a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap index f2e64163..e372d036 100644 --- a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap @@ -15,12 +15,13 @@ ObjectSchema { "_nodes": Array [ "plugins", "shortcodes", - "typescript", "build", "server", "hooks", "debug", - "locations", + "srcDir", + "distDir", + "rootDir", "siteUrl", ], "_options": Object { @@ -293,6 +294,33 @@ ObjectSchema { ], "type": "object", }, + "distDir": StringSchema { + "_blacklist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "_conditions": Array [], + "_default": "public", + "_deps": Array [], + "_exclusive": Object {}, + "_label": "Where should files be written? This represents the \\"root\\" of your site and where your html will be built.", + "_mutate": undefined, + "_options": Object { + "abortEarly": true, + "recursive": true, + }, + "_type": "string", + "_typeError": [Function], + "_whitelist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "tests": Array [], + "transforms": Array [ + [Function], + ], + "type": "string", + }, "hooks": ObjectSchema { "_blacklist": RefSet { "list": Set {}, @@ -402,27 +430,20 @@ ObjectSchema { ], "type": "object", }, - "locations": ObjectSchema { + "plugins": ObjectSchema { "_blacklist": RefSet { "list": Set {}, "refs": Map {}, }, "_conditions": Array [], + "_default": Object {}, "_defaultDefault": [Function], "_deps": Array [], "_excludedEdges": Array [], "_exclusive": Object {}, - "_label": "Where various files are written and read from.", + "_label": "Used to define Elder.js plugins.", "_mutate": undefined, - "_nodes": Array [ - "intersectionObserverPoly", - "buildFolder", - "srcFolder", - "systemJs", - "svelte", - "public", - "assets", - ], + "_nodes": Array [], "_options": Object { "abortEarly": true, "recursive": true, @@ -433,293 +454,39 @@ ObjectSchema { "list": Set {}, "refs": Map {}, }, - "fields": Object { - "assets": StringSchema { - "_blacklist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "_conditions": Array [], - "_default": "./public/dist/static/", - "_deps": Array [], - "_exclusive": Object {}, - "_label": "Where your site's assets files should be written to if you are using the Elder.js template. (Include ./public/)\\"", - "_mutate": undefined, - "_options": Object { - "abortEarly": true, - "recursive": true, - }, - "_type": "string", - "_typeError": [Function], - "_whitelist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "tests": Array [], - "transforms": Array [ - [Function], - ], - "type": "string", - }, - "buildFolder": StringSchema { - "_blacklist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "_conditions": Array [], - "_default": "", - "_deps": Array [], - "_exclusive": Object {}, - "_label": "If Elder.js doesn't find the files it is looking for in the src folder, it will look in the build folder. (used for typescript)", - "_mutate": undefined, - "_options": Object { - "abortEarly": true, - "recursive": true, - }, - "_type": "string", - "_typeError": [Function], - "_whitelist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "tests": Array [], - "transforms": Array [ - [Function], - ], - "type": "string", - }, - "intersectionObserverPoly": StringSchema { - "_blacklist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "_conditions": Array [], - "_default": "/dist/static/intersection-observer.js", - "_deps": Array [], - "_exclusive": Object {}, - "_label": "Elder.js uses a poly fill for the intersection observer. This is where it will be found on your site. (exclude /public/)", - "_mutate": undefined, - "_options": Object { - "abortEarly": true, - "recursive": true, - }, - "_type": "string", - "_typeError": [Function], - "_whitelist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "tests": Array [], - "transforms": Array [ - [Function], - ], - "type": "string", - }, - "public": StringSchema { - "_blacklist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "_conditions": Array [], - "_default": "./public/", - "_deps": Array [], - "_exclusive": Object {}, - "_label": "Where should files be written? This represents the \\"root\\" of your site and where your html will be built.", - "_mutate": undefined, - "_options": Object { - "abortEarly": true, - "recursive": true, - }, - "_type": "string", - "_typeError": [Function], - "_whitelist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "tests": Array [], - "transforms": Array [ - [Function], - ], - "type": "string", - }, - "srcFolder": StringSchema { - "_blacklist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "_conditions": Array [], - "_default": "./src/", - "_deps": Array [], - "_exclusive": Object {}, - "_label": "Elder.js and plugins use this to resolve where things should be in the expected file structure.", - "_mutate": undefined, - "_options": Object { - "abortEarly": true, - "recursive": true, - }, - "_type": "string", - "_typeError": [Function], - "_whitelist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "tests": Array [], - "transforms": Array [ - [Function], - ], - "type": "string", - }, - "svelte": ObjectSchema { - "_blacklist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "_conditions": Array [], - "_defaultDefault": [Function], - "_deps": Array [], - "_excludedEdges": Array [], - "_exclusive": Object {}, - "_mutate": undefined, - "_nodes": Array [ - "clientComponents", - "ssrComponents", - ], - "_options": Object { - "abortEarly": true, - "recursive": true, - }, - "_type": "object", - "_typeError": [Function], - "_whitelist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "fields": Object { - "clientComponents": StringSchema { - "_blacklist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "_conditions": Array [], - "_default": "./public/dist/svelte/", - "_deps": Array [], - "_exclusive": Object {}, - "_label": "Location where Svelte components that are bundled for the client should be saved. (Include ./public/)", - "_mutate": undefined, - "_options": Object { - "abortEarly": true, - "recursive": true, - }, - "_type": "string", - "_typeError": [Function], - "_whitelist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "tests": Array [], - "transforms": Array [ - [Function], - ], - "type": "string", - }, - "ssrComponents": StringSchema { - "_blacklist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "_conditions": Array [], - "_default": "./___ELDER___/compiled/", - "_deps": Array [], - "_exclusive": Object {}, - "_label": "Location where should SSR components be stored.", - "_mutate": undefined, - "_options": Object { - "abortEarly": true, - "recursive": true, - }, - "_type": "string", - "_typeError": [Function], - "_whitelist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "tests": Array [], - "transforms": Array [ - [Function], - ], - "type": "string", - }, - }, - "tests": Array [], - "transforms": Array [ - [Function], - ], - "type": "object", - }, - "systemJs": StringSchema { - "_blacklist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "_conditions": Array [], - "_default": "/dist/static/s.min.js", - "_deps": Array [], - "_exclusive": Object {}, - "_label": "If you are using the recommended Elder.js rollup file it is using Systemjs. This defines is where the systemjs file will be found on your site. (exclude /public/)", - "_mutate": undefined, - "_options": Object { - "abortEarly": true, - "recursive": true, - }, - "_type": "string", - "_typeError": [Function], - "_whitelist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "tests": Array [], - "transforms": Array [ - [Function], - ], - "type": "string", - }, - }, + "fields": Object {}, "tests": Array [], "transforms": Array [ [Function], ], "type": "object", }, - "plugins": ObjectSchema { + "rootDir": StringSchema { "_blacklist": RefSet { "list": Set {}, "refs": Map {}, }, "_conditions": Array [], - "_default": Object {}, - "_defaultDefault": [Function], + "_default": "process.cwd()", "_deps": Array [], - "_excludedEdges": Array [], "_exclusive": Object {}, - "_label": "Used to define Elder.js plugins.", + "_label": "Here your package.json lives.", "_mutate": undefined, - "_nodes": Array [], "_options": Object { "abortEarly": true, "recursive": true, }, - "_type": "object", + "_type": "string", "_typeError": [Function], "_whitelist": RefSet { "list": Set {}, "refs": Map {}, }, - "fields": Object {}, "tests": Array [], "transforms": Array [ [Function], ], - "type": "object", + "type": "string", }, "server": ObjectSchema { "_blacklist": RefSet { @@ -894,22 +661,22 @@ ObjectSchema { ], "type": "string", }, - "typescript": BooleanSchema { + "srcDir": StringSchema { "_blacklist": RefSet { "list": Set {}, "refs": Map {}, }, "_conditions": Array [], - "_default": false, + "_default": "src", "_deps": Array [], "_exclusive": Object {}, - "_label": "This causes Elder.js to look in the /build/ folder ", + "_label": "Where Elder.js should find it's expected file structure. If you are using a build step such as typescript on your project, you may need to edit this. ", "_mutate": undefined, "_options": Object { "abortEarly": true, "recursive": true, }, - "_type": "boolean", + "_type": "string", "_typeError": [Function], "_whitelist": RefSet { "list": Set {}, @@ -919,7 +686,7 @@ ObjectSchema { "transforms": Array [ [Function], ], - "type": "boolean", + "type": "string", }, }, "tests": Array [], @@ -1162,7 +929,7 @@ ObjectSchema { "max": true, "min": true, }, - "_label": "The priority level a hook should run at. Elder.js hooks run at 1 or 100 where 1 is the highest priorty and 100 is the lowest priority.", + "_label": "The priority level a hook should run at. Elder.js hooks run here 100 is the highest priority and 1 is the lowest priority.", "_mutate": undefined, "_options": Object { "abortEarly": true, diff --git a/src/utils/__tests__/getConfig.spec.ts b/src/utils/__tests__/getConfig.spec.ts index 54398277..a217e38e 100644 --- a/src/utils/__tests__/getConfig.spec.ts +++ b/src/utils/__tests__/getConfig.spec.ts @@ -1,5 +1,4 @@ -const defaultConfig = { debug: { automagic: true }, locations: { buildFolder: '' } }; -jest.mock('../tsConfigExist.ts', () => () => true); +const defaultConfig = { debug: { automagic: true }, distDir: 'public', srcDir: 'src', rootDir: 'test' }; jest.mock('../validations.ts', () => ({ getDefaultConfig: () => defaultConfig, })); @@ -14,7 +13,7 @@ jest.mock('cosmiconfig', () => { jest.mock('path', () => { return { - resolve: (...strings) => strings.join('/').replace('./', ''), + resolve: (...strings) => strings.join('/').replace('./', '').replace('test/test', 'test'), }; }); @@ -22,13 +21,16 @@ process.cwd = () => 'test'; describe('#getConfig', () => { const output = { + $$internal: { + clientComponents: 'test/public/svelte/', + ssrComponents: 'test/___ELDER___/compiled/', + }, debug: { automagic: true, }, - locations: { - buildFolder: './build/', - }, - typescript: true, + distDir: 'test/public', + rootDir: 'test', + srcDir: 'test/src', }; beforeEach(() => { @@ -47,22 +49,6 @@ describe('#getConfig', () => { expect(getConfig()).toEqual(defaultConfig); }); - it('not able to set build folder from tsconfig', () => { - jest.mock('fs', () => ({ - readFileSync: () => - JSON.stringify({ - compilerOptions: { - outDir: '/build', - }, - }), - })); - - // eslint-disable-next-line global-require - const getConfig = require('../getConfig').default; - - expect(getConfig()).toEqual(defaultConfig); - }); - it('works', () => { jest.mock('fs', () => ({ readFileSync: () => diff --git a/src/utils/__tests__/index.spec.ts b/src/utils/__tests__/index.spec.ts index 0c7ca475..669765df 100644 --- a/src/utils/__tests__/index.spec.ts +++ b/src/utils/__tests__/index.spec.ts @@ -21,5 +21,6 @@ test('includes all', () => { 'prepareServer', 'prepareProcessStack', 'getConfig', + 'getRollupConfig', ]); }); diff --git a/src/utils/__tests__/svelteComponent.spec.ts b/src/utils/__tests__/svelteComponent.spec.ts index 3507b7c9..9ac0fa32 100644 --- a/src/utils/__tests__/svelteComponent.spec.ts +++ b/src/utils/__tests__/svelteComponent.spec.ts @@ -9,18 +9,16 @@ const componentProps = { permalinks: jest.fn(), }, settings: { - locations: { - public: '/', - svelte: { - ssrComponents: '___ELDER___/compiled/', - clientComponents: 'public/dist/svelte/', - }, - }, + distDir: 'test/public', + rootDir: 'test', + srcDir: 'test/src', $$internal: { hashedComponents: { Home: 'Home.a1b2c3', Datepicker: 'Datepicker.a1b2c3', }, + clientComponents: 'test/public/svelte', + ssrComponents: 'test/___ELDER___/compiled', }, }, }, @@ -112,7 +110,7 @@ describe('#svelteComponent', () => { string: ` function initdatepickerSwrzsrVDCd() { - System.import('public/dist/svelte/Datepicker.a1b2c3.js').then(({ default: App }) => { + System.import('/svelte/Datepicker.a1b2c3.js').then(({ default: App }) => { new App({ target: document.getElementById('datepicker-SwrzsrVDCd'), hydrate: true, props: {"a":"b"} }); }); } diff --git a/src/utils/__tests__/tsConfigExist.spec.ts b/src/utils/__tests__/tsConfigExist.spec.ts deleted file mode 100644 index dcb5b805..00000000 --- a/src/utils/__tests__/tsConfigExist.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import tsConfigExist from '../tsConfigExist'; - -class StatSyncError extends Error { - code: 'ENOENT'; - - constructor(msg: string) { - super(msg); - this.code = 'ENOENT'; - } -} - -jest.mock('fs', () => { - return { - statSync: (path) => { - if (path.startsWith('test')) { - throw new StatSyncError(''); - } - if (path.startsWith('folder')) { - throw new Error(''); - } - return {}; - }, - }; -}); - -test('#tsConfigExist - Error NO ENTity', () => { - process.cwd = () => 'test'; - expect(tsConfigExist()).toBe(false); -}); - -test('#tsConfigExist - Unknown error', () => { - process.cwd = () => 'folder'; - expect(() => tsConfigExist()).toThrow(''); -}); - -test('#tsConfigExist - statSync ok', () => { - process.cwd = () => 'config'; - expect(tsConfigExist()).toBe(true); -}); diff --git a/src/utils/__tests__/validations.spec.ts b/src/utils/__tests__/validations.spec.ts index 0afbb72c..868aa775 100644 --- a/src/utils/__tests__/validations.spec.ts +++ b/src/utils/__tests__/validations.spec.ts @@ -26,6 +26,9 @@ describe('#validations', () => { numberOfWorkers: -1, shuffleRequests: false, }, + rootDir: 'process.cwd()', + srcDir: 'src', + distDir: 'public', debug: { automagic: false, build: false, @@ -37,23 +40,10 @@ describe('#validations', () => { disable: [], }, siteUrl: '', - locations: { - assets: './public/dist/static/', - buildFolder: '', - intersectionObserverPoly: '/dist/static/intersection-observer.js', - public: './public/', - srcFolder: './src/', - svelte: { - clientComponents: './public/dist/svelte/', - ssrComponents: './___ELDER___/compiled/', - }, - systemJs: '/dist/static/s.min.js', - }, plugins: {}, server: { prefix: '', }, - typescript: false, shortcodes: { closePattern: '}}', openPattern: '{{', diff --git a/src/utils/getConfig.ts b/src/utils/getConfig.ts index bcb2dcd1..fed2e73b 100644 --- a/src/utils/getConfig.ts +++ b/src/utils/getConfig.ts @@ -1,10 +1,8 @@ import { cosmiconfigSync } from 'cosmiconfig'; import defaultsDeep from 'lodash.defaultsdeep'; import path from 'path'; -import fs from 'fs'; import { ConfigOptions } from './types'; import { getDefaultConfig } from './validations'; -import getHashedSvelteComponents from './getHashedSvelteComponents'; function getConfig(context?: string): ConfigOptions { const explorerSync = cosmiconfigSync('elder'); @@ -19,8 +17,8 @@ function getConfig(context?: string): ConfigOptions { const rootDir = config.rootDir === 'process.cwd()' ? process.cwd() : path.resolve(config.rootDir); config.rootDir = rootDir; - config.srcDir = path.resolve(rootDir, config.srcDir); - config.distDir = path.resolve(rootDir, config.distDir); + config.srcDir = path.resolve(rootDir, `./${config.srcDir}`); + config.distDir = path.resolve(rootDir, `./${config.distDir}`); const ssrComponents = path.resolve(config.rootDir, './___ELDER___/compiled/'); const clientComponents = path.resolve(config.distDir, './svelte/'); @@ -28,7 +26,6 @@ function getConfig(context?: string): ConfigOptions { config.$$internal = { ssrComponents, clientComponents, - hashedComponents: getHashedSvelteComponents({ ssrComponents, clientComponents }), }; if (config.debug.automagic && (!context || context !== 'build')) { diff --git a/src/utils/getHashedSvelteComponents.ts b/src/utils/getHashedSvelteComponents.ts index ae5b270b..8fc9cc38 100644 --- a/src/utils/getHashedSvelteComponents.ts +++ b/src/utils/getHashedSvelteComponents.ts @@ -1,5 +1,4 @@ import glob from 'glob'; -import path from 'path'; let results = {}; diff --git a/src/utils/getRollupConfig.ts b/src/utils/getRollupConfig.ts index 32171bd3..00b653cd 100644 --- a/src/utils/getRollupConfig.ts +++ b/src/utils/getRollupConfig.ts @@ -125,21 +125,22 @@ export default function getRollupConfig({ svelteConfig }) { [ ['./node_modules/intersection-observer/intersection-observer.js', './static/intersection-observer.js'], ['./node_modules/systemjs/dist/s.min.js', './static/s.min.js'], - ] - .filter((dep) => fs.existsSync(path.resolve(rootDir, dep[0]))) - .forEach((dep) => { - configs.push({ - input: dep[0], - output: [ - { - file: path.resolve(distDir, dep[1]), - format: 'iife', - name: dep[1], - plugins: [terser()], - }, - ], - }); + ].forEach((dep) => { + if (!fs.existsSync(path.resolve(rootDir, dep[0]))) { + throw new Error(`Elder.js peer dependency not found at ${dep[0]}`); + } + configs.push({ + input: dep[0], + output: [ + { + file: path.resolve(distDir, dep[1]), + format: 'iife', + name: dep[1], + plugins: [terser()], + }, + ], }); + }); // SSR /routes/ Svelte files. const templates = glob.sync(`${relSrcDir}/routes/*/*.svelte`).reduce((out, cv) => { diff --git a/src/utils/svelteComponent.ts b/src/utils/svelteComponent.ts index 1d4ab708..2de034d3 100644 --- a/src/utils/svelteComponent.ts +++ b/src/utils/svelteComponent.ts @@ -30,8 +30,7 @@ const svelteComponent = (componentName) => ({ page, props, hydrateOptions }: Com if (!componentCache[cleanComponentName]) { const clientComponents = page.settings.$$internal.hashedComponents; const ssrComponent = path.resolve(page.settings.$$internal.ssrComponents, `./${cleanComponentName}.js`); - let clientSvelteFolder = page.settings.$$internal.clientComponents.replace(page.settings.distDir, ''); - if (clientSvelteFolder.indexOf('.') === 0) clientSvelteFolder = clientSvelteFolder.substring(1); + const clientSvelteFolder = page.settings.$$internal.clientComponents.replace(page.settings.distDir, ''); // eslint-disable-next-line global-require, import/no-dynamic-require const { render } = require(ssrComponent); diff --git a/src/utils/validations.ts b/src/utils/validations.ts index 9713cdf0..a2e204d9 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -144,7 +144,6 @@ const configSchema = yup.object({ `If you have some pages that take longer to generate than others, you may want to shuffle your requests so they are spread out more evenly across processes when building.`, ), }), - typescript: yup.boolean().default(false).label('This causes Elder.js to look in the /build/ folder '), shortcodes: yup.object({ openPattern: yup.string().default('{{').label('Opening pattern for identifying shortcodes in html output.'), closePattern: yup.string().default('}}').label('closing pattern for identifying shortcodes in html output.'), From b87f818c29f54ddefc2aeb25ef320fd17de25403 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Wed, 16 Sep 2020 18:01:30 -0400 Subject: [PATCH 21/75] 0.1.6-next.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e90ae4dd..2df3264f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.0", + "version": "0.1.6-next.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5d30d7a5..56e5eaf9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.0", + "version": "0.1.6-next.1", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From de5090f600db7e6dbc343a6bdbf0aee29c8b35fd Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Wed, 16 Sep 2020 18:42:23 -0400 Subject: [PATCH 22/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20support=20fo?= =?UTF-8?q?r=20plugin=20Svelte=20Files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Elder.ts | 6 +-- src/build/build.ts | 2 +- src/index.ts | 4 +- src/utils/getConfig.ts | 8 +--- src/utils/getRollupConfig.ts | 80 ++++++++++++++++++++++++++++++------ 5 files changed, 75 insertions(+), 25 deletions(-) diff --git a/src/Elder.ts b/src/Elder.ts index afafbebb..a71b64fa 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -40,8 +40,6 @@ import workerBuild from './workerBuild'; import { inlineSvelteComponent } from './partialHydration/inlineSvelteComponent'; import elderJsShortcodes from './shortcodes'; -const getElderConfig = getConfig; - class Elder { bootstrapComplete: Promise; @@ -80,7 +78,7 @@ class Elder { this.markBootstrapComplete = resolve; }); - const config = getConfig(context); + const config = getConfig(); this.settings = { ...config, @@ -500,4 +498,4 @@ class Elder { } } -export { Elder, getElderConfig, build, partialHydration }; +export { Elder, build, partialHydration }; diff --git a/src/build/build.ts b/src/build/build.ts index 5218ce88..15e89b05 100644 --- a/src/build/build.ts +++ b/src/build/build.ts @@ -2,7 +2,7 @@ import cliProgress from 'cli-progress'; import os from 'os'; import cluster from 'cluster'; -import { Elder, getElderConfig } from '../Elder'; +import { Elder, getElderConfig } from '../index'; import shuffleArray from '../utils/shuffleArray'; import { BuildResult } from '../utils/types'; diff --git a/src/index.ts b/src/index.ts index f9410c9a..27fff3cb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,12 @@ /* istanbul ignore file */ export { configSchema, hookSchema, routeSchema, pluginSchema } from './utils/validations'; -export { Elder, getElderConfig, build, partialHydration } from './Elder'; +export { Elder, build, partialHydration } from './Elder'; export * from './utils/types'; export * from './utils/index'; export * from './routes/routes'; export * from './hookInterface/types'; export { hookInterface } from './hookInterface/hookInterface'; export { hookEntityDefinitions } from './hookInterface/hookEntityDefinitions'; + +export { default as getElderConfig } from './utils/getConfig'; diff --git a/src/utils/getConfig.ts b/src/utils/getConfig.ts index fed2e73b..eb06c8f4 100644 --- a/src/utils/getConfig.ts +++ b/src/utils/getConfig.ts @@ -4,7 +4,7 @@ import path from 'path'; import { ConfigOptions } from './types'; import { getDefaultConfig } from './validations'; -function getConfig(context?: string): ConfigOptions { +function getConfig(): ConfigOptions { const explorerSync = cosmiconfigSync('elder'); const explorerSearch = explorerSync.search(); let loadedConfig = {}; @@ -28,12 +28,6 @@ function getConfig(context?: string): ConfigOptions { clientComponents, }; - if (config.debug.automagic && (!context || context !== 'build')) { - console.log( - `debug.automagic:: Your elder.config.js has debug.automagic = true. We call this chatty mode, but it is designed to show you the things we're doing automatically so you're aware. To turn it off set debug.automagic = 'false'`, - ); - } - return config; } diff --git a/src/utils/getRollupConfig.ts b/src/utils/getRollupConfig.ts index 00b653cd..5d510eb7 100644 --- a/src/utils/getRollupConfig.ts +++ b/src/utils/getRollupConfig.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-lonely-if */ // require('dotenv').config(); import svelte from 'rollup-plugin-svelte'; import { nodeResolve } from '@rollup/plugin-node-resolve'; @@ -13,7 +14,8 @@ import glob from 'glob'; import path from 'path'; import fs from 'fs-extra'; import del from 'del'; -import { getElderConfig, partialHydration } from '../Elder'; +import { getElderConfig, partialHydration } from '../index'; +import { ConfigOptions } from './types'; const production = process.env.NODE_ENV === 'production' || !process.env.ROLLUP_WATCH; @@ -107,11 +109,31 @@ function createSSRConfig({ input, output, svelteConfig, multiInputConfig = false return config; } +function getPluginPaths(elderConfig: ConfigOptions) { + const pluginNames = Object.keys(elderConfig.plugins); + + return pluginNames.reduce((out, pluginName) => { + const pluginPath = path.resolve(elderConfig.srcDir, `./plugins/${pluginName}`); + const nmPluginPath = path.resolve(elderConfig.rootDir, `./node_modules/${pluginName}`); + if (fs.existsSync(`${pluginPath}/index.js`)) { + const svelteFiles = glob.sync(`${pluginPath}/*.svelte`); + console.log(`${pluginPath}/*.svelte`, svelteFiles); + if (svelteFiles.length > 0) { + out.push(`${pluginPath}/`); + } + } else if (fs.existsSync(`${nmPluginPath}/package.json`)) { + if (glob.sync(`${nmPluginPath}/*.svelte`).length > 0) { + out.push(`${nmPluginPath}/`); + } + } + return out; + }, []); +} + export default function getRollupConfig({ svelteConfig }) { const elderConfig = getElderConfig(); const { $$internal, distDir, srcDir, rootDir } = elderConfig; const { ssrComponents, clientComponents } = $$internal; - const relSrcDir = srcDir.replace(rootDir, '').substr(1); console.log(`Elder.js using rollup in ${production ? 'production' : 'development'} mode.`); @@ -177,11 +199,14 @@ export default function getRollupConfig({ svelteConfig }) { return out; }, []); + const pluginPaths = getPluginPaths(elderConfig); + + configs = [...configs, ...templates, ...layouts]; + if (production) { // production build does bundle splitting, minification, and babel - configs = [...configs, ...templates, ...layouts]; + if (fs.existsSync(path.resolve(srcDir, `./components/`))) { - console.log(`${relSrcDir}/components/*/*.svelte`); configs.push( createBrowserConfig({ input: [`${relSrcDir}/components/*/*.svelte`], @@ -216,11 +241,11 @@ export default function getRollupConfig({ svelteConfig }) { } } else { // watch/dev build bundles each component individually for faster reload times during dev. - let sharedComponents = []; + if (fs.existsSync(path.resolve(srcDir, `./components/`))) { - sharedComponents = glob.sync(path.resolve(srcDir, './components/*/*.svelte')).reduce((out, cv) => { + glob.sync(path.resolve(srcDir, './components/*/*.svelte')).forEach((cv) => { const file = cv.replace(`${rootDir}/`, ''); - out.push( + configs.push( createBrowserConfig({ input: file, output: { @@ -232,7 +257,7 @@ export default function getRollupConfig({ svelteConfig }) { svelteConfig, }), ); - out.push( + configs.push( createSSRConfig({ input: file, output: { @@ -243,12 +268,43 @@ export default function getRollupConfig({ svelteConfig }) { svelteConfig, }), ); - - return out; - }, []); + }); } - configs = [...configs, ...templates, ...layouts, ...sharedComponents]; } + pluginPaths.forEach((pluginPath) => { + configs.push( + createBrowserConfig({ + input: [`${pluginPath}*.svelte`], + output: { + dir: clientComponents, + entryFileNames: 'entry[name]-[hash].js', + sourcemap: !production, + format: 'system', + }, + multiInputConfig: multiInput({ + relative: pluginPath.replace(elderConfig.distDir, '').substr(1), + transformOutputPath: (output) => `${path.basename(output)}`, + }), + svelteConfig, + }), + ); + configs.push( + createSSRConfig({ + input: [`${pluginPath}*.svelte`], + output: { + dir: ssrComponents, + format: 'cjs', + exports: 'auto', + }, + multiInputConfig: multiInput({ + relative: pluginPath.replace(elderConfig.distDir, '').substr(1), + transformOutputPath: (output) => `${path.basename(output)}`, + }), + svelteConfig, + }), + ); + }); + return configs; } From b4739603ed2d5dcc54bc8eeaa21d97a3a0eeb733 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Wed, 16 Sep 2020 18:44:16 -0400 Subject: [PATCH 23/75] 0.1.6-next.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2df3264f..6edba0b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.1", + "version": "0.1.6-next.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 56e5eaf9..e02475f1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.1", + "version": "0.1.6-next.2", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From 52cf00b9d4bce39753db187909161dd827a5baff Mon Sep 17 00:00:00 2001 From: halafi Date: Thu, 17 Sep 2020 09:40:51 +0200 Subject: [PATCH 24/75] fix: eslint --- src/hooks.ts | 2 +- src/utils/Page.ts | 4 +- src/utils/types.ts | 74 +++--- src/utils/validations.ts | 1 - yarn.lock | 501 ++++++++++++++++++++++++++++++++------- 5 files changed, 456 insertions(+), 126 deletions(-) diff --git a/src/hooks.ts b/src/hooks.ts index d138bf90..de9fa1b3 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -163,7 +163,7 @@ const hooks: Array = [ name: 'elderCompileHtml', description: 'Creates an HTML string out of the Svelte layout and stacks.', priority: 50, - run: async ({ request, headString, footerString, layoutHtml, htmlString }) => { + run: async ({ request, headString, footerString, layoutHtml }) => { return { htmlString: `${headString}${layoutHtml}${footerString}`, }; diff --git a/src/utils/Page.ts b/src/utils/Page.ts index a2f454f9..96d21e8d 100644 --- a/src/utils/Page.ts +++ b/src/utils/Page.ts @@ -50,7 +50,7 @@ const buildPage = async (page) => { await page.runHook('shortcodes', page); - // todo: readonly proxies? + // TODO: readonly proxies? page.perf.start('html.layout'); page.layoutHtml = page.route.layout({ page, @@ -59,7 +59,7 @@ const buildPage = async (page) => { helpers: page.helpers, settings: page.settings, request: page.request, - routeHTML: page.routeHtml, //todo, depreciate this + routeHTML: page.routeHtml, // TODO: depreciate this routeHtml: page.routeHtml, }, }); diff --git a/src/utils/types.ts b/src/utils/types.ts index 347ac958..767bcaba 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -23,18 +23,26 @@ type DebugOptions = { automagic: boolean; }; -type PathOptions = { - // assets: string; - // public: string; - // svelte: SvelteOptions; - // systemJs: string; - // intersectionObserverPoly: string; - // srcFolder: string; - // buildFolder: string; +// type PathOptions = { +/* + assets: string; + public: string; + svelte: SvelteOptions; + systemJs: string; + intersectionObserverPoly: string; + srcFolder: string; + buildFolder: string; +*/ + +// distDir: string; +// srcDir: string; +// rootDir: string; +// }; - distDir: string; - srcDir: string; - rootDir: string; +type Internal = { + hashedComponents?: {}; + ssrComponents: string; + clientComponents: string; }; export type ConfigOptions = { @@ -59,12 +67,6 @@ export type ConfigOptions = { $$internal: Internal; }; -type Internal = { - hashedComponents?: {}; - ssrComponents: string; - clientComponents: string; -}; - export type SettingOptions = { server: boolean; build: boolean; @@ -116,6 +118,25 @@ interface Init { (input: any): any; } +export interface ShortcodeResponse { + html?: string; + css?: string; + js?: string; + head?: string; +} + +export interface ShortcodeDef { + shortcode: string; + run: (any) => ShortcodeResponse | Promise; + plugin?: any; // reference to the plugin closure scope. + $$meta: { + addedBy: string; + type: string; + }; +} + +export type ShortcodeDefs = Array; + export type PluginOptions = { name: string; description: string; @@ -141,22 +162,3 @@ export interface ComponentPayload { props: any; hydrateOptions?: HydrateOptions; } - -export interface ShortcodeDef { - shortcode: string; - run: (any) => ShortcodeResponse | Promise; - plugin?: any; // reference to the plugin closure scope. - $$meta: { - addedBy: string; - type: string; - }; -} - -export interface ShortcodeResponse { - html?: string; - css?: string; - js?: string; - head?: string; -} - -export type ShortcodeDefs = Array; diff --git a/src/utils/validations.ts b/src/utils/validations.ts index a2e204d9..979ff96e 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -1,5 +1,4 @@ import * as yup from 'yup'; -import path from 'path'; import type { ConfigOptions, PluginOptions, ShortcodeDef } from './types'; import type { RouteOptions } from '../routes/types'; import type { HookOptions } from '../hookInterface/types'; diff --git a/yarn.lock b/yarn.lock index ea16c463..e8ee769e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== @@ -63,7 +63,7 @@ dependencies: "@babel/types" "^7.11.0" -"@babel/helper-module-imports@^7.10.4": +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== @@ -225,6 +225,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/runtime@^7.0.0-beta.55": + version "7.11.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" + integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.10.5": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.5.tgz#303d8bd440ecd5a491eae6117fd3367698674c5c" @@ -311,14 +318,25 @@ resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-9.1.2.tgz#d05f66db03e3a3638a654e8badf2deb489eb220d" integrity sha512-r3fwVbVH+M8W0qYlBBZFsUwKe6NT5qvz+EmU7sr8VeN1cQ63z+3cfXyTo7WGGEMEgKiT0jboNAK3b1FZp8k9LQ== -"@eslint/eslintrc@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.1.0.tgz#3d1f19fb797d42fb1c85458c1c73541eeb1d9e76" - integrity sha512-bfL5365QSCmH6cPeFT7Ywclj8C7LiF7sO6mUGzZhtAMV7iID1Euq6740u/SRi4C80NOnVz/CEfK8/HO+nCAPJg== +"@elderjs/shortcodes@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@elderjs/shortcodes/-/shortcodes-1.0.6.tgz#11a675a6aab1446422dd597c8013508729404b7a" + integrity sha512-8n6FpnCbr4RnJYQDs7869zeywYXNyVtZnA5E4fHYWp2/fJX3OlDp7eYfMj6AnoE+E3Ehs5LVn9uT+rqUXcA0pQ== + +"@eslint/eslintrc@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.1.3.tgz#7d1a2b2358552cc04834c0979bd4275362e37085" + integrity sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA== dependencies: ajv "^6.12.4" debug "^4.1.1" + espree "^7.3.0" + globals "^12.1.0" + ignore "^4.0.6" import-fresh "^3.2.1" + js-yaml "^3.13.1" + lodash "^4.17.19" + minimatch "^3.0.4" strip-json-comments "^3.1.1" "@istanbuljs/load-nyc-config@^1.0.0": @@ -550,6 +568,56 @@ "@nodelib/fs.scandir" "2.1.3" fastq "^1.6.0" +"@rollup/plugin-commonjs@^14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-14.0.0.tgz#4285f9ec2db686a31129e5a2b415c94aa1f836f0" + integrity sha512-+PSmD9ePwTAeU106i9FRdc+Zb3XUWyW26mo5Atr2mk82hor8+nPwkztEjFo8/B1fJKfaQDg9aM2bzQkjhi7zOw== + dependencies: + "@rollup/pluginutils" "^3.0.8" + commondir "^1.0.1" + estree-walker "^1.0.1" + glob "^7.1.2" + is-reference "^1.1.2" + magic-string "^0.25.2" + resolve "^1.11.0" + +"@rollup/plugin-json@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-4.1.0.tgz#54e09867ae6963c593844d8bd7a9c718294496f3" + integrity sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw== + dependencies: + "@rollup/pluginutils" "^3.0.8" + +"@rollup/plugin-node-resolve@^8.4.0": + version "8.4.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.4.0.tgz#261d79a680e9dc3d86761c14462f24126ba83575" + integrity sha512-LFqKdRLn0ShtQyf6SBYO69bGE1upV6wUhBX0vFOUnLAyzx5cwp8svA0eHUnu8+YU57XOkrMtfG63QOpQx25pHQ== + dependencies: + "@rollup/pluginutils" "^3.1.0" + "@types/resolve" "1.17.1" + builtin-modules "^3.1.0" + deep-freeze "^0.0.1" + deepmerge "^4.2.2" + is-module "^1.0.0" + resolve "^1.17.0" + +"@rollup/plugin-replace@^2.3.3": + version "2.3.3" + resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-2.3.3.tgz#cd6bae39444de119f5d905322b91ebd4078562e7" + integrity sha512-XPmVXZ7IlaoWaJLkSCDaa0Y6uVo5XQYHhiMFzOd5qSv5rE+t/UJToPIOE56flKIxBFQI27ONsxb7dqHnwSsjKQ== + dependencies: + "@rollup/pluginutils" "^3.0.8" + magic-string "^0.25.5" + +"@rollup/pluginutils@^3.0.0", "@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" + integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== + dependencies: + "@types/estree" "0.0.39" + estree-walker "^1.0.1" + picomatch "^2.2.2" + "@sinonjs/commons@^1.7.0": version "1.8.1" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217" @@ -602,6 +670,16 @@ resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== +"@types/estree@*": + version "0.0.45" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884" + integrity sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g== + +"@types/estree@0.0.39": + version "0.0.39" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" + integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== + "@types/fs-extra@^9.0.1": version "9.0.1" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.1.tgz#91c8fc4c51f6d5dbe44c2ca9ab09310bd00c7918" @@ -609,6 +687,14 @@ dependencies: "@types/node" "*" +"@types/glob@^7.1.1": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" + integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + "@types/graceful-fs@^4.1.2": version "4.1.3" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.3.tgz#039af35fe26bec35003e8d86d2ee9c586354348f" @@ -651,10 +737,10 @@ jest-diff "^25.2.1" pretty-format "^25.2.1" -"@types/jest@^26.0.12": - version "26.0.12" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.12.tgz#0f20fef9e74f55a312530284e6178f3b3254f501" - integrity sha512-vZOFjm562IPb1EmaKxMjdcouxVb1l3NqoUH4XC4tDQ2R/AWde+0HXBUhyfc6L+7vc3mJ393U+5vr3nH2CLSVVg== +"@types/jest@^26.0.14": + version "26.0.14" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.14.tgz#078695f8f65cb55c5a98450d65083b2b73e5a3f3" + integrity sha512-Hz5q8Vu0D288x3iWXePSn53W7hAjP0H7EQ6QvDO9c7t46mR0lNOLlfuwQ+JkVxuhygHzlzPX+0jKdA3ZgSh+Vg== dependencies: jest-diff "^25.2.1" pretty-format "^25.2.1" @@ -669,15 +755,20 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= +"@types/minimatch@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== + "@types/node@*": version "14.0.27" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.27.tgz#a151873af5a5e851b51b3b065c9e63390a9e0eb1" integrity sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g== -"@types/node@^14.6.2": - version "14.6.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.6.2.tgz#264b44c5a28dfa80198fc2f7b6d3c8a054b9491f" - integrity sha512-onlIwbaeqvZyniGPfdw/TEhKIh79pz66L1q06WUQqJLnAb6wbjvOtepLYTGHTqzdXgBYIE3ZdmqHDGsRsbBz7A== +"@types/node@^14.10.3": + version "14.10.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.10.3.tgz#5ae1f119c96643fc9b19b2d1a83bfa2ec3dbb7ea" + integrity sha512-zdN0hor7TLkjAdKTnYW+Y22oIhUUpil5ZD1V1OFq0CR0CLKw+NdR6dkziTfkWRLo6sKzisayoj/GNpNbe4LY9Q== "@types/normalize-package-data@^2.4.0": version "2.4.0" @@ -694,6 +785,13 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.0.2.tgz#5bb52ee68d0f8efa9cc0099920e56be6cc4e37f3" integrity sha512-IkVfat549ggtkZUthUzEX49562eGikhSYeVGX97SkMFn+sTZrgRewXjQ4tPKFPCykZHkX1Zfd9OoELGqKU2jJA== +"@types/resolve@1.17.1": + version "1.17.1" + resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" + integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw== + dependencies: + "@types/node" "*" + "@types/stack-utils@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" @@ -711,28 +809,28 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.1.tgz#88bde9239e29d688315718552cf80a3490491017" - integrity sha512-pQZtXupCn11O4AwpYVUX4PDFfmIJl90ZgrEBg0CEcqlwvPiG0uY81fimr1oMFblZnpKAq6prrT9a59pj1x58rw== +"@typescript-eslint/eslint-plugin@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.1.1.tgz#78d5b18e259b13c2f4ec41dd9105af269a161a75" + integrity sha512-Hoxyt99EA9LMmqo/5PuWWPeWeB3mKyvibfJ1Hy5SfiUpjE8Nqp+5QNd9fOkzL66+fqvIWSIE+Ett16LGMzCGnQ== dependencies: - "@typescript-eslint/experimental-utils" "4.0.1" - "@typescript-eslint/scope-manager" "4.0.1" + "@typescript-eslint/experimental-utils" "4.1.1" + "@typescript-eslint/scope-manager" "4.1.1" debug "^4.1.1" functional-red-black-tree "^1.0.1" regexpp "^3.0.0" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz#7d9a3ab6821ad5274dad2186c1aa0d93afd696eb" - integrity sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw== +"@typescript-eslint/experimental-utils@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.1.1.tgz#52ff4e37c93113eb96385a4e6d075abece1ea72d" + integrity sha512-jzYsNciHoa4Z3c1URtmeT/bamYm8Dwfw6vuN3WHIE/BXb1iC4KveAnXDErTAZtPVxTYBaYn3n2gbt6F6D2rm1A== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.0.1" - "@typescript-eslint/types" "4.0.1" - "@typescript-eslint/typescript-estree" "4.0.1" + "@typescript-eslint/scope-manager" "4.1.1" + "@typescript-eslint/types" "4.1.1" + "@typescript-eslint/typescript-estree" "4.1.1" eslint-scope "^5.0.0" eslint-utils "^2.0.0" @@ -746,28 +844,28 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.0.1.tgz#73772080db7a7a4534a35d719e006f503e664dc3" - integrity sha512-1+qLmXHNAWSQ7RB6fdSQszAiA7JTwzakj5cNYjBTUmpH2cqilxMZEIV+DRKjVZs8NzP3ALmKexB0w/ExjcK9Iw== +"@typescript-eslint/parser@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.1.1.tgz#324b4b35e314075adbc92bd8330cf3ef0c88cf3e" + integrity sha512-NLIhmicpKGfJbdXyQBz9j48PA6hq6e+SDOoXy7Ak6bq1ebGqbgG+fR1UIDAuay6OjQdot69c/URu2uLlsP8GQQ== dependencies: - "@typescript-eslint/scope-manager" "4.0.1" - "@typescript-eslint/types" "4.0.1" - "@typescript-eslint/typescript-estree" "4.0.1" + "@typescript-eslint/scope-manager" "4.1.1" + "@typescript-eslint/types" "4.1.1" + "@typescript-eslint/typescript-estree" "4.1.1" debug "^4.1.1" -"@typescript-eslint/scope-manager@4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz#24d93c3000bdfcc5a157dc4d32b742405a8631b5" - integrity sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ== +"@typescript-eslint/scope-manager@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.1.1.tgz#bdb8526e82435f32b4ccd9dd4cec01af97b48850" + integrity sha512-0W8TTobCvIIQ2FsrYTffyZGAAFUyIbEHq5EYJb1m7Rpd005jrnOvKOo8ywCLhs/Bm17C+KsrUboBvBAARQVvyA== dependencies: - "@typescript-eslint/types" "4.0.1" - "@typescript-eslint/visitor-keys" "4.0.1" + "@typescript-eslint/types" "4.1.1" + "@typescript-eslint/visitor-keys" "4.1.1" -"@typescript-eslint/types@4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.0.1.tgz#1cf72582f764931f085cb8230ff215980fe467b2" - integrity sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg== +"@typescript-eslint/types@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.1.1.tgz#57500c4a86b28cb47094c1a62f1177ea279a09cb" + integrity sha512-zrBiqOKYerMTllKcn+BP+i1b7LW/EbMMYytroXMxUTvFPn1smkCu0D7lSAx29fTUO4jnwV0ljSvYQtn2vNrNxA== "@typescript-eslint/typescript-estree@2.34.0": version "2.34.0" @@ -782,13 +880,13 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/typescript-estree@4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz#29a43c7060641ec51c902d9f50ac7c5866ec479f" - integrity sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw== +"@typescript-eslint/typescript-estree@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.1.1.tgz#2015a84d71303ecdb6f46efd807ac19a51aab490" + integrity sha512-2AUg5v0liVBsqbGxBphbJ0QbGqSRVaF5qPoTPWcxop+66vMdU1h4CCvHxTC47+Qb+Pr4l2RhXDd41JNpwcQEKw== dependencies: - "@typescript-eslint/types" "4.0.1" - "@typescript-eslint/visitor-keys" "4.0.1" + "@typescript-eslint/types" "4.1.1" + "@typescript-eslint/visitor-keys" "4.1.1" debug "^4.1.1" globby "^11.0.1" is-glob "^4.0.1" @@ -796,12 +894,12 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/visitor-keys@4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz#d4e8de62775f2a6db71c7e8539633680039fdd6c" - integrity sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw== +"@typescript-eslint/visitor-keys@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.1.1.tgz#bb05664bf4bea28dc120d1da94f3027d42ab0f6f" + integrity sha512-/EOOXbA2ferGLG6RmCHEQ0lTTLkOlXYDgblCmQk3tIU7mTPLm4gKhFMeeUSe+bcchTUsKeCk8xcpbop5Zr/8Rw== dependencies: - "@typescript-eslint/types" "4.0.1" + "@typescript-eslint/types" "4.1.1" eslint-visitor-keys "^2.0.0" abab@^2.0.3: @@ -832,6 +930,14 @@ acorn@^7.1.1, acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3: version "6.12.3" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706" @@ -1156,6 +1262,11 @@ buffer-from@1.x, buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +builtin-modules@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484" + integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw== + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -1253,6 +1364,11 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -1336,6 +1452,11 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + commitizen@^4.0.3: version "4.2.1" resolved "https://registry.yarnpkg.com/commitizen/-/commitizen-4.2.1.tgz#3b098b16c6b1a37f0d129018dff6751b20cd3103" @@ -1356,6 +1477,11 @@ commitizen@^4.0.3: strip-bom "4.0.0" strip-json-comments "3.0.1" +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + component-emitter@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" @@ -1393,6 +1519,11 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= +core-js@^3.1.3: + version "3.6.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" + integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== + core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -1535,6 +1666,11 @@ dedent@0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= +deep-freeze@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84" + integrity sha1-OgsABd4YZygZ39OM0x+RF5yJPoQ= + deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -1574,6 +1710,20 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" +del@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7" + integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA== + dependencies: + globby "^10.0.1" + graceful-fs "^4.2.2" + is-glob "^4.0.1" + is-path-cwd "^2.2.0" + is-path-inside "^3.0.1" + p-map "^3.0.0" + rimraf "^3.0.0" + slash "^3.0.0" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -1820,13 +1970,13 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== -eslint@^7.8.0: - version "7.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.8.0.tgz#9a3e2e6e4d0a3f8c42686073c25ebf2e91443e8a" - integrity sha512-qgtVyLZqKd2ZXWnLQA4NtVbOyH56zivOAdBFWE54RFkSZjokzNrcP4Z0eVWsZ+84ByXv+jL9k/wE1ENYe8xRFw== +eslint@^7.9.0: + version "7.9.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.9.0.tgz#522aeccc5c3a19017cf0cb46ebfd660a79acf337" + integrity sha512-V6QyhX21+uXp4T+3nrNfI3hQNBDa/P8ga7LoQOenwrlEFXrEnUEE+ok1dMtaS3b6rmLXhT1TkTIsG75HMLbknA== dependencies: "@babel/code-frame" "^7.0.0" - "@eslint/eslintrc" "^0.1.0" + "@eslint/eslintrc" "^0.1.3" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -1901,6 +2051,16 @@ estraverse@^5.1.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== +estree-walker@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" + integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== + +estree-walker@^1.0.0, estree-walker@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" + integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -2039,7 +2199,7 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== -fast-glob@^3.1.1: +fast-glob@^3.0.0, fast-glob@^3.0.3, fast-glob@^3.1.1: version "3.2.4" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== @@ -2198,7 +2358,7 @@ fs-extra@8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^9.0.1: +fs-extra@^9.0.0, fs-extra@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc" integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ== @@ -2213,7 +2373,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^2.1.2: +fsevents@^2.1.2, fsevents@~2.1.2: version "2.1.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== @@ -2344,6 +2504,20 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" +globby@^10.0.1: + version "10.0.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" + integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg== + dependencies: + "@types/glob" "^7.1.1" + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.0.3" + glob "^7.1.3" + ignore "^5.1.1" + merge2 "^1.2.3" + slash "^3.0.0" + globby@^11.0.1: version "11.0.1" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" @@ -2356,7 +2530,7 @@ globby@^11.0.1: merge2 "^1.3.0" slash "^3.0.0" -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== @@ -2477,7 +2651,12 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ignore@^5.1.4: +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.1, ignore@^5.1.4: version "5.1.8" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== @@ -2503,6 +2682,11 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -2540,11 +2724,6 @@ inquirer@6.5.2: strip-ansi "^5.1.0" through "^2.3.6" -intersection-observer@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.11.0.tgz#f4ea067070326f68393ee161cc0a2ca4c0040c6f" - integrity sha512-KZArj2QVnmdud9zTpKf279m2bbGfG+4/kn16UU0NL3pTVl52ZHiJ9IRNSsnn6jaHrL9EGLFM5eWjTx2fz/+zoQ== - ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" @@ -2667,6 +2846,11 @@ is-glob@^4.0.0, is-glob@^4.0.1: dependencies: is-extglob "^2.1.1" +is-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" + integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -2679,6 +2863,16 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-path-cwd@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-inside@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" + integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== + is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -2691,6 +2885,13 @@ is-potential-custom-element-name@^1.0.0: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397" integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c= +is-reference@^1.1.2, is-reference@^1.1.4: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" + integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== + dependencies: + "@types/estree" "*" + is-regex@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" @@ -3189,7 +3390,7 @@ jest-watcher@^26.3.0: jest-util "^26.3.0" string-length "^4.0.1" -jest-worker@^26.3.0: +jest-worker@^26.0.0, jest-worker@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.3.0.tgz#7c8a97e4f4364b4f05ed8bca8ca0c24de091871f" integrity sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw== @@ -3432,7 +3633,7 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash@^4.17.12, lodash@^4.17.20: +lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.20: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== @@ -3447,6 +3648,13 @@ longest@^2.0.1: resolved "https://registry.yarnpkg.com/longest/-/longest-2.0.1.tgz#781e183296aa94f6d4d916dc335d0d17aefa23f8" integrity sha1-eB4YMpaqlPbU2RbcM10NF676I/g= +magic-string@^0.25.2, magic-string@^0.25.4, magic-string@^0.25.5: + version "0.25.7" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" + integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== + dependencies: + sourcemap-codec "^1.4.4" + make-dir@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -3483,11 +3691,16 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.3.0: +merge2@^1.2.3, merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== +merge@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" + integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== + micromatch@^3.0.4, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -3834,6 +4047,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-map@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" + integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== + dependencies: + aggregate-error "^3.0.0" + p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" @@ -3930,7 +4150,7 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: +picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1, picomatch@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== @@ -3983,10 +4203,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.1.1.tgz#d9485dd5e499daa6cb547023b87a6cf51bee37d6" - integrity sha512-9bY+5ZWCfqj3ghYBLxApy2zf6m+NJo5GzmLTpr9FsApsfjriNnS2dahWReHMi7qNPhhHl9SYHJs2cHZLgexNIw== +prettier@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.1.2.tgz#3050700dae2e4c8b67c4c3f666cdb8af405e1ce5" + integrity sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg== pretty-format@^25.2.1, pretty-format@^25.5.0: version "25.5.0" @@ -4049,6 +4269,13 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + react-is@^16.12.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -4175,6 +4402,11 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== +require-relative@^0.8.7: + version "0.8.7" + resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" + integrity sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4= + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -4212,7 +4444,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.10.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2: +resolve@^1.10.0, resolve@^1.11.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== @@ -4251,6 +4483,82 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +rollup-plugin-babel@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz#d15bd259466a9d1accbdb2fe2fff17c52d030acb" + integrity sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + rollup-pluginutils "^2.8.1" + +rollup-plugin-css-only@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-css-only/-/rollup-plugin-css-only-2.1.0.tgz#b9e8505eb01c5257b5eab65bd51eec9050bed9a3" + integrity sha512-pfdcqAWEmRMFy+ABXAQPA/DKyPqLuBTOf+lWSOgtrVs1v/q7DSXzYa9QZg4myd8/1F7NHcdvPkWnfWqMxq9vrw== + dependencies: + "@rollup/pluginutils" "^3.0.0" + fs-extra "^9.0.0" + +rollup-plugin-delete@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-delete/-/rollup-plugin-delete-2.0.0.tgz#262acf80660d48c3b167fb0baabd0c3ab985c153" + integrity sha512-/VpLMtDy+8wwRlDANuYmDa9ss/knGsAgrDhM+tEwB1npHwNu4DYNmDfUL55csse/GHs9Q+SMT/rw9uiaZ3pnzA== + dependencies: + del "^5.1.0" + +rollup-plugin-external-globals@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-external-globals/-/rollup-plugin-external-globals-0.5.0.tgz#1662cacfb240a6e4e0618db2b79e9feae0134603" + integrity sha512-v3qjync/2wcqdSesNP3qPnYeOnnV39ydCU+2fTxjlmux8uA1VqM4cUVffkgzoDh3TBOEhN8JWAHrN7Hs9ZD0Sg== + dependencies: + estree-walker "^1.0.0" + is-reference "^1.1.4" + magic-string "^0.25.4" + rollup-pluginutils "^2.8.2" + +rollup-plugin-multi-input@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/rollup-plugin-multi-input/-/rollup-plugin-multi-input-1.1.1.tgz#c77fbb8d042952fb7b877de5c00da553a914f28d" + integrity sha512-q/sFiS7h7AQk0V/fFREt5Gizewov01V1RZgORFmXL6W9emkJOPu94GFJ21KYtSob4bmEmDq9Hpr+3ukKNi84CA== + dependencies: + "@babel/runtime" "^7.0.0-beta.55" + core-js "^3.1.3" + fast-glob "^3.0.0" + lodash "^4.17.11" + +rollup-plugin-svelte@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/rollup-plugin-svelte/-/rollup-plugin-svelte-6.0.1.tgz#a4fc9c19c5c4277e6dbf8e79185c4cbd6b4383bf" + integrity sha512-kS9/JZMBNgpKTqVKlwV8mhmGwxu8NiNf6+n5ZzdZ8yDp3+ADqjf8Au+JNEpoOn6kLlh1hLS2Gsa76k9RP57HDQ== + dependencies: + require-relative "^0.8.7" + rollup-pluginutils "^2.8.2" + sourcemap-codec "^1.4.8" + +rollup-plugin-terser@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-6.1.0.tgz#071866585aea104bfbb9dd1019ac523e63c81e45" + integrity sha512-4fB3M9nuoWxrwm39habpd4hvrbrde2W2GG4zEGPQg1YITNkM3Tqur5jSuXlWNzbv/2aMLJ+dZJaySc3GCD8oDw== + dependencies: + "@babel/code-frame" "^7.8.3" + jest-worker "^26.0.0" + serialize-javascript "^3.0.0" + terser "^4.7.0" + +rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2: + version "2.8.2" + resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" + integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== + dependencies: + estree-walker "^0.6.1" + +rollup@^2.21.0: + version "2.27.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.27.1.tgz#372744e1d36eba0fd942d997600c2fc2ca266305" + integrity sha512-GiWHQvnmMgBktSpY/1+nrGpwPsTw4b9P28og2uedfeq4JZ16rzAmnQ5Pm/E0/BEmDNia1ZbY7+qu3nBgNa19Hg== + optionalDependencies: + fsevents "~2.1.2" + rsvp@^4.8.4: version "4.8.5" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" @@ -4273,7 +4581,7 @@ rxjs@^6.4.0: dependencies: tslib "^1.9.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.2: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -4332,6 +4640,13 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +serialize-javascript@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-3.1.0.tgz#8bf3a9170712664ef2561b44b691eafe399214ea" + integrity sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg== + dependencies: + randombytes "^2.1.0" + set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -4441,7 +4756,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.17, source-map-support@^0.5.6: +source-map-support@^0.5.17, source-map-support@^0.5.6, source-map-support@~0.5.12: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== @@ -4469,6 +4784,11 @@ source-map@^0.7.3: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== +sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -4665,6 +4985,11 @@ supports-hyperlinks@^2.0.0: has-flag "^4.0.0" supports-color "^7.0.0" +svelte@^3.25.1: + version "3.25.1" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.25.1.tgz#218def1243fea5a97af6eb60f5e232315bb57ac4" + integrity sha512-IbrVKTmuR0BvDw4ii8/gBNy8REu7nWTRy9uhUz+Yuae5lIjWgSGwKlWtJGC2Vg95s+UnXPqDu0Kk/sUwe0t2GQ== + symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -4675,11 +5000,6 @@ synchronous-promise@^2.0.13: resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.13.tgz#9d8c165ddee69c5a6542862b405bc50095926702" integrity sha512-R9N6uDkVsghHePKh1TEqbnLddO2IY25OcsksyFp/qBe7XYd0PVbKEWxhcdMhpLzE1I6skj5l4aEZ3CRxcbArlA== -systemjs@^6.5.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/systemjs/-/systemjs-6.5.0.tgz#42e5e19e324e99b6e96a946697fddb3de9f6f3d5" - integrity sha512-B+NzKJD1srC/URfNVBdDExAUAsAVXpVQxZxX54AtqU0xiK9imkqurQu3qi6JdyA2GBAw2ssjolYIa7kh+xY1uw== - table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" @@ -4698,6 +5018,15 @@ terminal-link@^2.0.0: ansi-escapes "^4.2.1" supports-hyperlinks "^2.0.0" +terser@^4.7.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" + integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" From 56c87257dc18b2c7ff38fb2eab0e647dba6ec521 Mon Sep 17 00:00:00 2001 From: halafi Date: Thu, 17 Sep 2020 09:43:46 +0200 Subject: [PATCH 25/75] chore: package-lock --- package-lock.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 6edba0b2..78095b56 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4142,7 +4142,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, "optional": true }, "function-bind": { @@ -8465,6 +8464,14 @@ "glob": "^7.1.3" } }, + "rollup": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.27.1.tgz", + "integrity": "sha512-GiWHQvnmMgBktSpY/1+nrGpwPsTw4b9P28og2uedfeq4JZ16rzAmnQ5Pm/E0/BEmDNia1ZbY7+qu3nBgNa19Hg==", + "requires": { + "fsevents": "~2.1.2" + } + }, "rollup-plugin-babel": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz", From 39b913348a929948a77e8f51d4c288ae780da09f Mon Sep 17 00:00:00 2001 From: halafi Date: Thu, 17 Sep 2020 10:12:16 +0200 Subject: [PATCH 26/75] test(build): fix config mock, mock cosmiconfig --- src/build/__tests__/build.spec.ts | 21 +++++++++++++-------- src/build/build.ts | 3 ++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/build/__tests__/build.spec.ts b/src/build/__tests__/build.spec.ts index 1b64cf36..ae717966 100644 --- a/src/build/__tests__/build.spec.ts +++ b/src/build/__tests__/build.spec.ts @@ -3,8 +3,21 @@ import { getWorkerCounts } from '../build'; let calledHooks = []; +jest.mock('cosmiconfig', () => ({ + cosmiconfigSync: () => ({ search: () => null }), +})); + jest.mock('cli-progress'); +jest.mock('../../utils/getConfig', () => () => ({ + debug: { + build: true, + }, + build: { + numberOfWorkers: 5, + }, +})); + jest.mock('../../Elder', () => ({ Elder: class ElderMock { errors: []; @@ -34,14 +47,6 @@ jest.mock('../../Elder', () => ({ }); } }, - getElderConfig: () => ({ - debug: { - build: true, - }, - build: { - numberOfWorkers: 5, - }, - }), })); jest.mock('os', () => ({ diff --git a/src/build/build.ts b/src/build/build.ts index 15e89b05..4e5789c9 100644 --- a/src/build/build.ts +++ b/src/build/build.ts @@ -2,7 +2,8 @@ import cliProgress from 'cli-progress'; import os from 'os'; import cluster from 'cluster'; -import { Elder, getElderConfig } from '../index'; +import getElderConfig from '../utils/getConfig'; +import { Elder } from '../Elder'; import shuffleArray from '../utils/shuffleArray'; import { BuildResult } from '../utils/types'; From e34b4ca16232b9b75d3d92c3d362c64ea90e1604 Mon Sep 17 00:00:00 2001 From: halafi Date: Thu, 17 Sep 2020 10:31:47 +0200 Subject: [PATCH 27/75] fix(externalhelpers.spec): broken tests --- .../externalHelpers.spec.ts.snap | 24 +++++++-- src/__tests__/externalHelpers.spec.ts | 54 ++++++++++--------- 2 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/__tests__/__snapshots__/externalHelpers.spec.ts.snap b/src/__tests__/__snapshots__/externalHelpers.spec.ts.snap index a3b579ae..1483d886 100644 --- a/src/__tests__/__snapshots__/externalHelpers.spec.ts.snap +++ b/src/__tests__/__snapshots__/externalHelpers.spec.ts.snap @@ -1,9 +1,25 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`#externalHelpers works - buildHelpers 1`] = `undefined`; +exports[`#externalHelpers works - userHelpers is a function 1`] = ` +Object { + "userHelper": [Function], +} +`; -exports[`#externalHelpers works - buildHelpers 2`] = `undefined`; +exports[`#externalHelpers works - userHelpers is a function 2`] = ` +Object { + "userHelper": [Function], +} +`; -exports[`#externalHelpers works - userHelpers 1`] = `undefined`; +exports[`#externalHelpers works - userHelpers is not a function 1`] = ` +Object { + "userHelper": [Function], +} +`; -exports[`#externalHelpers works - userHelpers 2`] = `undefined`; +exports[`#externalHelpers works - userHelpers is not a function 2`] = ` +Object { + "userHelper": [Function], +} +`; diff --git a/src/__tests__/externalHelpers.spec.ts b/src/__tests__/externalHelpers.spec.ts index 679c9c63..82b01ed9 100644 --- a/src/__tests__/externalHelpers.spec.ts +++ b/src/__tests__/externalHelpers.spec.ts @@ -8,10 +8,7 @@ const settings = { debug: { automagic: true, }, - locations: { - buildFolder: './___ELDER___/', - srcFolder: './src/', - }, + srcDir: './src/', }; const query = {}; @@ -39,7 +36,7 @@ describe('#externalHelpers', () => { const modifiedSettings = { ...settings, debug: { automagic: false }, - locations: { ...settings.locations, buildFolder: '' }, + srcDir: '', }; expect( await externalHelpers({ @@ -49,23 +46,27 @@ describe('#externalHelpers', () => { }), ).toEqual(undefined); }); - it('works - buildHelpers', async () => { + it('returns undefined if file is not there', async () => { + jest.mock('fs', () => ({ + statSync: jest.fn().mockImplementationOnce(() => { + throw new Error(''); + }), + })); + // eslint-disable-next-line global-require + const externalHelpers = require('../externalHelpers').default; + // @ts-ignore + expect(await externalHelpers({ settings, query, helpers: [] })).toBe(undefined); + }); + it('works - userHelpers is not a function', async () => { jest.mock( - 'test/___ELDER___/helpers/index.js', - () => () => - Promise.resolve({ - userHelper: () => 'something', - }), + 'src/helpers/index.js', + () => ({ + userHelper: () => 'something', + }), { virtual: true }, ); - jest.mock('test/src/helpers/index.js', () => () => Promise.resolve({ srcHelper: jest.fn() }), { virtual: true }); jest.mock('fs', () => ({ - statSync: jest - .fn() - .mockImplementationOnce(() => { - throw new Error(''); - }) - .mockImplementationOnce(() => {}), + statSync: jest.fn().mockImplementationOnce(() => {}), })); // eslint-disable-next-line global-require const externalHelpers = require('../externalHelpers').default; @@ -75,14 +76,17 @@ describe('#externalHelpers', () => { // @ts-ignore expect(await externalHelpers({ settings, query, helpers: [] })).toMatchSnapshot(); }); - it('works - userHelpers', async () => { - jest.mock('test/___ELDER___/helpers/index.js', () => () => ({ userHelper: jest.fn() }), { virtual: true }); - jest.mock('test/src/helpers/index.js', () => () => Promise.resolve({ srcHelper: jest.fn() }), { virtual: true }); + it('works - userHelpers is a function', async () => { + jest.mock( + 'src/helpers/index.js', + () => () => + Promise.resolve({ + userHelper: () => 'something', + }), + { virtual: true }, + ); jest.mock('fs', () => ({ - statSync: jest - .fn() - .mockImplementationOnce(() => {}) - .mockImplementationOnce(() => {}), + statSync: jest.fn().mockImplementationOnce(() => {}), })); // eslint-disable-next-line global-require const externalHelpers = require('../externalHelpers').default; From 5c667a4492d6400184f9160033713af847755958 Mon Sep 17 00:00:00 2001 From: halafi Date: Thu, 17 Sep 2020 14:39:02 +0200 Subject: [PATCH 28/75] test: internal shortcodes --- src/__tests__/shortcodes.spec.ts | 69 ++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/__tests__/shortcodes.spec.ts diff --git a/src/__tests__/shortcodes.spec.ts b/src/__tests__/shortcodes.spec.ts new file mode 100644 index 00000000..d2ee5527 --- /dev/null +++ b/src/__tests__/shortcodes.spec.ts @@ -0,0 +1,69 @@ +import shortcodes from '../shortcodes'; + +describe('#shortcodes', () => { + it('contains all shortcodes we want', () => { + expect(shortcodes).toEqual([ + { + shortcode: 'svelteComponent', + run: expect.any(Function), + $$meta: { + addedBy: 'elder', + type: 'elder', + }, + }, + ]); + }); + + it('[svelteComponent] run function behaves as expected', async () => { + // throws error + await expect(() => + shortcodes[0].run({ + props: {}, + helpers: null, + }), + ).rejects.toThrow('svelteComponent shortcode requires a name="" property.'); + // parse nothing + expect( + await shortcodes[0].run({ + props: { + name: 'ParseNothing', + something: 12, + }, + helpers: { + inlineSvelteComponent: ({ name, props, options }) => + `${name}${JSON.stringify(props)}${JSON.stringify(options)}`, + }, + }), + ).toEqual({ + html: 'ParseNothing{}{}', + }); + expect( + await shortcodes[0].run({ + props: { + name: 'ParseProps', + props: '{"foo":"bar", "count":42}', + }, + helpers: { + inlineSvelteComponent: ({ name, props, options }) => + `${name}${JSON.stringify(props)}${JSON.stringify(options)}`, + }, + }), + ).toEqual({ + html: 'ParseProps{"foo":"bar","count":42}{}', + }); + expect( + await shortcodes[0].run({ + props: { + name: 'ParseOptions', + options: '{"foo":"bar", "count":37}', + }, + helpers: { + inlineSvelteComponent: ({ name, props, options }) => + `${name}${JSON.stringify(props)}${JSON.stringify(options)}`, + }, + }), + ).toEqual({ + html: 'ParseOptions{}{"foo":"bar","count":37}', + }); + }); +}); From d44c62ac4a9acf56af7506711cab186d6e1c2366 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Thu, 17 Sep 2020 09:52:59 -0400 Subject: [PATCH 29/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Add=20safe=20guard?= =?UTF-8?q?=20to=20manipuation=20within=20the=20data=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/Page.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/utils/Page.ts b/src/utils/Page.ts index a2f454f9..30aca3f5 100644 --- a/src/utils/Page.ts +++ b/src/utils/Page.ts @@ -26,8 +26,11 @@ const buildPage = async (page) => { perf: page.perf, allRequests: createReadOnlyProxy(page.allRequests, 'allRequests', `${page.request.route}: data function`), }); - if (dataResponse) { - page.data = dataResponse; + if (dataResponse && Object.keys(dataResponse).length > 0) { + page.data = { + ...page.data, + ...dataResponse, + }; } } page.perf.end('data'); From 2e76df294c6ddc66b3fa922bd9fa794cf90df3f8 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Thu, 17 Sep 2020 09:56:39 -0400 Subject: [PATCH 30/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20readonly=20proxies?= =?UTF-8?q?=20for=20request/settings=20in=20svelte?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/Page.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/utils/Page.ts b/src/utils/Page.ts index c057329f..9c16d2ba 100644 --- a/src/utils/Page.ts +++ b/src/utils/Page.ts @@ -43,26 +43,22 @@ const buildPage = async (page) => { props: { data: page.data, helpers: page.helpers, - settings: page.settings, - request: page.request, + settings: createReadOnlyProxy(page.settings, 'settings', `${page.request.route}: Svelte Template`), + request: createReadOnlyProxy(page.request, 'request', `${page.request.route}: Svelte Template`), }, }); page.perf.end('html.template'); - // shortcodes here. - await page.runHook('shortcodes', page); - // TODO: readonly proxies? page.perf.start('html.layout'); page.layoutHtml = page.route.layout({ page, props: { data: page.data, helpers: page.helpers, - settings: page.settings, - request: page.request, - routeHTML: page.routeHtml, // TODO: depreciate this + settings: createReadOnlyProxy(page.settings, 'settings', `${page.request.route}: Svelte Layout`), + request: createReadOnlyProxy(page.request, 'request', `${page.request.route}: Svelte Layout`), routeHtml: page.routeHtml, }, }); From 56684d86df1ce27fe0d4ccccc90e247536c095f4 Mon Sep 17 00:00:00 2001 From: halafi Date: Thu, 17 Sep 2020 16:10:34 +0200 Subject: [PATCH 31/75] test: prepareShortcodeParser --- .../__tests__/prepareShortcodeParser.spec.ts | 180 ++++++++++++++++++ src/utils/prepareShortcodeParser.ts | 2 +- 2 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 src/utils/__tests__/prepareShortcodeParser.spec.ts diff --git a/src/utils/__tests__/prepareShortcodeParser.spec.ts b/src/utils/__tests__/prepareShortcodeParser.spec.ts new file mode 100644 index 00000000..e21cf80f --- /dev/null +++ b/src/utils/__tests__/prepareShortcodeParser.spec.ts @@ -0,0 +1,180 @@ +import prepareShortcodeParser from '../prepareShortcodeParser'; + +class ShortcodeParser { + opts: any = {}; // just store them so we know what got passed over + + shortcodes: string[] = []; + + constructor(opts) { + this.opts = opts; + } + + add(shortcode: string, fn: (props: any, content: string) => Promise) { + fn({}, 'someContent').then(() => { + this.shortcodes.push(shortcode); + }); + } +} + +jest.mock('@elderjs/shortcodes', () => (opts) => new ShortcodeParser(opts)); +jest.mock('../createReadOnlyProxy'); + +const args = { + helpers: {}, + data: {}, + request: {}, + query: {}, + allRequests: [], + cssStack: [], + headStack: [], + customJsStack: [], +}; + +describe('#prepareShortcodeParser', () => { + it('works with empty shortcodes', () => { + const shortcodeParser = prepareShortcodeParser({ + ...args, + shortcodes: [], + settings: { + shortcodes: { + openPattern: '\\[', + closePattern: '\\]', + }, + }, + }); + expect(shortcodeParser).toBeInstanceOf(ShortcodeParser); + expect(shortcodeParser).toEqual({ + opts: { + openPattern: '\\[', + closePattern: '\\]', + }, + shortcodes: [], + }); + }); + + it('throws errors if you try to add invalid shortcodes', () => { + expect(() => + prepareShortcodeParser({ + ...args, + shortcodes: [ + { + run: jest.fn(), + foo: 'bar', + }, + ], + settings: { + shortcodes: { + openPattern: '\\<', + closePattern: '\\>', + }, + }, + }), + ).toThrow( + `Shortcodes must have a shortcode property to define their usage. Problem code: ${JSON.stringify({ + run: jest.fn(), + foo: 'bar', + })}`, + ); + expect(() => + prepareShortcodeParser({ + ...args, + shortcodes: [ + { + shortcode: 'svelteComponent', + }, + ], + settings: { + shortcodes: { + openPattern: '\\<', + closePattern: '\\>', + }, + }, + }), + ).toThrow(`Shortcodes must have a run function. Problem code: ${JSON.stringify({ shortcode: 'svelteComponent' })}`); + }); + + it('works with valid shortcode that returns html but doesnt set anything else', async () => { + const shortcodeParser = prepareShortcodeParser({ + ...args, + shortcodes: [ + { + shortcode: 'sayHi', + run: async () => ({ + html: '
    hi
    ', + }), + }, + ], + settings: { + shortcodes: { + openPattern: '\\👍', + closePattern: '\\👎', + }, + }, + }); + expect(shortcodeParser).toBeInstanceOf(ShortcodeParser); + // wait for our mock class to run the functions to ensure coverage + // CAUTION: this could turn out into non-deterministic test if the async fn doesn't finish + await new Promise((r) => setTimeout(r, 250)); + expect(shortcodeParser).toEqual({ + opts: { + openPattern: '\\👍', + closePattern: '\\👎', + }, + shortcodes: ['sayHi'], + }); + expect(args.cssStack).toEqual([]); + expect(args.headStack).toEqual([]); + expect(args.customJsStack).toEqual([]); + }); + + it('works with valid shortcode that sets css, head and js', async () => { + const shortcodeParser = prepareShortcodeParser({ + ...args, + shortcodes: [ + { + shortcode: 'svelteComponent', + run: async () => ({ + css: 'body{font-size:1rem;}', + js: 'alert("hello, I am test");', + head: '', + }), + }, + ], + settings: { + shortcodes: { + openPattern: '\\66', + closePattern: '\\33', + }, + }, + }); + expect(shortcodeParser).toBeInstanceOf(ShortcodeParser); + // wait for our mock class to run the functions to ensure coverage + // CAUTION: this could turn out into non-deterministic test if the async fn doesn't finish + await new Promise((r) => setTimeout(r, 250)); + expect(shortcodeParser).toEqual({ + opts: { + openPattern: '\\66', + closePattern: '\\33', + }, + shortcodes: ['svelteComponent'], + }); + expect(args.cssStack).toEqual([ + { + source: `svelteComponent shortcode`, + string: 'body{font-size:1rem;}', + }, + ]); + expect(args.headStack).toEqual([ + { + source: `svelteComponent shortcode`, + string: '', + }, + ]); + expect(args.customJsStack).toEqual([ + { + source: `svelteComponent shortcode`, + string: 'alert("hello, I am test");', + }, + ]); + }); +}); diff --git a/src/utils/prepareShortcodeParser.ts b/src/utils/prepareShortcodeParser.ts index d8dc3642..7957849e 100644 --- a/src/utils/prepareShortcodeParser.ts +++ b/src/utils/prepareShortcodeParser.ts @@ -26,7 +26,7 @@ function prepareShortcodeParser({ ); shortcodeParser.add(shortcode.shortcode, async (props, content) => { - // todo: plugin? + // TODO: plugin? const { html, css, js, head } = await shortcode.run({ props, content, From 2fd02ca3bc4227ba27afb2234aacabe0afcf80f9 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Thu, 17 Sep 2020 12:15:08 -0400 Subject: [PATCH 32/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20helpers.shor?= =?UTF-8?q?tcode=20to=20inline=20shortcodes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Elder.ts | 7 ++- .../__snapshots__/Elder.spec.ts.snap | 2 + .../__tests__/__snapshots__/Page.spec.ts.snap | 1 - src/utils/__tests__/index.spec.ts | 1 + src/utils/index.ts | 2 + src/utils/prepareInlineShortcode.ts | 33 ++++++++++++++ src/utils/prepareShortcodeParser.ts | 44 ++++++++++--------- 7 files changed, 68 insertions(+), 22 deletions(-) create mode 100644 src/utils/prepareInlineShortcode.ts diff --git a/src/Elder.ts b/src/Elder.ts index a71b64fa..a09ed53c 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -22,6 +22,7 @@ import { asyncForEach, getHashedSvelteComponents, getConfig, + prepareInlineShortcode, } from './utils'; import { RoutesOptions } from './routes/types'; import { HookOptions } from './hookInterface/types'; @@ -240,6 +241,7 @@ class Elder { type: 'plugin', addedBy: pluginName, }; + shortcode.plugin = sanitizedPlugin; pluginShortcodes.push(shortcode); }); } @@ -349,7 +351,9 @@ class Elder { })); } catch (err) { if (err.code === 'MODULE_NOT_FOUND') { - console.error(`Could not load hooks file from ${shortcodeSrcPath}.`); + console.error( + `Could not load shortcodes file from ${shortcodeSrcPath}. They are not required, but could be useful.`, + ); } else { console.error(err); } @@ -377,6 +381,7 @@ class Elder { this.helpers = { permalinks: permalinks({ routes: this.routes, settings: this.settings }), inlineSvelteComponent, + shortcode: prepareInlineShortcode({ settings: this.settings }), }; if (context === 'server') { diff --git a/src/__tests__/__snapshots__/Elder.spec.ts.snap b/src/__tests__/__snapshots__/Elder.spec.ts.snap index 60d374ca..1c6f8728 100644 --- a/src/__tests__/__snapshots__/Elder.spec.ts.snap +++ b/src/__tests__/__snapshots__/Elder.spec.ts.snap @@ -13,6 +13,7 @@ Elder { "test-a": [Function], "test-b": [Function], }, + "shortcode": [Function], }, "hookInterface": Array [ Object { @@ -648,6 +649,7 @@ Elder { "test-a": [Function], "test-b": [Function], }, + "shortcode": [Function], }, "hookInterface": Array [ Object { diff --git a/src/utils/__tests__/__snapshots__/Page.spec.ts.snap b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap index 90827167..cc2cd761 100644 --- a/src/utils/__tests__/__snapshots__/Page.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap @@ -443,7 +443,6 @@ Page { }, "type": "build", }, - "routeHTML": undefined, "routeHtml": undefined, "settings": Object { "$$internal": Object { diff --git a/src/utils/__tests__/index.spec.ts b/src/utils/__tests__/index.spec.ts index 669765df..4d039fdd 100644 --- a/src/utils/__tests__/index.spec.ts +++ b/src/utils/__tests__/index.spec.ts @@ -22,5 +22,6 @@ test('includes all', () => { 'prepareProcessStack', 'getConfig', 'getRollupConfig', + 'prepareInlineShortcode', ]); }); diff --git a/src/utils/index.ts b/src/utils/index.ts index 2c600e9e..03e57508 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -17,6 +17,7 @@ import { validateHook, validateRoute, validatePlugin, validateShortcode } from ' import prepareProcessStack from './prepareProcessStack'; import getConfig from './getConfig'; import getRollupConfig from './getRollupConfig'; +import prepareInlineShortcode from './prepareInlineShortcode'; export { asyncForEach, @@ -39,4 +40,5 @@ export { prepareProcessStack, getConfig, getRollupConfig, + prepareInlineShortcode, }; diff --git a/src/utils/prepareInlineShortcode.ts b/src/utils/prepareInlineShortcode.ts new file mode 100644 index 00000000..6191ce40 --- /dev/null +++ b/src/utils/prepareInlineShortcode.ts @@ -0,0 +1,33 @@ +const prepareInlineShortcode = ({ settings }) => ({ name, props = {}, content = '' }) => { + const { openPattern, closePattern } = settings.shortcodes; + if (!name) throw new Error(`helpers.shortcode requires a name prop`); + let shortcode = `${openPattern}${name}`; + + shortcode += Object.entries(props).reduce((out, [key, val]) => { + if (typeof val === 'object' || Array.isArray(val)) { + out += ` ${key}='${JSON.stringify(val)}'`; + } else { + out += ` ${key}='${val}'`; + } + + return out; + }, ''); + + if (!content) { + // self closing + shortcode += `/${closePattern}`; + } else { + // close the open shortcode. + shortcode += closePattern; + + // add content + shortcode += content; + + // close the shortcode. + shortcode += `${openPattern}/${name}${closePattern}`; + } + + return shortcode; +}; + +export default prepareInlineShortcode; diff --git a/src/utils/prepareShortcodeParser.ts b/src/utils/prepareShortcodeParser.ts index 7957849e..f553e568 100644 --- a/src/utils/prepareShortcodeParser.ts +++ b/src/utils/prepareShortcodeParser.ts @@ -26,8 +26,7 @@ function prepareShortcodeParser({ ); shortcodeParser.add(shortcode.shortcode, async (props, content) => { - // TODO: plugin? - const { html, css, js, head } = await shortcode.run({ + const shortcodeResponse = await shortcode.run({ props, content, plugin: shortcode.plugin, @@ -63,25 +62,30 @@ function prepareShortcodeParser({ ), }); - if (css) { - cssStack.push({ - source: `${shortcode.shortcode} shortcode`, - string: css, - }); + if (typeof shortcodeResponse === 'object') { + const { html, css, js, head } = shortcodeResponse; + if (css) { + cssStack.push({ + source: `${shortcode.shortcode} shortcode`, + string: css, + }); + } + if (js) { + customJsStack.push({ + source: `${shortcode.shortcode} shortcode`, + string: js, + }); + } + if (head) { + headStack.push({ + source: `${shortcode.shortcode} shortcode`, + string: head, + }); + } + return html || ''; } - if (js) { - customJsStack.push({ - source: `${shortcode.shortcode} shortcode`, - string: js, - }); - } - if (head) { - headStack.push({ - source: `${shortcode.shortcode} shortcode`, - string: head, - }); - } - return html || ''; + + return shortcodeResponse || ''; }); }); From fb6b8d6026a544b52c9f18596bb8c2a02274eecf Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Thu, 17 Sep 2020 12:18:29 -0400 Subject: [PATCH 33/75] 0.1.6-next.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 78095b56..0006610a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.2", + "version": "0.1.6-next.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e02475f1..9aee6f2e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.2", + "version": "0.1.6-next.3", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From 86652352f74a49db1ea327b3098fd46f6c045876 Mon Sep 17 00:00:00 2001 From: halafi Date: Thu, 17 Sep 2020 18:37:38 +0200 Subject: [PATCH 34/75] test: getRollupConfig sub functions --- src/utils/__tests__/getRollupConfig.spec.ts | 208 ++++++++++++++++++++ src/utils/getRollupConfig.ts | 7 +- 2 files changed, 211 insertions(+), 4 deletions(-) create mode 100644 src/utils/__tests__/getRollupConfig.spec.ts diff --git a/src/utils/__tests__/getRollupConfig.spec.ts b/src/utils/__tests__/getRollupConfig.spec.ts new file mode 100644 index 00000000..16b0f459 --- /dev/null +++ b/src/utils/__tests__/getRollupConfig.spec.ts @@ -0,0 +1,208 @@ +/* eslint-disable global-require */ +import multiInput from 'rollup-plugin-multi-input'; +import path from 'path'; +import { createBrowserConfig, createSSRConfig } from '../getRollupConfig'; + +describe('#getRollupConfig', () => { + beforeEach(() => { + jest.resetModules(); + }); + + it('createBrowserConfig works', () => { + [true, false].forEach((sourcemap) => { + expect( + createBrowserConfig({ + input: [`./components/*/*.svelte`], + output: { + dir: './public/dist/svelte/', + entryFileNames: 'entry[name]-[hash].js', + sourcemap, + format: 'system', + }, + multiInputConfig: multiInput({ + // TODO: test with false + relative: `./components`, + transformOutputPath: (output) => `${path.basename(output)}`, + }), + svelteConfig: {}, + }), + ).toEqual({ + cache: true, + input: ['./components/*/*.svelte'], + output: { + dir: './public/dist/svelte/', + entryFileNames: 'entry[name]-[hash].js', + format: 'system', + sourcemap, + }, + plugins: [ + { + options: expect.any(Function), + pluginName: 'rollup-plugin-multi-input', + }, + { + name: 'replace', + renderChunk: expect.any(Function), + transform: expect.any(Function), + }, + { + name: 'json', + transform: expect.any(Function), + }, + { + generateBundle: expect.any(Function), + load: expect.any(Function), + name: 'svelte', + resolveId: expect.any(Function), + transform: expect.any(Function), + }, + { + name: 'rollup-plugin-external-globals', + transform: expect.any(Function), + }, + { + buildStart: expect.any(Function), + generateBundle: expect.any(Function), + getPackageInfoForId: expect.any(Function), + load: expect.any(Function), + name: 'node-resolve', + resolveId: expect.any(Function), + }, + { + buildStart: expect.any(Function), + load: expect.any(Function), + name: 'commonjs', + resolveId: expect.any(Function), + transform: expect.any(Function), + }, + { + load: expect.any(Function), + name: 'babel', + resolveId: expect.any(Function), + transform: expect.any(Function), + }, + { + name: 'terser', + renderChunk: expect.any(Function), + }, + ], + treeshake: true, + }); + }); + }); + + it('createSSRConfig works', () => { + expect( + createSSRConfig({ + input: [`./components/*/*.svelte`], + output: { + dir: './___ELDER___/compiled/', + format: 'cjs', + exports: 'auto', + }, + multiInputConfig: multiInput({ + relative: `./components`, + transformOutputPath: (output) => `${path.basename(output)}`, + }), + svelteConfig: { + preprocess: [ + { + style: ({ content }) => { + return content.toUpperCase(); + }, + }, + ], + }, + }), + ).toEqual({ + cache: true, + input: ['./components/*/*.svelte'], + output: { + dir: './___ELDER___/compiled/', + exports: 'auto', + format: 'cjs', + }, + plugins: [ + { + options: expect.any(Function), + pluginName: 'rollup-plugin-multi-input', + }, + { + name: 'replace', + renderChunk: expect.any(Function), + transform: expect.any(Function), + }, + { + name: 'json', + transform: expect.any(Function), + }, + { + generateBundle: expect.any(Function), + load: expect.any(Function), + name: 'svelte', + resolveId: expect.any(Function), + transform: expect.any(Function), + }, + { + buildStart: expect.any(Function), + generateBundle: expect.any(Function), + getPackageInfoForId: expect.any(Function), + load: expect.any(Function), + name: 'node-resolve', + resolveId: expect.any(Function), + }, + { + buildStart: expect.any(Function), + load: expect.any(Function), + name: 'commonjs', + resolveId: expect.any(Function), + transform: expect.any(Function), + }, + { + generateBundle: expect.any(Function), + name: 'css', + transform: expect.any(Function), + }, + { + name: 'terser', + renderChunk: expect.any(Function), + }, + ], + treeshake: true, + }); + }); + + it('getPluginPaths works', () => { + jest.mock('glob', () => ({ + sync: jest + .fn() + .mockImplementationOnce(() => ['a-file1.svelte', 'a-file2.svelte']) + .mockImplementationOnce(() => ['b-file1.svelte', 'b-file2.svelte']), + })); + + jest.mock('path', () => ({ + resolve: (...strings) => strings.join('/').replace('./', '').replace('//', '/').replace('/./', '/'), + posix: () => ({ dirname: () => '' }), + })); + + jest.mock('fs-extra', () => ({ + existsSync: jest + .fn() + .mockImplementationOnce(() => true) // first plugin from src + .mockImplementationOnce(() => false) // 2nd from node modules + .mockImplementationOnce(() => true), + })); + + expect( + // @ts-ignore + require('../getRollupConfig').getPluginPaths({ + srcDir: './src', + rootDir: './', + plugins: { + pluginA: {}, + pluginB: {}, + }, + }), + ).toEqual(['src/plugins/pluginA/', '/node_modules/pluginB/']); + }); +}); diff --git a/src/utils/getRollupConfig.ts b/src/utils/getRollupConfig.ts index 5d510eb7..50324406 100644 --- a/src/utils/getRollupConfig.ts +++ b/src/utils/getRollupConfig.ts @@ -19,7 +19,7 @@ import { ConfigOptions } from './types'; const production = process.env.NODE_ENV === 'production' || !process.env.ROLLUP_WATCH; -function createBrowserConfig({ input, output, multiInputConfig = false, svelteConfig }) { +export function createBrowserConfig({ input, output, multiInputConfig = false, svelteConfig }) { const config = { cache: true, treeshake: true, @@ -68,7 +68,7 @@ function createBrowserConfig({ input, output, multiInputConfig = false, svelteCo return config; } -function createSSRConfig({ input, output, svelteConfig, multiInputConfig = false }) { +export function createSSRConfig({ input, output, svelteConfig, multiInputConfig = false }) { const config = { cache: true, treeshake: true, @@ -109,7 +109,7 @@ function createSSRConfig({ input, output, svelteConfig, multiInputConfig = false return config; } -function getPluginPaths(elderConfig: ConfigOptions) { +export function getPluginPaths(elderConfig: ConfigOptions) { const pluginNames = Object.keys(elderConfig.plugins); return pluginNames.reduce((out, pluginName) => { @@ -117,7 +117,6 @@ function getPluginPaths(elderConfig: ConfigOptions) { const nmPluginPath = path.resolve(elderConfig.rootDir, `./node_modules/${pluginName}`); if (fs.existsSync(`${pluginPath}/index.js`)) { const svelteFiles = glob.sync(`${pluginPath}/*.svelte`); - console.log(`${pluginPath}/*.svelte`, svelteFiles); if (svelteFiles.length > 0) { out.push(`${pluginPath}/`); } From 46afc955ee86ce5d2950f3b36ede6db8010be187 Mon Sep 17 00:00:00 2001 From: halafi Date: Thu, 17 Sep 2020 18:45:41 +0200 Subject: [PATCH 35/75] test: getRollupConfig cases --- src/utils/__tests__/getRollupConfig.spec.ts | 124 ++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/src/utils/__tests__/getRollupConfig.spec.ts b/src/utils/__tests__/getRollupConfig.spec.ts index 16b0f459..94198363 100644 --- a/src/utils/__tests__/getRollupConfig.spec.ts +++ b/src/utils/__tests__/getRollupConfig.spec.ts @@ -91,6 +91,67 @@ describe('#getRollupConfig', () => { }); }); + it('createBrowserConfig multiInputConfig = false', () => { + expect( + createBrowserConfig({ + input: [`./components/*/*.svelte`], + output: { + dir: './public/dist/svelte/', + entryFileNames: 'entry[name]-[hash].js', + sourcemap: true, + format: 'system', + }, + svelteConfig: {}, + }).plugins, + ).toEqual([ + { + name: 'replace', + renderChunk: expect.any(Function), + transform: expect.any(Function), + }, + { + name: 'json', + transform: expect.any(Function), + }, + { + generateBundle: expect.any(Function), + load: expect.any(Function), + name: 'svelte', + resolveId: expect.any(Function), + transform: expect.any(Function), + }, + { + name: 'rollup-plugin-external-globals', + transform: expect.any(Function), + }, + { + buildStart: expect.any(Function), + generateBundle: expect.any(Function), + getPackageInfoForId: expect.any(Function), + load: expect.any(Function), + name: 'node-resolve', + resolveId: expect.any(Function), + }, + { + buildStart: expect.any(Function), + load: expect.any(Function), + name: 'commonjs', + resolveId: expect.any(Function), + transform: expect.any(Function), + }, + { + load: expect.any(Function), + name: 'babel', + resolveId: expect.any(Function), + transform: expect.any(Function), + }, + { + name: 'terser', + renderChunk: expect.any(Function), + }, + ]); + }); + it('createSSRConfig works', () => { expect( createSSRConfig({ @@ -172,6 +233,69 @@ describe('#getRollupConfig', () => { }); }); + it('createSSRConfig multiInputConfig = false', () => { + expect( + createSSRConfig({ + input: [`./components/*/*.svelte`], + output: { + dir: './___ELDER___/compiled/', + format: 'cjs', + exports: 'auto', + }, + svelteConfig: { + preprocess: [ + { + style: ({ content }) => { + return content.toUpperCase(); + }, + }, + ], + }, + }).plugins, + ).toEqual([ + { + name: 'replace', + renderChunk: expect.any(Function), + transform: expect.any(Function), + }, + { + name: 'json', + transform: expect.any(Function), + }, + { + generateBundle: expect.any(Function), + load: expect.any(Function), + name: 'svelte', + resolveId: expect.any(Function), + transform: expect.any(Function), + }, + { + buildStart: expect.any(Function), + generateBundle: expect.any(Function), + getPackageInfoForId: expect.any(Function), + load: expect.any(Function), + name: 'node-resolve', + resolveId: expect.any(Function), + }, + { + buildStart: expect.any(Function), + load: expect.any(Function), + name: 'commonjs', + resolveId: expect.any(Function), + transform: expect.any(Function), + }, + { + generateBundle: expect.any(Function), + name: 'css', + transform: expect.any(Function), + }, + { + name: 'terser', + renderChunk: expect.any(Function), + }, + ]); + }); + it('getPluginPaths works', () => { jest.mock('glob', () => ({ sync: jest From b30a397aa4242494784a164df01beafead4bc409 Mon Sep 17 00:00:00 2001 From: halafi Date: Thu, 17 Sep 2020 19:03:59 +0200 Subject: [PATCH 36/75] test: getRollupConfig --- .../getRollupConfig.spec.ts.snap | 612 ++++++++++++++++++ src/utils/__tests__/getRollupConfig.spec.ts | 44 ++ 2 files changed, 656 insertions(+) create mode 100644 src/utils/__tests__/__snapshots__/getRollupConfig.spec.ts.snap diff --git a/src/utils/__tests__/__snapshots__/getRollupConfig.spec.ts.snap b/src/utils/__tests__/__snapshots__/getRollupConfig.spec.ts.snap new file mode 100644 index 00000000..f9a690a3 --- /dev/null +++ b/src/utils/__tests__/__snapshots__/getRollupConfig.spec.ts.snap @@ -0,0 +1,612 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`#getRollupConfig getRollupConfig as a whole works 1`] = ` +Array [ + Object { + "input": "./node_modules/intersection-observer/intersection-observer.js", + "output": Array [ + Object { + "file": "dist/static/intersection-observer.js", + "format": "iife", + "name": "./static/intersection-observer.js", + "plugins": Array [ + Object { + "name": "terser", + "renderChunk": [Function], + }, + ], + }, + ], + }, + Object { + "input": "./node_modules/systemjs/dist/s.min.js", + "output": Array [ + Object { + "file": "dist/static/s.min.js", + "format": "iife", + "name": "./static/s.min.js", + "plugins": Array [ + Object { + "name": "terser", + "renderChunk": [Function], + }, + ], + }, + ], + }, + Object { + "cache": true, + "input": "route1.svelte", + "output": Object { + "dir": "test/___ELDER___/compiled", + "exports": "auto", + "format": "cjs", + }, + "plugins": Array [ + Object { + "name": "replace", + "renderChunk": [Function], + "transform": [Function], + }, + Object { + "name": "json", + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "load": [Function], + "name": "svelte", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "buildStart": [Function], + "generateBundle": [Function], + "getPackageInfoForId": [Function], + "load": [Function], + "name": "node-resolve", + "resolveId": [Function], + }, + Object { + "buildStart": [Function], + "load": [Function], + "name": "commonjs", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "name": "css", + "transform": [Function], + }, + Object { + "name": "terser", + "renderChunk": [Function], + }, + ], + "treeshake": true, + }, + Object { + "cache": true, + "input": "route2.svelte", + "output": Object { + "dir": "test/___ELDER___/compiled", + "exports": "auto", + "format": "cjs", + }, + "plugins": Array [ + Object { + "name": "replace", + "renderChunk": [Function], + "transform": [Function], + }, + Object { + "name": "json", + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "load": [Function], + "name": "svelte", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "buildStart": [Function], + "generateBundle": [Function], + "getPackageInfoForId": [Function], + "load": [Function], + "name": "node-resolve", + "resolveId": [Function], + }, + Object { + "buildStart": [Function], + "load": [Function], + "name": "commonjs", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "name": "css", + "transform": [Function], + }, + Object { + "name": "terser", + "renderChunk": [Function], + }, + ], + "treeshake": true, + }, + Object { + "cache": true, + "input": "layout1.svelte", + "output": Object { + "dir": "test/___ELDER___/compiled", + "exports": "auto", + "format": "cjs", + }, + "plugins": Array [ + Object { + "name": "replace", + "renderChunk": [Function], + "transform": [Function], + }, + Object { + "name": "json", + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "load": [Function], + "name": "svelte", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "buildStart": [Function], + "generateBundle": [Function], + "getPackageInfoForId": [Function], + "load": [Function], + "name": "node-resolve", + "resolveId": [Function], + }, + Object { + "buildStart": [Function], + "load": [Function], + "name": "commonjs", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "name": "css", + "transform": [Function], + }, + Object { + "name": "terser", + "renderChunk": [Function], + }, + ], + "treeshake": true, + }, + Object { + "cache": true, + "input": "layout2.svelte", + "output": Object { + "dir": "test/___ELDER___/compiled", + "exports": "auto", + "format": "cjs", + }, + "plugins": Array [ + Object { + "name": "replace", + "renderChunk": [Function], + "transform": [Function], + }, + Object { + "name": "json", + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "load": [Function], + "name": "svelte", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "buildStart": [Function], + "generateBundle": [Function], + "getPackageInfoForId": [Function], + "load": [Function], + "name": "node-resolve", + "resolveId": [Function], + }, + Object { + "buildStart": [Function], + "load": [Function], + "name": "commonjs", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "name": "css", + "transform": [Function], + }, + Object { + "name": "terser", + "renderChunk": [Function], + }, + ], + "treeshake": true, + }, + Object { + "cache": true, + "input": Array [ + "rc/components/*/*.svelte", + ], + "output": Object { + "dir": "test/public/svelte", + "entryFileNames": "entry[name]-[hash].js", + "format": "system", + "sourcemap": false, + }, + "plugins": Array [ + Object { + "options": [Function], + "pluginName": "rollup-plugin-multi-input", + }, + Object { + "name": "replace", + "renderChunk": [Function], + "transform": [Function], + }, + Object { + "name": "json", + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "load": [Function], + "name": "svelte", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "name": "rollup-plugin-external-globals", + "transform": [Function], + }, + Object { + "buildStart": [Function], + "generateBundle": [Function], + "getPackageInfoForId": [Function], + "load": [Function], + "name": "node-resolve", + "resolveId": [Function], + }, + Object { + "buildStart": [Function], + "load": [Function], + "name": "commonjs", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "load": [Function], + "name": "babel", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "name": "terser", + "renderChunk": [Function], + }, + ], + "treeshake": true, + }, + Object { + "cache": true, + "input": Array [ + "rc/components/*/*.svelte", + ], + "output": Object { + "dir": "test/___ELDER___/compiled", + "exports": "auto", + "format": "cjs", + }, + "plugins": Array [ + Object { + "options": [Function], + "pluginName": "rollup-plugin-multi-input", + }, + Object { + "name": "replace", + "renderChunk": [Function], + "transform": [Function], + }, + Object { + "name": "json", + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "load": [Function], + "name": "svelte", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "buildStart": [Function], + "generateBundle": [Function], + "getPackageInfoForId": [Function], + "load": [Function], + "name": "node-resolve", + "resolveId": [Function], + }, + Object { + "buildStart": [Function], + "load": [Function], + "name": "commonjs", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "name": "css", + "transform": [Function], + }, + Object { + "name": "terser", + "renderChunk": [Function], + }, + ], + "treeshake": true, + }, + Object { + "cache": true, + "input": Array [ + "src/plugins/pluginA/*.svelte", + ], + "output": Object { + "dir": "test/public/svelte", + "entryFileNames": "entry[name]-[hash].js", + "format": "system", + "sourcemap": false, + }, + "plugins": Array [ + Object { + "options": [Function], + "pluginName": "rollup-plugin-multi-input", + }, + Object { + "name": "replace", + "renderChunk": [Function], + "transform": [Function], + }, + Object { + "name": "json", + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "load": [Function], + "name": "svelte", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "name": "rollup-plugin-external-globals", + "transform": [Function], + }, + Object { + "buildStart": [Function], + "generateBundle": [Function], + "getPackageInfoForId": [Function], + "load": [Function], + "name": "node-resolve", + "resolveId": [Function], + }, + Object { + "buildStart": [Function], + "load": [Function], + "name": "commonjs", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "load": [Function], + "name": "babel", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "name": "terser", + "renderChunk": [Function], + }, + ], + "treeshake": true, + }, + Object { + "cache": true, + "input": Array [ + "src/plugins/pluginA/*.svelte", + ], + "output": Object { + "dir": "test/___ELDER___/compiled", + "exports": "auto", + "format": "cjs", + }, + "plugins": Array [ + Object { + "options": [Function], + "pluginName": "rollup-plugin-multi-input", + }, + Object { + "name": "replace", + "renderChunk": [Function], + "transform": [Function], + }, + Object { + "name": "json", + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "load": [Function], + "name": "svelte", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "buildStart": [Function], + "generateBundle": [Function], + "getPackageInfoForId": [Function], + "load": [Function], + "name": "node-resolve", + "resolveId": [Function], + }, + Object { + "buildStart": [Function], + "load": [Function], + "name": "commonjs", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "name": "css", + "transform": [Function], + }, + Object { + "name": "terser", + "renderChunk": [Function], + }, + ], + "treeshake": true, + }, + Object { + "cache": true, + "input": Array [ + "src/plugins/pluginB/*.svelte", + ], + "output": Object { + "dir": "test/public/svelte", + "entryFileNames": "entry[name]-[hash].js", + "format": "system", + "sourcemap": false, + }, + "plugins": Array [ + Object { + "options": [Function], + "pluginName": "rollup-plugin-multi-input", + }, + Object { + "name": "replace", + "renderChunk": [Function], + "transform": [Function], + }, + Object { + "name": "json", + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "load": [Function], + "name": "svelte", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "name": "rollup-plugin-external-globals", + "transform": [Function], + }, + Object { + "buildStart": [Function], + "generateBundle": [Function], + "getPackageInfoForId": [Function], + "load": [Function], + "name": "node-resolve", + "resolveId": [Function], + }, + Object { + "buildStart": [Function], + "load": [Function], + "name": "commonjs", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "load": [Function], + "name": "babel", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "name": "terser", + "renderChunk": [Function], + }, + ], + "treeshake": true, + }, + Object { + "cache": true, + "input": Array [ + "src/plugins/pluginB/*.svelte", + ], + "output": Object { + "dir": "test/___ELDER___/compiled", + "exports": "auto", + "format": "cjs", + }, + "plugins": Array [ + Object { + "options": [Function], + "pluginName": "rollup-plugin-multi-input", + }, + Object { + "name": "replace", + "renderChunk": [Function], + "transform": [Function], + }, + Object { + "name": "json", + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "load": [Function], + "name": "svelte", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "buildStart": [Function], + "generateBundle": [Function], + "getPackageInfoForId": [Function], + "load": [Function], + "name": "node-resolve", + "resolveId": [Function], + }, + Object { + "buildStart": [Function], + "load": [Function], + "name": "commonjs", + "resolveId": [Function], + "transform": [Function], + }, + Object { + "generateBundle": [Function], + "name": "css", + "transform": [Function], + }, + Object { + "name": "terser", + "renderChunk": [Function], + }, + ], + "treeshake": true, + }, +] +`; diff --git a/src/utils/__tests__/getRollupConfig.spec.ts b/src/utils/__tests__/getRollupConfig.spec.ts index 94198363..12b71cc6 100644 --- a/src/utils/__tests__/getRollupConfig.spec.ts +++ b/src/utils/__tests__/getRollupConfig.spec.ts @@ -329,4 +329,48 @@ describe('#getRollupConfig', () => { }), ).toEqual(['src/plugins/pluginA/', '/node_modules/pluginB/']); }); + + it('getRollupConfig as a whole works', () => { + jest.mock('../getConfig', () => () => ({ + $$internal: { + clientComponents: 'test/public/svelte', + ssrComponents: 'test/___ELDER___/compiled', + }, + distDir: './dist', + srcDir: './src', + rootDir: './', + plugins: { + pluginA: {}, + pluginB: {}, + }, + })); + + jest.mock('path', () => ({ + resolve: (...strings) => strings.join('/').replace('./', '').replace('//', '/').replace('/./', '/'), + posix: () => ({ dirname: () => '' }), + })); + jest.mock('del'); + jest.mock('fs-extra', () => ({ + existsSync: jest.fn().mockImplementation(() => true), + })); + jest.mock('glob', () => ({ + sync: jest + .fn() + .mockImplementationOnce(() => ['route1.svelte', 'route2.svelte']) + .mockImplementationOnce(() => ['layout1.svelte', 'layout2.svelte']) + .mockImplementationOnce(() => ['pluginA.svelte', 'pluginB.svelte']) + .mockImplementationOnce(() => ['foo.svelte', 'bar.svelte']), + })); + + const svelteConfig = { + preprocess: [ + { + style: ({ content }) => { + return content.toUpperCase(); + }, + }, + ], + }; + expect(require('../getRollupConfig').default({ svelteConfig })).toMatchSnapshot(); + }); }); From 1b09ad0098f0be9d3759e2b85015006d59d8f770 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Thu, 17 Sep 2020 13:09:38 -0400 Subject: [PATCH 37/75] =?UTF-8?q?chore:=20=F0=9F=A4=96=20remove=20stray=20?= =?UTF-8?q?console=20log?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/getRollupConfig.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils/getRollupConfig.ts b/src/utils/getRollupConfig.ts index 5d510eb7..dae5510d 100644 --- a/src/utils/getRollupConfig.ts +++ b/src/utils/getRollupConfig.ts @@ -117,7 +117,6 @@ function getPluginPaths(elderConfig: ConfigOptions) { const nmPluginPath = path.resolve(elderConfig.rootDir, `./node_modules/${pluginName}`); if (fs.existsSync(`${pluginPath}/index.js`)) { const svelteFiles = glob.sync(`${pluginPath}/*.svelte`); - console.log(`${pluginPath}/*.svelte`, svelteFiles); if (svelteFiles.length > 0) { out.push(`${pluginPath}/`); } From 52630ad2b46eca2fc24a868e4a3ad568b4793d0e Mon Sep 17 00:00:00 2001 From: halafi Date: Thu, 17 Sep 2020 19:13:29 +0200 Subject: [PATCH 38/75] test: prepareInlineShortcode --- .../__tests__/prepareInlineShortcode.spec.ts | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/utils/__tests__/prepareInlineShortcode.spec.ts diff --git a/src/utils/__tests__/prepareInlineShortcode.spec.ts b/src/utils/__tests__/prepareInlineShortcode.spec.ts new file mode 100644 index 00000000..a6733f23 --- /dev/null +++ b/src/utils/__tests__/prepareInlineShortcode.spec.ts @@ -0,0 +1,45 @@ +import prepareInlineShortcode from '../prepareInlineShortcode'; + +describe('#prepareInlineShortcode', () => { + it('works - no content, no props', () => { + const settings = { + shortcodes: { + openPattern: '<12345', + closePattern: '54321>', + }, + }; + const fn = prepareInlineShortcode({ settings }); + // @ts-ignore + expect(() => fn({})).toThrow('helpers.shortcode requires a name prop'); + expect( + fn({ + name: 'Test', + props: {}, + content: '', + }), + ).toEqual('<12345Test/54321>'); + }); + + it('works - with content and props', () => { + const settings = { + shortcodes: { + openPattern: '<', + closePattern: '>', + }, + }; + const fn = prepareInlineShortcode({ settings }); + expect( + fn({ + name: 'Test', + props: { + foo: 'bar', + answer: 42, + nested: { + prop: 'porp', + }, + }, + content: '
    Hi, I am content
    ', + }), + ).toEqual("
    Hi, I am content
    "); + }); +}); From 4b2341b42237e11836021aacf62eb82eccfee3aa Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Thu, 17 Sep 2020 14:53:15 -0400 Subject: [PATCH 39/75] =?UTF-8?q?fix:=20=F0=9F=90=9B=20use=20devalue=20ins?= =?UTF-8?q?tead=20of=20JSON.stringify=20for=20props?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 5 +++++ package.json | 17 +++++++++-------- src/utils/__tests__/svelteComponent.spec.ts | 2 +- src/utils/svelteComponent.ts | 3 ++- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0006610a..4f0a7dee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2922,6 +2922,11 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, + "devalue": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-2.0.1.tgz", + "integrity": "sha512-I2TiqT5iWBEyB8GRfTDP0hiLZ0YeDJZ+upDxjBfOC2lebO5LezQMv7QvIUTzdb64jQyAKLf1AHADtGN+jw6v8Q==" + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", diff --git a/package.json b/package.json index 9aee6f2e..f0d00656 100644 --- a/package.json +++ b/package.json @@ -26,15 +26,20 @@ "systemjs": "^6.5.0" }, "dependencies": { + "@elderjs/shortcodes": "^1.0.6", + "@rollup/plugin-commonjs": "^14.0.0", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^8.4.0", + "@rollup/plugin-replace": "^2.3.3", "cli-progress": "^3.8.2", "cosmiconfig": "^7.0.0", + "del": "^5.1.0", + "devalue": "^2.0.1", "fs-extra": "^9.0.1", "glob": "^7.1.6", "lodash.defaultsdeep": "^4.6.1", - "@elderjs/shortcodes": "^1.0.6", "nanoid": "^3.1.12", - "yup": "^0.29.3", - "del": "^5.1.0", + "rollup": "^2.21.0", "rollup-plugin-babel": "^4.4.0", "rollup-plugin-css-only": "^2.1.0", "rollup-plugin-delete": "^2.0.0", @@ -42,12 +47,8 @@ "rollup-plugin-multi-input": "^1.1.1", "rollup-plugin-svelte": "^6.0.1", "rollup-plugin-terser": "^6.1.0", - "@rollup/plugin-commonjs": "^14.0.0", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^8.4.0", - "@rollup/plugin-replace": "^2.3.3", "svelte": "^3.25.1", - "rollup": "^2.21.0" + "yup": "^0.29.3" }, "devDependencies": { "@types/fs-extra": "^9.0.1", diff --git a/src/utils/__tests__/svelteComponent.spec.ts b/src/utils/__tests__/svelteComponent.spec.ts index 9ac0fa32..4d1e2ca6 100644 --- a/src/utils/__tests__/svelteComponent.spec.ts +++ b/src/utils/__tests__/svelteComponent.spec.ts @@ -111,7 +111,7 @@ describe('#svelteComponent', () => { function initdatepickerSwrzsrVDCd() { System.import('/svelte/Datepicker.a1b2c3.js').then(({ default: App }) => { - new App({ target: document.getElementById('datepicker-SwrzsrVDCd'), hydrate: true, props: {"a":"b"} }); + new App({ target: document.getElementById('datepicker-SwrzsrVDCd'), hydrate: true, props: {a:"b"} }); }); } diff --git a/src/utils/svelteComponent.ts b/src/utils/svelteComponent.ts index 2de034d3..d8f99ae4 100644 --- a/src/utils/svelteComponent.ts +++ b/src/utils/svelteComponent.ts @@ -1,4 +1,5 @@ import path from 'path'; +import devalue from 'devalue'; import getUniqueId from './getUniqueId'; import IntersectionObserver from './IntersectionObserver'; import { ComponentPayload } from './types'; @@ -107,7 +108,7 @@ const svelteComponent = (componentName) => ({ page, props, hydrateOptions }: Com const clientJs = ` System.import('${clientSrc}').then(({ default: App }) => { - new App({ target: document.getElementById('${cleanComponentName.toLowerCase()}-${id}'), hydrate: true, props: ${JSON.stringify( + new App({ target: document.getElementById('${cleanComponentName.toLowerCase()}-${id}'), hydrate: true, props: ${devalue( props, )} }); });`; From aec0830be056eee98f7db06eb6c940ee78a1b186 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Thu, 17 Sep 2020 14:53:33 -0400 Subject: [PATCH 40/75] 0.1.6-next.4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4f0a7dee..a200e103 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.3", + "version": "0.1.6-next.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f0d00656..37827da1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.3", + "version": "0.1.6-next.4", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From 20233fa92d88334eb7ea4518f6c3a3b344aa9f36 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Fri, 18 Sep 2020 10:58:33 -0400 Subject: [PATCH 41/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20Much=20better=20er?= =?UTF-8?q?ror=20handling=20and=20reporting=20for=20builds?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/build/build.ts | 51 +++++++++++++++++++++++-------------- src/hooks.ts | 19 ++++++++++---- src/utils/Page.ts | 9 ++----- src/utils/prepareRunHook.ts | 37 +++++++++++++++------------ src/workerBuild.ts | 12 +++++---- 5 files changed, 76 insertions(+), 52 deletions(-) diff --git a/src/build/build.ts b/src/build/build.ts index 4e5789c9..3427826b 100644 --- a/src/build/build.ts +++ b/src/build/build.ts @@ -119,8 +119,9 @@ async function build(): Promise { counts[workerId].count = msg[1]; // eslint-disable-next-line prefer-destructuring counts[workerId].errCount = msg[2]; - if (msg[4]) { - errors.push(msg[4]); + if (msg[3]) { + msg[3].errors = msg[3].errors.map((jsonErr) => JSON.parse(jsonErr)); + errors.push(msg[3]); } if (totalRequests === requestsProcessed) { markWorkersComplete({ errors, timings }); @@ -210,29 +211,31 @@ async function build(): Promise { singlebar.stop(); } - // eslint-disable-next-line no-restricted-syntax - for (const id in cluster.workers) { - if (Object.prototype.hasOwnProperty.call(cluster.workers, id)) { - cluster.workers[id].kill(); - } + let success = true; + + mElder.errors = [...mElder.errors, ...errors]; + if (mElder.errors.length > 0) { + success = false; } const time = Date.now() - start; if (time > 60000) { - console.log(`Build completed ${totalRequests} pages in ${Math.round((time / 60000) * 100) / 100} minutes`); + console.log( + `Build ${success ? 'Completed Successfully:' : 'Failed:'} Built ${totalRequests} pages in ${ + Math.round((time / 60000) * 100) / 100 + } minutes`, + ); } else if (time > 1000) { - console.log(`Build completed ${totalRequests} pages in ${Math.round((time / 1000) * 100) / 100} seconds`); + console.log( + `Build ${success ? 'Completed Successfully:' : 'Failed:'} Built ${totalRequests} pages in ${ + Math.round((time / 1000) * 100) / 100 + } seconds`, + ); } else { - console.log(`Build completed ${totalRequests} pages in ${time}ms`); - } - - let success = true; - - mElder.errors = [...mElder.errors, ...errors]; - if (mElder.errors.length > 0) { - await mElder.runHook('error', mElder); - success = false; + console.log( + `Build ${success ? 'Completed Successfully:' : 'Failed:'} Built ${totalRequests} pages in ${time}ms`, + ); } await mElder.runHook('buildComplete', { success, ...mElder, timings }); @@ -240,6 +243,16 @@ async function build(): Promise { if (settings.debug.build) { console.log('Build complete. Workers:', cluster.workers); } + if (!success) { + throw new Error(`Build did not complete successfully.`); + } + + // eslint-disable-next-line no-restricted-syntax + for (const id in cluster.workers) { + if (Object.prototype.hasOwnProperty.call(cluster.workers, id)) { + cluster.workers[id].kill(); + } + } } else { process.on('message', async (msg) => { if (msg.cmd === 'start') { @@ -252,7 +265,7 @@ async function build(): Promise { }); } } catch (e) { - console.log(e); + process.exit(1); } } export default build; diff --git a/src/hooks.ts b/src/hooks.ts index de9fa1b3..9f1be598 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -175,8 +175,10 @@ const hooks: Array = [ name: 'elderConsoleLogErrors', description: 'Log any errors to the console.', priority: 1, - run: async ({ errors, request }) => { - console.error(request.permalink, errors); + run: async ({ errors, request, settings }) => { + if (!settings.worker) { + console.error(request.permalink, errors); + } }, }, { @@ -235,9 +237,16 @@ const hooks: Array = [ priority: 50, run: async ({ errors, settings }) => { if (errors && errors.length > 0) { - const buildOutputLocation = path.resolve(settings.rootDir, `./___ELDER___/build-${Date.now()}.json`); - console.log(`Writing details on the ${errors.length} build errors to: ${buildOutputLocation}`); - fs.writeJSONSync(buildOutputLocation, { errors, settings }); + const buildOutputLocation = path.resolve(settings.rootDir, `./___ELDER___/build-errors-${Date.now()}.json`); + console.log( + `Errors during Elder.js build. Writing details on the ${errors.length} build errors to: ${buildOutputLocation}`, + ); + fs.writeJSONSync(buildOutputLocation, { settings, buildErrors: errors }); + + errors.forEach((error) => { + console.error(error); + console.error(`------`); + }); } }, }, diff --git a/src/utils/Page.ts b/src/utils/Page.ts index 9c16d2ba..9845f373 100644 --- a/src/utils/Page.ts +++ b/src/utils/Page.ts @@ -176,7 +176,6 @@ class Page { this.routes = routes; this.cssString = ''; this.htmlString = ''; - this.headStack = []; this.cssStack = []; this.beforeHydrateStack = []; @@ -186,23 +185,19 @@ class Page { this.shortcodes = shortcodes; this.processStack = prepareProcessStack(this); - this.perf.end('constructor'); - this.perf.start('initToBuildGap'); } build() { - return buildPage(this); + return buildPage(this).then((page) => page); } html() { if (this.htmlString) { return this.htmlString; } - return buildPage(this) - .then((page) => page.htmlString) - .catch(JSON.stringify); + return buildPage(this).then((page) => page.htmlString); } } diff --git a/src/utils/prepareRunHook.ts b/src/utils/prepareRunHook.ts index 9deda87b..3263d521 100644 --- a/src/utils/prepareRunHook.ts +++ b/src/utils/prepareRunHook.ts @@ -42,25 +42,30 @@ function prepareRunHook({ hooks, allSupportedHooks, settings }) { await hookList.reduce((p, hook) => { return p.then(async () => { if (props.perf) props.perf.start(`hook.${hookName}.${hook.name}`); - let hookResponse = await hook.run(hookProps); + try { + let hookResponse = await hook.run(hookProps); - if (!hookResponse) hookResponse = {}; + if (!hookResponse) hookResponse = {}; - if (settings && settings.debug && settings.debug.hooks) { - console.log(`${hook.name} ran on ${hookName} and returned`, hookResponse); - } - - Object.keys(hookResponse).forEach((key) => { - if (hookDefinition.mutable && hookDefinition.mutable.includes(key)) { - hookOutput[key] = hookResponse[key]; - hookProps[key] = hookResponse[key]; - } else { - console.error( - `Received attempted mutation on "${hookName}" from "${hook.name}" on the object "${key}". ${key} is not mutable on this hook `, - hook.$$meta, - ); + if (settings && settings.debug && settings.debug.hooks) { + console.log(`${hook.name} ran on ${hookName} and returned`, hookResponse); } - }); + + Object.keys(hookResponse).forEach((key) => { + if (hookDefinition.mutable && hookDefinition.mutable.includes(key)) { + hookOutput[key] = hookResponse[key]; + hookProps[key] = hookResponse[key]; + } else { + console.error( + `Received attempted mutation on "${hookName}" from "${hook.name}" on the object "${key}". ${key} is not mutable on this hook `, + hook.$$meta, + ); + } + }); + } catch (e) { + e.message = `Hook: "${hook.name}" threw an error: ${e.message}`; + props.errors.push(e); + } if (props.perf) props.perf.end(`hook.${hookName}.${hook.name}`); }); }, Promise.resolve()); diff --git a/src/workerBuild.ts b/src/workerBuild.ts index faeb41bc..fba43609 100644 --- a/src/workerBuild.ts +++ b/src/workerBuild.ts @@ -39,25 +39,27 @@ async function workerBuild({ bootstrapComplete, workerRequests }) { errors, shortcodes, }); - const { errors: buildErrors, timings } = await page.build(); i += 1; + const response: any = ['requestComplete', i]; + + // try { + const { errors: buildErrors, timings } = await page.build(); bTimes.push(timings); - const response: any = ['requestComplete', i]; if (buildErrors && buildErrors.length > 0) { errs += 1; response.push(errs); - response.push({ request, errors: buildErrors }); - bErrors.push({ request, errors: buildErrors }); + response.push({ request, errors: buildErrors.map((e) => JSON.stringify(e, Object.getOwnPropertyNames(e))) }); } else { response.push(errs); } + // } catch (e) {} if (process.send) { process.send(response); } }); - return { timings: bTimes, errors: bErrors }; + return { timings: bTimes }; } export default workerBuild; From 6737fb2b5eb64bfc4dff0320f8f7181d49178afb Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Fri, 18 Sep 2020 11:36:28 -0400 Subject: [PATCH 42/75] =?UTF-8?q?test:=20=F0=9F=92=8D=20get=20tests=20almo?= =?UTF-8?q?st=20working?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/__tests__/hooks.spec.ts | 4 +++- src/build/__tests__/build.spec.ts | 6 ++++-- src/build/build.ts | 19 +++++++++++-------- src/utils/__tests__/Page.spec.ts | 13 ------------- src/utils/__tests__/prepareRunHook.spec.ts | 4 +++- src/workerBuild.ts | 3 ++- 6 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/__tests__/hooks.spec.ts b/src/__tests__/hooks.spec.ts index 6c2db377..a4e085a7 100644 --- a/src/__tests__/hooks.spec.ts +++ b/src/__tests__/hooks.spec.ts @@ -69,7 +69,9 @@ describe('#hooks', () => { it('elderConsoleLogErrors', async () => { const hook = hooks.find((h) => h.name === 'elderConsoleLogErrors'); - expect(await hook.run({ request: { permalink: '/foo' }, errors: ['foo', 'bar'] })).toBe(undefined); + expect( + await hook.run({ settings: { worker: false }, request: { permalink: '/foo' }, errors: ['foo', 'bar'] }), + ).toBe(undefined); }); it('elderWriteHtmlFileToPublic', async () => { const hook = hooks.find((h) => h.name === 'elderWriteHtmlFileToPublic'); diff --git a/src/build/__tests__/build.spec.ts b/src/build/__tests__/build.spec.ts index ae717966..309f5c17 100644 --- a/src/build/__tests__/build.spec.ts +++ b/src/build/__tests__/build.spec.ts @@ -142,6 +142,7 @@ describe('#build', () => { sent.push(i); return true; }, + exit: () => '' as never, }; // eslint-disable-next-line global-require @@ -258,11 +259,12 @@ describe('#build', () => { // eslint-disable-next-line global-require const build = require('../build').default; await build(); - jest.advanceTimersByTime(1000); // not all intervalls are cleared + jest.advanceTimersByTime(5000); // not all intervalls are cleared + // eslint-disable-next-line global-require expect(require('cluster').workers.map((w) => w.killed)).toEqual([true, true]); + expect(calledHooks).toEqual([ - 'error-{"errors":["bornToFail","pushMeToErrors"]}', 'buildComplete-{"success":false,"errors":["bornToFail","pushMeToErrors"],"timings":[null,null]}', ]); expect(setInterval).toHaveBeenCalledTimes(2); diff --git a/src/build/build.ts b/src/build/build.ts index 3427826b..b16a0bb3 100644 --- a/src/build/build.ts +++ b/src/build/build.ts @@ -211,6 +211,13 @@ async function build(): Promise { singlebar.stop(); } + // eslint-disable-next-line no-restricted-syntax + for (const id in cluster.workers) { + if (Object.prototype.hasOwnProperty.call(cluster.workers, id)) { + cluster.workers[id].kill(); + } + } + let success = true; mElder.errors = [...mElder.errors, ...errors]; @@ -246,13 +253,6 @@ async function build(): Promise { if (!success) { throw new Error(`Build did not complete successfully.`); } - - // eslint-disable-next-line no-restricted-syntax - for (const id in cluster.workers) { - if (Object.prototype.hasOwnProperty.call(cluster.workers, id)) { - cluster.workers[id].kill(); - } - } } else { process.on('message', async (msg) => { if (msg.cmd === 'start') { @@ -265,7 +265,10 @@ async function build(): Promise { }); } } catch (e) { - process.exit(1); + if (e.message === 'Build did not complete successfully.') { + process.exit(1); + } + console.error(e); } } export default build; diff --git a/src/utils/__tests__/Page.spec.ts b/src/utils/__tests__/Page.spec.ts index 65f14401..6f27961b 100644 --- a/src/utils/__tests__/Page.spec.ts +++ b/src/utils/__tests__/Page.spec.ts @@ -221,17 +221,4 @@ describe('#Page', () => { ]); expect(page).toMatchSnapshot(); }); - - it('init and request html, throw catched errors', async () => { - const page = new Page({ - ...pageInput, - runHook: (hook) => { - if (hook === 'request' || hook === 'error') { - throw new Error(`mocked for hook: ${hook}`); - } - return runHook(hook); - }, - }); - expect(await page.html()).toEqual('{}'); - }); }); diff --git a/src/utils/__tests__/prepareRunHook.spec.ts b/src/utils/__tests__/prepareRunHook.spec.ts index a53a2491..2116bfa6 100644 --- a/src/utils/__tests__/prepareRunHook.spec.ts +++ b/src/utils/__tests__/prepareRunHook.spec.ts @@ -75,6 +75,8 @@ describe('#prepareRunHook', () => { it('cannot mutate not mutable prop', async () => { prepareRunHookFn = prepareRunHook({ hooks, allSupportedHooks, settings }); const errors = []; - await expect(prepareRunHookFn('bootstrap', { settings, errors, perf })).rejects.toThrow(); + await prepareRunHookFn('bootstrap', { settings, errors, perf }); + expect(errors).toHaveLength(2); + expect(errors[1]).toEqual('something bad happened'); }); }); diff --git a/src/workerBuild.ts b/src/workerBuild.ts index fba43609..24cdb9b9 100644 --- a/src/workerBuild.ts +++ b/src/workerBuild.ts @@ -50,6 +50,7 @@ async function workerBuild({ bootstrapComplete, workerRequests }) { errs += 1; response.push(errs); response.push({ request, errors: buildErrors.map((e) => JSON.stringify(e, Object.getOwnPropertyNames(e))) }); + bErrors.push({ request, errors: buildErrors }); } else { response.push(errs); } @@ -59,7 +60,7 @@ async function workerBuild({ bootstrapComplete, workerRequests }) { process.send(response); } }); - return { timings: bTimes }; + return { timings: bTimes, errors: bErrors }; } export default workerBuild; From 5c1cd9fb9882546a7f5b7b9e6fcdefec82ced4de Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Fri, 18 Sep 2020 11:38:18 -0400 Subject: [PATCH 43/75] 0.1.6-next.5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a200e103..2d7c936e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.4", + "version": "0.1.6-next.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 37827da1..36918e2a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.4", + "version": "0.1.6-next.5", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From 97fdaa7a7aef4d84a7e6c9d8b20fd4663d2b9aa7 Mon Sep 17 00:00:00 2001 From: halafi Date: Fri, 18 Sep 2020 17:57:24 +0200 Subject: [PATCH 44/75] fix: build test --- src/build/__tests__/build.spec.ts | 14 ++++++++++---- yarn.lock | 5 +++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/build/__tests__/build.spec.ts b/src/build/__tests__/build.spec.ts index 309f5c17..cfca0428 100644 --- a/src/build/__tests__/build.spec.ts +++ b/src/build/__tests__/build.spec.ts @@ -91,7 +91,7 @@ class WorkerMock { this.handlers.message(['start']); this.handlers.message(['done']); if (this.withError) { - this.handlers.message(['requestComplete', 3, 0, 'ignoreMe', 'pushMeToErrors']); + this.handlers.message(['requestComplete', 3, 0, { errors: [`{"msg":"pushMeToErrors"}`] }]); } else { this.handlers.message(['requestComplete']); } @@ -255,18 +255,24 @@ describe('#build', () => { global.Date.now = dateNowStub; + const realProcess = process; + const exitMock = jest.fn(); + // @ts-ignore + global.process = { ...realProcess, exit: exitMock }; + expect(calledHooks).toEqual([]); // eslint-disable-next-line global-require const build = require('../build').default; await build(); - jest.advanceTimersByTime(5000); // not all intervalls are cleared + jest.advanceTimersByTime(1000); // not all intervalls are cleared + expect(setInterval).toHaveBeenCalledTimes(2); + expect(exitMock).toHaveBeenCalled(); // eslint-disable-next-line global-require expect(require('cluster').workers.map((w) => w.killed)).toEqual([true, true]); expect(calledHooks).toEqual([ - 'buildComplete-{"success":false,"errors":["bornToFail","pushMeToErrors"],"timings":[null,null]}', + 'buildComplete-{"success":false,"errors":["bornToFail",{"errors":[{"msg":"pushMeToErrors"}]}],"timings":[null,null]}', ]); - expect(setInterval).toHaveBeenCalledTimes(2); }); }); diff --git a/yarn.lock b/yarn.lock index e8ee769e..20258438 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1744,6 +1744,11 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== +devalue@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/devalue/-/devalue-2.0.1.tgz#5d368f9adc0928e47b77eea53ca60d2f346f9762" + integrity sha512-I2TiqT5iWBEyB8GRfTDP0hiLZ0YeDJZ+upDxjBfOC2lebO5LezQMv7QvIUTzdb64jQyAKLf1AHADtGN+jw6v8Q== + diff-sequences@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" From 5747f1bf3d5a48b5d208fe1fa07a775773341a36 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Fri, 18 Sep 2020 12:59:59 -0400 Subject: [PATCH 45/75] =?UTF-8?q?fix:=20=F0=9F=90=9B=20proper=20'browser'?= =?UTF-8?q?=20and=20'server'=20in=20rollup=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/getRollupConfig.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/getRollupConfig.ts b/src/utils/getRollupConfig.ts index 50324406..c444406a 100644 --- a/src/utils/getRollupConfig.ts +++ b/src/utils/getRollupConfig.ts @@ -27,7 +27,7 @@ export function createBrowserConfig({ input, output, multiInputConfig = false, s output, plugins: [ replace({ - 'process.env.componentType': 'browser', + 'process.env.componentType': "'browser'", 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), }), json(), @@ -76,7 +76,7 @@ export function createSSRConfig({ input, output, svelteConfig, multiInputConfig output, plugins: [ replace({ - 'process.env.componentType': 'server', + 'process.env.componentType': "'server'", 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), }), json(), @@ -94,7 +94,7 @@ export function createSSRConfig({ input, output, svelteConfig, multiInputConfig browser: false, dedupe: ['svelte'], }), - commonjs({ sourceMap: false }), + commonjs({ sourceMap: true }), css({ ignore: true, }), From f63d297a788ff8dda6e0d63408f8385aca96ccae Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Fri, 18 Sep 2020 13:52:18 -0400 Subject: [PATCH 46/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20settle=20on=20temp?= =?UTF-8?q?lateHtml=20and=20make=20sure=20entities=20exist?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/__tests__/__snapshots__/Elder.spec.ts.snap | 12 ++++++------ src/hookInterface/hookEntityDefinitions.ts | 5 +++++ src/hookInterface/hookInterface.ts | 6 +++--- src/hooks.ts | 6 +++--- src/utils/Page.ts | 6 +++--- src/utils/__tests__/__snapshots__/Page.spec.ts.snap | 4 ++-- src/utils/__tests__/hookEntityDefinitions.spec.ts | 8 ++++++++ 7 files changed, 30 insertions(+), 17 deletions(-) create mode 100644 src/utils/__tests__/hookEntityDefinitions.spec.ts diff --git a/src/__tests__/__snapshots__/Elder.spec.ts.snap b/src/__tests__/__snapshots__/Elder.spec.ts.snap index 1c6f8728..de20f2e2 100644 --- a/src/__tests__/__snapshots__/Elder.spec.ts.snap +++ b/src/__tests__/__snapshots__/Elder.spec.ts.snap @@ -92,7 +92,7 @@ Elder { Object { "advanced": true, "context": "Fired upon a request that originates from the express/polka middleware version of Elder.js. The hook has access to \\"req\\" and \\"next\\" common in express like middleware.", - "experimental": true, + "experimental": false, "hook": "middleware", "location": "prepareServer.ts", "mutable": Array [ @@ -215,7 +215,7 @@ Elder { "location": "Page.ts", "mutable": Array [ "errors", - "routeHtml", + "templateHtml", "cssStack", "headStack", "customJsStack", @@ -230,7 +230,7 @@ Elder { "cssStack", "headStack", "customJsStack", - "routeHtml", + "templateHtml", "shortcodes", "allRequests", ], @@ -728,7 +728,7 @@ Elder { Object { "advanced": true, "context": "Fired upon a request that originates from the express/polka middleware version of Elder.js. The hook has access to \\"req\\" and \\"next\\" common in express like middleware.", - "experimental": true, + "experimental": false, "hook": "middleware", "location": "prepareServer.ts", "mutable": Array [ @@ -851,7 +851,7 @@ Elder { "location": "Page.ts", "mutable": Array [ "errors", - "routeHtml", + "templateHtml", "cssStack", "headStack", "customJsStack", @@ -866,7 +866,7 @@ Elder { "cssStack", "headStack", "customJsStack", - "routeHtml", + "templateHtml", "shortcodes", "allRequests", ], diff --git a/src/hookInterface/hookEntityDefinitions.ts b/src/hookInterface/hookEntityDefinitions.ts index 4ab8398d..82624439 100644 --- a/src/hookInterface/hookEntityDefinitions.ts +++ b/src/hookInterface/hookEntityDefinitions.ts @@ -33,6 +33,11 @@ const hookEntityDefinitions = { req: "The 'req' object from Express or Polka when Elder.js is being used as a server.", next: "The 'next' object from Express or Polka when Elder.js is being used as a server.", res: "The 'res' object from Express or Polka when Elder.js is being used as a server.", + templateHtml: "The HTML string returned by the SSR'd Svelte template for the request's route.", + shortcodes: "An array of shortcode definitions that are processed on the 'shortcodes' hook.", + footerString: 'A HTML string that Elder.js will write to the footer.', + layoutHtml: + "The compiled HTML response for a route containing all of the HTML from the Route's layout and template. ", }; // eslint-disable-next-line import/prefer-default-export diff --git a/src/hookInterface/hookInterface.ts b/src/hookInterface/hookInterface.ts index 0ba70f07..1f2b4039 100644 --- a/src/hookInterface/hookInterface.ts +++ b/src/hookInterface/hookInterface.ts @@ -88,7 +88,7 @@ export const hookInterface: Array = [
  • Anything you'd use an Express 'req' or 'next' for you can do and customize other parts of the Elder.js on this hook.
  • `, location: 'prepareServer.ts', - experimental: true, + experimental: false, advanced: true, }, @@ -166,11 +166,11 @@ export const hookInterface: Array = [ 'cssStack', 'headStack', 'customJsStack', - 'routeHtml', + 'templateHtml', 'shortcodes', 'allRequests', ], - mutable: ['errors', 'routeHtml', 'cssStack', 'headStack', 'customJsStack'], + mutable: ['errors', 'templateHtml', 'cssStack', 'headStack', 'customJsStack'], context: `Executed after the route's html has been compiled, but before the layout html has been compiled.`, use: `

    Elder.js uses this hook to process shortcodes. The vast majority of users won't need to use this hook, but if you were so inclined you could write your own shortcode parser or if you'd like to disable shortcodes completely, you can add 'elderProcessShortcodes' to hooks.disable in your elder.config.js file.

    NOTE: Don't use this hook for anything besides shortcodes.

    `, diff --git a/src/hooks.ts b/src/hooks.ts index 9f1be598..41b872cc 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -44,7 +44,7 @@ const hooks: Array = [ cssStack, headStack, customJsStack, - routeHtml, + templateHtml, shortcodes, allRequests, }) => { @@ -61,10 +61,10 @@ const hooks: Array = [ allRequests, }); - const html = await ShortcodeParser.parse(routeHtml); + const html = await ShortcodeParser.parse(templateHtml); return { - routeHtml: html, + templateHtml: html, headStack, cssStack, customJsStack, diff --git a/src/utils/Page.ts b/src/utils/Page.ts index 9845f373..9a021746 100644 --- a/src/utils/Page.ts +++ b/src/utils/Page.ts @@ -38,7 +38,7 @@ const buildPage = async (page) => { // start building templates page.perf.start('html.template'); - page.routeHtml = page.route.templateComponent({ + page.templateHtml = page.route.templateComponent({ page, props: { data: page.data, @@ -59,7 +59,7 @@ const buildPage = async (page) => { helpers: page.helpers, settings: createReadOnlyProxy(page.settings, 'settings', `${page.request.route}: Svelte Layout`), request: createReadOnlyProxy(page.request, 'request', `${page.request.route}: Svelte Layout`), - routeHtml: page.routeHtml, + templateHtml: page.templateHtml, }, }); page.perf.end('html.layout'); @@ -139,7 +139,7 @@ class Page { layoutHtml: string; - routeHtml: string; + templateHtml: string; cssString: string; diff --git a/src/utils/__tests__/__snapshots__/Page.spec.ts.snap b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap index cc2cd761..3bbf7734 100644 --- a/src/utils/__tests__/__snapshots__/Page.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap @@ -443,7 +443,6 @@ Page { }, "type": "build", }, - "routeHtml": undefined, "settings": Object { "$$internal": Object { "hashedComponents": Object { @@ -494,6 +493,7 @@ Page { "typescript": false, "worker": true, }, + "templateHtml": undefined, }, }, ], @@ -593,7 +593,6 @@ Page { ], }, }, - "routeHtml": undefined, "routes": Object { "content": Object { "$$meta": Object { @@ -672,6 +671,7 @@ Page { }, "shortcodes": Array [], "styleTag": "", + "templateHtml": undefined, "timings": Array [], "uid": "xxxxxxxxxx", } diff --git a/src/utils/__tests__/hookEntityDefinitions.spec.ts b/src/utils/__tests__/hookEntityDefinitions.spec.ts new file mode 100644 index 00000000..c7f202d7 --- /dev/null +++ b/src/utils/__tests__/hookEntityDefinitions.spec.ts @@ -0,0 +1,8 @@ +import { hookEntityDefinitions } from '../../hookInterface/hookEntityDefinitions'; +import hookInterface from '../../hookInterface/hookInterface'; + +test('#hookEntityDefinitions', async () => { + const entities = [...new Set(hookInterface.reduce((out, hook) => [...out, ...hook.props, ...hook.mutable], []))]; + const definitions = Object.keys(hookEntityDefinitions); + entities.forEach((entity) => expect(definitions).toContain(entity)); +}); From ddfd78acf8d9ad3581c595d60c8915f4562f675e Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Fri, 18 Sep 2020 13:52:41 -0400 Subject: [PATCH 47/75] 0.1.6-next.6 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2d7c936e..c01e0f2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.5", + "version": "0.1.6-next.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 36918e2a..8e78e610 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.5", + "version": "0.1.6-next.6", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From 7b591cd28967a0c6e45919210e4f4c42b45211a6 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Fri, 18 Sep 2020 15:58:36 -0400 Subject: [PATCH 48/75] =?UTF-8?q?fix:=20=F0=9F=90=9B=20change=20siteUrl=20?= =?UTF-8?q?to=20origin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/validations.spec.ts.snap | 56 ++++++++-------- src/utils/__tests__/validations.spec.ts | 2 +- src/utils/validations.ts | 66 +------------------ 3 files changed, 30 insertions(+), 94 deletions(-) diff --git a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap index e372d036..f755fecd 100644 --- a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap @@ -22,7 +22,7 @@ ObjectSchema { "srcDir", "distDir", "rootDir", - "siteUrl", + "origin", ], "_options": Object { "abortEarly": true, @@ -430,6 +430,33 @@ ObjectSchema { ], "type": "object", }, + "origin": StringSchema { + "_blacklist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "_conditions": Array [], + "_default": "", + "_deps": Array [], + "_exclusive": Object {}, + "_label": "The domain your site is hosted on. https://yourdomain.com.", + "_mutate": undefined, + "_options": Object { + "abortEarly": true, + "recursive": true, + }, + "_type": "string", + "_typeError": [Function], + "_whitelist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "tests": Array [], + "transforms": Array [ + [Function], + ], + "type": "string", + }, "plugins": ObjectSchema { "_blacklist": RefSet { "list": Set {}, @@ -634,33 +661,6 @@ ObjectSchema { ], "type": "object", }, - "siteUrl": StringSchema { - "_blacklist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "_conditions": Array [], - "_default": "", - "_deps": Array [], - "_exclusive": Object {}, - "_label": "The domain your site is hosted on. https://yourdomain.com.", - "_mutate": undefined, - "_options": Object { - "abortEarly": true, - "recursive": true, - }, - "_type": "string", - "_typeError": [Function], - "_whitelist": RefSet { - "list": Set {}, - "refs": Map {}, - }, - "tests": Array [], - "transforms": Array [ - [Function], - ], - "type": "string", - }, "srcDir": StringSchema { "_blacklist": RefSet { "list": Set {}, diff --git a/src/utils/__tests__/validations.spec.ts b/src/utils/__tests__/validations.spec.ts index 868aa775..a21a8536 100644 --- a/src/utils/__tests__/validations.spec.ts +++ b/src/utils/__tests__/validations.spec.ts @@ -39,7 +39,7 @@ describe('#validations', () => { hooks: { disable: [], }, - siteUrl: '', + origin: '', plugins: {}, server: { prefix: '', diff --git a/src/utils/validations.ts b/src/utils/validations.ts index 979ff96e..f6a5affa 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -18,7 +18,7 @@ const shortcodeSchema = yup.object({ }); const configSchema = yup.object({ - siteUrl: yup.string().notRequired().default('').label(`The domain your site is hosted on. https://yourdomain.com.`), + origin: yup.string().notRequired().default('').label(`The domain your site is hosted on. https://yourdomain.com.`), rootDir: yup.string().notRequired().default('process.cwd()').label('Here your package.json lives.'), distDir: yup .string() @@ -32,70 +32,6 @@ const configSchema = yup.object({ .label( "Where Elder.js should find it's expected file structure. If you are using a build step such as typescript on your project, you may need to edit this. ", ), - // locations: yup - // .object({ - // // assets: yup - // // .string() - // // .notRequired() - // // .default('./public/dist/static/') - // // .label( - // // 'Where your site\'s assets files should be written to if you are using the Elder.js template. (Include ./public/)"', - // // ), - // // public: yup - // // .string() - // // .notRequired() - // // .default('./public/') - // // .label( - // // 'Where should files be written? This represents the "root" of your site and where your html will be built.', - // // ), - // svelte: yup - // .object() - // .shape({ - // ssrComponents: yup - // .string() - // .notRequired() - // .default('./___ELDER___/compiled/') - // .label('Location where should SSR components be stored.'), - // clientComponents: yup - // .string() - // .notRequired() - // .default('./public/dist/svelte/') - // .label( - // 'Location where Svelte components that are bundled for the client should be saved. (Include ./public/)', - // ), - // }) - // .notRequired(), - // systemJs: yup - // .string() - // .notRequired() - // .default('/dist/static/s.min.js') - // .label( - // 'If you are using the recommended Elder.js rollup file it is using Systemjs. This defines is where the systemjs file will be found on your site. (exclude /public/)', - // ), - // srcFolder: yup - // .string() - // .notRequired() - // .default('./src/') - // .label('Elder.js and plugins use this to resolve where things should be in the expected file structure.'), - - // buildFolder: yup - // .string() - // .notRequired() - // .default('') - // .label( - // `If Elder.js doesn't find the files it is looking for in the src folder, it will look in the build folder. (used for typescript)`, - // ), - - // intersectionObserverPoly: yup - // .string() - // .notRequired() - // .default('/dist/static/intersection-observer.js') - // .label( - // 'Elder.js uses a poly fill for the intersection observer. This is where it will be found on your site. (exclude /public/)', - // ), - // }) - // .notRequired() - // .label('Where various files are written and read from.'), debug: yup .object() .shape({ From dda2f79d1991816a73430010c5ea445237ca8426 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Fri, 18 Sep 2020 15:58:57 -0400 Subject: [PATCH 49/75] 0.1.6-next.7 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index c01e0f2a..c0e7eb0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.6", + "version": "0.1.6-next.7", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8e78e610..c529c373 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.6", + "version": "0.1.6-next.7", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From 58b40ad8998a960b049d2609d796e4c4607238c5 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 21 Sep 2020 10:25:49 -0400 Subject: [PATCH 50/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20allRequests?= =?UTF-8?q?=20to=20buildComplete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hookInterface/hookInterface.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hookInterface/hookInterface.ts b/src/hookInterface/hookInterface.ts index 1f2b4039..3bb1d7f5 100644 --- a/src/hookInterface/hookInterface.ts +++ b/src/hookInterface/hookInterface.ts @@ -282,7 +282,7 @@ export const hookInterface: Array = [ { hook: 'buildComplete', - props: ['helpers', 'data', 'settings', 'timings', 'query', 'errors', 'routes'], + props: ['helpers', 'data', 'settings', 'timings', 'query', 'errors', 'routes', 'allRequests'], mutable: [], context: 'Executed after a build is complete', use: `

    Contains whether the build was successful. If not it contains errors for the entire build. Also includes From b8baaec1c95e27a5755847256787ed9e5001d28f Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 21 Sep 2020 10:59:28 -0400 Subject: [PATCH 51/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20partialHydration?= =?UTF-8?q?=20error=20for=20non-self=20closing=20tags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/partialHydration.spec.ts | 24 +++++++++++++++++++ src/partialHydration/partialHydration.ts | 13 ++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/partialHydration/__tests__/partialHydration.spec.ts b/src/partialHydration/__tests__/partialHydration.spec.ts index 1bdd3b60..41ed0f6e 100644 --- a/src/partialHydration/__tests__/partialHydration.spec.ts +++ b/src/partialHydration/__tests__/partialHydration.spec.ts @@ -39,4 +39,28 @@ test('#partialHydration', async () => { }) ).code, ).toEqual(`Contains whether the build was successful. If not it contains errors for the entire build. Also includes average performance details, and a granular performance object. Could be used to fire off additional scripts such as generating a sitemap or copying asset files to the public folder.

    @@ -1042,6 +1043,7 @@ Elder { "query", "errors", "routes", + "allRequests", ], "use": "

    Contains whether the build was successful. If not it contains errors for the entire build. Also includes average performance details, and a granular performance object. Could be used to fire off additional scripts such as generating a sitemap or copying asset files to the public folder.

    From bc602a2b3871f9edd07d40cc72c9778a2b7b6e0f Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 21 Sep 2020 11:36:51 -0400 Subject: [PATCH 53/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20improve=20error=20?= =?UTF-8?q?text=20on=20wrapping=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/partialHydration/partialHydration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/partialHydration/partialHydration.ts b/src/partialHydration/partialHydration.ts index cea4a899..40c73026 100644 --- a/src/partialHydration/partialHydration.ts +++ b/src/partialHydration/partialHydration.ts @@ -37,7 +37,7 @@ const partialHydration = { if (wrappedComponents && wrappedComponents.length > 0) { throw new Error( - `Elder.js only supports self-closing syntax on hydrated components. This means not or Something. Offending component: ${wrappedComponents[0][0]}`, + `Elder.js only supports self-closing syntax on hydrated components. This means not or Something. Offending component: ${wrappedComponents[0][0]}. Slots and child components aren't supported during hydration as it would result in huge HTML payloads. If you need this functionality try wrapping the offending component in a parent component without slots or child components and hydrate that.`, ); } From f1d6f9e105b3c7bac664bb8dc73ca216c6a6afd4 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 21 Sep 2020 14:13:02 -0400 Subject: [PATCH 54/75] =?UTF-8?q?docs:=20=E2=9C=8F=EF=B8=8F=20better=20err?= =?UTF-8?q?or=20message=20on=20partial=20hydration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/partialHydration/partialHydration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/partialHydration/partialHydration.ts b/src/partialHydration/partialHydration.ts index 40c73026..44ac508e 100644 --- a/src/partialHydration/partialHydration.ts +++ b/src/partialHydration/partialHydration.ts @@ -37,7 +37,7 @@ const partialHydration = { if (wrappedComponents && wrappedComponents.length > 0) { throw new Error( - `Elder.js only supports self-closing syntax on hydrated components. This means not or Something. Offending component: ${wrappedComponents[0][0]}. Slots and child components aren't supported during hydration as it would result in huge HTML payloads. If you need this functionality try wrapping the offending component in a parent component without slots or child components and hydrate that.`, + `Elder.js only supports self-closing syntax on hydrated components. This means not or Something. Offending component: ${wrappedComponents[0][0]}. Slots and child components aren't supported during hydration as it would result in huge HTML payloads. If you need this functionality try wrapping the offending component in a parent component without slots or child components and hydrate the parent component.`, ); } From 4260ae67b9c197bea3cfa442819b10379c73cc98 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 21 Sep 2020 14:13:30 -0400 Subject: [PATCH 55/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20shortcode=20debugg?= =?UTF-8?q?ing,=20support=20for=20\\[=20\\]=20brackets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/validations.spec.ts.snap | 30 +++++++++++++++- .../__tests__/prepareInlineShortcode.spec.ts | 23 ++++++++++++ .../__tests__/prepareShortcodeParser.spec.ts | 36 +++++++++++++++++++ src/utils/__tests__/validations.spec.ts | 1 + src/utils/prepareInlineShortcode.ts | 11 +++--- src/utils/prepareShortcodeParser.ts | 4 +++ src/utils/types.ts | 1 + src/utils/validations.ts | 7 +++- 8 files changed, 107 insertions(+), 6 deletions(-) diff --git a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap index f755fecd..f877b1a1 100644 --- a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap @@ -138,6 +138,7 @@ ObjectSchema { "automagic", "build", "performance", + "shortcodes", "hooks", "stacks", ], @@ -242,7 +243,34 @@ ObjectSchema { "_default": false, "_deps": Array [], "_exclusive": Object {}, - "_label": "Outputs a detauled speed report on each pageload.", + "_label": "Outputs a detailed speed report on each pageload.", + "_mutate": undefined, + "_options": Object { + "abortEarly": true, + "recursive": true, + }, + "_type": "boolean", + "_typeError": [Function], + "_whitelist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "tests": Array [], + "transforms": Array [ + [Function], + ], + "type": "boolean", + }, + "shortcodes": BooleanSchema { + "_blacklist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "_conditions": Array [], + "_default": false, + "_deps": Array [], + "_exclusive": Object {}, + "_label": "Output details of shortcode execution in the console.", "_mutate": undefined, "_options": Object { "abortEarly": true, diff --git a/src/utils/__tests__/prepareInlineShortcode.spec.ts b/src/utils/__tests__/prepareInlineShortcode.spec.ts index a6733f23..317b89ae 100644 --- a/src/utils/__tests__/prepareInlineShortcode.spec.ts +++ b/src/utils/__tests__/prepareInlineShortcode.spec.ts @@ -42,4 +42,27 @@ describe('#prepareInlineShortcode', () => { }), ).toEqual("
    Hi, I am content
    "); }); + + it('works - with \\ for escaped regex options', () => { + const settings = { + shortcodes: { + openPattern: '\\[', + closePattern: '\\]', + }, + }; + const fn = prepareInlineShortcode({ settings }); + expect( + fn({ + name: 'Test', + props: { + foo: 'bar', + answer: 42, + nested: { + prop: 'porp', + }, + }, + content: '
    Hi, I am content
    ', + }), + ).toEqual("[Test foo='bar' answer='42' nested='{\"prop\":\"porp\"}']
    Hi, I am content
    [/Test]"); + }); }); diff --git a/src/utils/__tests__/prepareShortcodeParser.spec.ts b/src/utils/__tests__/prepareShortcodeParser.spec.ts index e21cf80f..e57b339a 100644 --- a/src/utils/__tests__/prepareShortcodeParser.spec.ts +++ b/src/utils/__tests__/prepareShortcodeParser.spec.ts @@ -35,7 +35,15 @@ describe('#prepareShortcodeParser', () => { const shortcodeParser = prepareShortcodeParser({ ...args, shortcodes: [], + settings: { + debug: { + stacks: true, + hooks: true, + build: true, + automagic: true, + shortcodes: true, + }, shortcodes: { openPattern: '\\[', closePattern: '\\]', @@ -63,6 +71,13 @@ describe('#prepareShortcodeParser', () => { }, ], settings: { + debug: { + stacks: true, + hooks: true, + build: true, + automagic: true, + shortcodes: true, + }, shortcodes: { openPattern: '\\<', closePattern: '\\>', @@ -84,6 +99,13 @@ describe('#prepareShortcodeParser', () => { }, ], settings: { + debug: { + stacks: true, + hooks: true, + build: true, + automagic: true, + shortcodes: true, + }, shortcodes: { openPattern: '\\<', closePattern: '\\>', @@ -105,6 +127,13 @@ describe('#prepareShortcodeParser', () => { }, ], settings: { + debug: { + stacks: true, + hooks: true, + build: true, + automagic: true, + shortcodes: true, + }, shortcodes: { openPattern: '\\👍', closePattern: '\\👎', @@ -141,6 +170,13 @@ describe('#prepareShortcodeParser', () => { }, ], settings: { + debug: { + stacks: true, + hooks: true, + build: true, + automagic: true, + shortcodes: true, + }, shortcodes: { openPattern: '\\66', closePattern: '\\33', diff --git a/src/utils/__tests__/validations.spec.ts b/src/utils/__tests__/validations.spec.ts index a21a8536..10b13477 100644 --- a/src/utils/__tests__/validations.spec.ts +++ b/src/utils/__tests__/validations.spec.ts @@ -35,6 +35,7 @@ describe('#validations', () => { hooks: false, performance: false, stacks: false, + shortcodes: false, }, hooks: { disable: [], diff --git a/src/utils/prepareInlineShortcode.ts b/src/utils/prepareInlineShortcode.ts index 6191ce40..6d4b7858 100644 --- a/src/utils/prepareInlineShortcode.ts +++ b/src/utils/prepareInlineShortcode.ts @@ -1,7 +1,10 @@ const prepareInlineShortcode = ({ settings }) => ({ name, props = {}, content = '' }) => { const { openPattern, closePattern } = settings.shortcodes; + const openNoEscape = openPattern.replace('\\', ''); + const closeNoEscape = closePattern.replace('\\', ''); + if (!name) throw new Error(`helpers.shortcode requires a name prop`); - let shortcode = `${openPattern}${name}`; + let shortcode = `${openNoEscape}${name}`; shortcode += Object.entries(props).reduce((out, [key, val]) => { if (typeof val === 'object' || Array.isArray(val)) { @@ -15,16 +18,16 @@ const prepareInlineShortcode = ({ settings }) => ({ name, props = {}, content = if (!content) { // self closing - shortcode += `/${closePattern}`; + shortcode += `/${closeNoEscape}`; } else { // close the open shortcode. - shortcode += closePattern; + shortcode += closeNoEscape; // add content shortcode += content; // close the shortcode. - shortcode += `${openPattern}/${name}${closePattern}`; + shortcode += `${openNoEscape}/${name}${closeNoEscape}`; } return shortcode; diff --git a/src/utils/prepareShortcodeParser.ts b/src/utils/prepareShortcodeParser.ts index f553e568..db24d54b 100644 --- a/src/utils/prepareShortcodeParser.ts +++ b/src/utils/prepareShortcodeParser.ts @@ -62,6 +62,10 @@ function prepareShortcodeParser({ ), }); + if (settings.debug.shortcodes) { + console.log(`${shortcode.shortcode} returned`, shortcodeResponse); + } + if (typeof shortcodeResponse === 'object') { const { html, css, js, head } = shortcodeResponse; if (css) { diff --git a/src/utils/types.ts b/src/utils/types.ts index 767bcaba..91373fc8 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -21,6 +21,7 @@ type DebugOptions = { performance: boolean; build: boolean; automagic: boolean; + shortcodes: boolean; }; // type PathOptions = { diff --git a/src/utils/validations.ts b/src/utils/validations.ts index f6a5affa..81849c23 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -37,11 +37,16 @@ const configSchema = yup.object({ .shape({ stacks: yup.boolean().notRequired().default(false).label('Outputs details of stack processing in the console.'), hooks: yup.boolean().notRequired().default(false).label('Output details of hook execution in the console.'), + shortcodes: yup + .boolean() + .notRequired() + .default(false) + .label('Output details of shortcode execution in the console.'), performance: yup .boolean() .notRequired() .default(false) - .label('Outputs a detauled speed report on each pageload.'), + .label('Outputs a detailed speed report on each pageload.'), build: yup.boolean().notRequired().default(false).label('Displays detailed build information for each worker.'), automagic: yup .boolean() From f3c2e1c427bf55d3c2bcd88a5bd91bef355e9912 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 21 Sep 2020 14:30:23 -0400 Subject: [PATCH 56/75] 0.1.6-next.8 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index c0e7eb0f..0c842db6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.7", + "version": "0.1.6-next.8", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c529c373..a22f57fc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.7", + "version": "0.1.6-next.8", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From b60012f5f9b611dc6b79c181d3f8cc74e1d7a3fb Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 21 Sep 2020 15:00:22 -0400 Subject: [PATCH 57/75] =?UTF-8?q?chore:=20=F0=9F=A4=96=20get=20linter=20ha?= =?UTF-8?q?ppy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/partialHydration/partialHydration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/partialHydration/partialHydration.ts b/src/partialHydration/partialHydration.ts index 44ac508e..8cda260e 100644 --- a/src/partialHydration/partialHydration.ts +++ b/src/partialHydration/partialHydration.ts @@ -28,7 +28,7 @@ const partialHydration = { return out.replace(wholeMatch, replacement); }, content); - const wrappingComponentPattern = /<([a-zA-Z]+)[^>]+hydrate-client={([^]*?})}[^/>]*\>[^>]*<\/([a-zA-Z]+)>/gim; + const wrappingComponentPattern = /<([a-zA-Z]+)[^>]+hydrate-client={([^]*?})}[^/>]*>[^>]*<\/([a-zA-Z]+)>/gim; // // // Foo From a55fc57f801fc9b403726f1e8a0ddebff63e3aab Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 21 Sep 2020 18:55:34 -0400 Subject: [PATCH 58/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20move=20server=20to?= =?UTF-8?q?=20hook=20so=20it=20can=20be=20disabled=20or=20replaced?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/Elder.spec.ts.snap | 36 +++++++-- .../__snapshots__/hooks.spec.ts.snap | 7 ++ src/hookInterface/hookEntityDefinitions.ts | 2 + src/hookInterface/hookInterface.ts | 20 +---- src/hooks.ts | 75 +++++++++++++++++++ src/utils/__tests__/prepareServer.spec.ts | 12 ++- src/utils/prepareServer.ts | 75 ++----------------- 7 files changed, 134 insertions(+), 93 deletions(-) diff --git a/src/__tests__/__snapshots__/Elder.spec.ts.snap b/src/__tests__/__snapshots__/Elder.spec.ts.snap index c2e86cf1..b488ec42 100644 --- a/src/__tests__/__snapshots__/Elder.spec.ts.snap +++ b/src/__tests__/__snapshots__/Elder.spec.ts.snap @@ -97,11 +97,9 @@ Elder { "location": "prepareServer.ts", "mutable": Array [ "errors", - "request", "query", "helpers", "data", - "route", "settings", "allRequests", "routes", @@ -111,17 +109,18 @@ Elder { ], "props": Array [ "errors", - "request", "query", "helpers", "data", - "route", "settings", "allRequests", "routes", "req", "next", "res", + "serverLookupObject", + "runHook", + "shortcodes", ], "use": "

    If you're looking to use Elder.js with express/polka to build a server rendered website, then you'll be interested in this hook as it includes the familiar 'req' and 'next' objects as often used in Express middleware.

      @@ -425,6 +424,17 @@ Elder { "priority": 1, "run": [Function], }, + Object { + "$$meta": Object { + "addedBy": "elder.js", + "type": "internal", + }, + "description": "An express like middleware so requests can be served by Elder.js", + "hook": "middleware", + "name": "elderExpressLikeMiddleware", + "priority": 1, + "run": [Function], + }, Object { "$$meta": Object { "addedBy": "elder.js", @@ -734,11 +744,9 @@ Elder { "location": "prepareServer.ts", "mutable": Array [ "errors", - "request", "query", "helpers", "data", - "route", "settings", "allRequests", "routes", @@ -748,17 +756,18 @@ Elder { ], "props": Array [ "errors", - "request", "query", "helpers", "data", - "route", "settings", "allRequests", "routes", "req", "next", "res", + "serverLookupObject", + "runHook", + "shortcodes", ], "use": "

      If you're looking to use Elder.js with express/polka to build a server rendered website, then you'll be interested in this hook as it includes the familiar 'req' and 'next' objects as often used in Express middleware.

        @@ -1062,6 +1071,17 @@ Elder { "priority": 1, "run": [Function], }, + Object { + "$$meta": Object { + "addedBy": "elder.js", + "type": "internal", + }, + "description": "An express like middleware so requests can be served by Elder.js", + "hook": "middleware", + "name": "elderExpressLikeMiddleware", + "priority": 1, + "run": [Function], + }, Object { "$$meta": Object { "addedBy": "elder.js", diff --git a/src/__tests__/__snapshots__/hooks.spec.ts.snap b/src/__tests__/__snapshots__/hooks.spec.ts.snap index 793a14d4..76bdb7d3 100644 --- a/src/__tests__/__snapshots__/hooks.spec.ts.snap +++ b/src/__tests__/__snapshots__/hooks.spec.ts.snap @@ -88,6 +88,13 @@ Array [ "priority": 1, "run": [Function], }, + Object { + "description": "An express like middleware so requests can be served by Elder.js", + "hook": "middleware", + "name": "elderExpressLikeMiddleware", + "priority": 1, + "run": [Function], + }, Object { "description": "Builds the shortcode parser, parses shortcodes from the html returned by the route's html and appends anything needed to the stacks.", "hook": "shortcodes", diff --git a/src/hookInterface/hookEntityDefinitions.ts b/src/hookInterface/hookEntityDefinitions.ts index 82624439..d521f86a 100644 --- a/src/hookInterface/hookEntityDefinitions.ts +++ b/src/hookInterface/hookEntityDefinitions.ts @@ -38,6 +38,8 @@ const hookEntityDefinitions = { footerString: 'A HTML string that Elder.js will write to the footer.', layoutHtml: "The compiled HTML response for a route containing all of the HTML from the Route's layout and template. ", + serverLookupObject: `A key value object where the key is the relative permalink and the object is the 'request' object used by the Elder.js server.`, + runHook: `The function that powers hooks. 'await runhook('hookName', objectContainingProps)`, }; // eslint-disable-next-line import/prefer-default-export diff --git a/src/hookInterface/hookInterface.ts b/src/hookInterface/hookInterface.ts index 3bb1d7f5..4c545343 100644 --- a/src/hookInterface/hookInterface.ts +++ b/src/hookInterface/hookInterface.ts @@ -53,32 +53,20 @@ export const hookInterface: Array = [ hook: 'middleware', props: [ 'errors', - 'request', 'query', 'helpers', 'data', - 'route', - 'settings', - 'allRequests', - 'routes', - 'req', - 'next', - 'res', - ], - mutable: [ - 'errors', - 'request', - 'query', - 'helpers', - 'data', - 'route', 'settings', 'allRequests', 'routes', 'req', 'next', 'res', + 'serverLookupObject', + 'runHook', + 'shortcodes', ], + mutable: ['errors', 'query', 'helpers', 'data', 'settings', 'allRequests', 'routes', 'req', 'next', 'res'], context: 'Fired upon a request that originates from the express/polka middleware version of Elder.js. The hook has access to "req" and "next" common in express like middleware.', use: `

        If you're looking to use Elder.js with express/polka to build a server rendered website, then you'll be interested in this hook as it includes the familiar 'req' and 'next' objects as often used in Express middleware.

        diff --git a/src/hooks.ts b/src/hooks.ts index 41b872cc..fc24b49f 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -4,6 +4,7 @@ import { parseBuildPerf } from './utils'; import externalHelpers from './externalHelpers'; import { HookOptions } from './hookInterface/types'; import prepareShortcodeParser from './utils/prepareShortcodeParser'; +import Page from './utils/Page'; const hooks: Array = [ { @@ -29,6 +30,80 @@ const hooks: Array = [ return null; }, }, + { + hook: 'middleware', + name: 'elderExpressLikeMiddleware', + description: 'An express like middleware so requests can be served by Elder.js', + priority: 1, + run: async ({ + serverLookupObject, + settings, + query, + helpers, + data, + routes, + allRequests, + runHook, + errors, + shortcodes, + req, + next, + res, + }) => { + if (req.path) { + let reqPath = req.path; + + if (settings.server.prefix && settings.server.prefix.length > 0) { + if (reqPath.indexOf(settings.server.prefix) !== 0) { + return next(); + } + } + + // see if we have a request object with the path as is. (could include / or not.) + let requestObject = serverLookupObject[reqPath]; + + if (!requestObject && reqPath[reqPath.length - 1] === '/') { + // check the path without a slash. + requestObject = serverLookupObject[reqPath.substring(0, reqPath.length - 1)]; + } else if (!requestObject) { + // check the path with a slash. + reqPath += '/'; + requestObject = serverLookupObject[reqPath]; + } + + // if we have a requestObject then we know it is for ElderGuide + if (requestObject) { + const forPage = { + request: requestObject, + settings, + query, + helpers, + data, + route: routes[requestObject.route], + runHook, + allRequests, + routes, + errors, + shortcodes, + }; + + const page = new Page(forPage); + + const html = await page.html(); + + if (html && !res.headerSent) { + res.setHeader('Content-Type', 'text/html'); + res.end(html); + } + } else { + next(); + } + } else { + next(); + } + return {}; + }, + }, { hook: 'shortcodes', name: 'elderProcessShortcodes', diff --git a/src/utils/__tests__/prepareServer.spec.ts b/src/utils/__tests__/prepareServer.spec.ts index f07ebc6c..194b1dd1 100644 --- a/src/utils/__tests__/prepareServer.spec.ts +++ b/src/utils/__tests__/prepareServer.spec.ts @@ -1,6 +1,13 @@ import { prepareServer } from '../prepareServer'; -jest.mock('../Page'); +jest.mock('../Page', () => { + return { + default: jest.fn().mockImplementation(() => { + return {}; + }), + html: () => 'html', + }; +}); describe('#prepareServer', () => { it('works', async () => { @@ -70,6 +77,7 @@ describe('#prepareServer', () => { const nextMock = jest.fn(() => 'nextMockResult'); const setHeaderMock = jest.fn(); const endMock = jest.fn(); + const res = { setHeader: setHeaderMock, end: endMock, @@ -97,7 +105,6 @@ describe('#prepareServer', () => { ), ).toEqual(undefined); expect(hooks).toEqual(['middleware']); - expect(setHeaderMock).toHaveBeenCalledTimes(1); expect(endMock).toHaveBeenCalledTimes(1); expect(nextMock).toHaveBeenCalledTimes(1); // no new calls // no requestObject @@ -112,6 +119,7 @@ describe('#prepareServer', () => { ).toEqual(undefined); expect(setHeaderMock).toHaveBeenCalledTimes(2); expect(endMock).toHaveBeenCalledTimes(2); + expect(setHeaderMock).toHaveBeenCalledTimes(1); expect(nextMock).toHaveBeenCalledTimes(2); // new call }); }); diff --git a/src/utils/prepareServer.ts b/src/utils/prepareServer.ts index 1c57aeb6..32855721 100644 --- a/src/utils/prepareServer.ts +++ b/src/utils/prepareServer.ts @@ -1,74 +1,15 @@ -import Page from './Page'; - function prepareServer({ bootstrapComplete }) { // eslint-disable-next-line consistent-return return async function prepServer(req, res, next) { - const { - serverLookupObject, - settings, - query, - helpers, - data, - routes, - allRequests, - runHook, - errors, - shortcodes, - } = await bootstrapComplete; - - if (req.path) { - let { path } = req; - - if (settings.server.prefix && settings.server.prefix.length > 0) { - if (path.indexOf(settings.server.prefix) !== 0) { - return next(); - } - } - - // see if we have a request object with the path as is. (could include / or not.) - let requestObject = serverLookupObject[path]; - if (!requestObject && path[path.length - 1] === '/') { - // check the path without a slash. - requestObject = serverLookupObject[path.substring(0, path.length - 1)]; - } else if (!requestObject) { - // check the path with a slash. - path += '/'; - requestObject = serverLookupObject[path]; - } + const { runHook, ...bootstrap } = await bootstrapComplete; - // if we have a requestObject then we know it is for ElderGuide - if (requestObject) { - const forPage = { - request: requestObject, - settings, - query, - helpers, - data, - route: routes[requestObject.route], - runHook, - allRequests, - routes, - errors, - shortcodes, - }; - - await runHook('middleware', { ...forPage, req, next, res }); - - const page = new Page(forPage); - - if (!res.headerSent) { - res.setHeader('Content-Type', 'text/html'); - res.end(await page.html()); - } - } else { - if (settings.server.prefix && settings.server.prefix.length > 0) { - res.setHeader('Content-Type', 'application/json'); - res.end('{ "error": "Unknown template" }'); - } - - next(); - } - } + await runHook('middleware', { + ...bootstrap, + runHook, + req, + next, + res, + }); }; } From 14f8adb64f1798cb71b258e562ee907b3b54eb5e Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 21 Sep 2020 18:55:47 -0400 Subject: [PATCH 59/75] 0.1.6-next.9 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0c842db6..439e355e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.8", + "version": "0.1.6-next.9", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a22f57fc..8e53337d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.8", + "version": "0.1.6-next.9", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From 138673fdfb69ed6abd482927105a7b304e1df191 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Mon, 21 Sep 2020 19:06:32 -0400 Subject: [PATCH 60/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20request=20to?= =?UTF-8?q?=20scope=20of=20middleware,=20update=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hookInterface/hookInterface.ts | 19 +++++++++++++++++-- src/hooks.ts | 10 ++++++++-- src/utils/prepareServer.ts | 1 + 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/hookInterface/hookInterface.ts b/src/hookInterface/hookInterface.ts index 4c545343..da587ef9 100644 --- a/src/hookInterface/hookInterface.ts +++ b/src/hookInterface/hookInterface.ts @@ -65,13 +65,28 @@ export const hookInterface: Array = [ 'serverLookupObject', 'runHook', 'shortcodes', + 'request', + ], + mutable: [ + 'errors', + 'query', + 'helpers', + 'data', + 'settings', + 'allRequests', + 'routes', + 'req', + 'next', + 'res', + 'request', ], - mutable: ['errors', 'query', 'helpers', 'data', 'settings', 'allRequests', 'routes', 'req', 'next', 'res'], context: 'Fired upon a request that originates from the express/polka middleware version of Elder.js. The hook has access to "req" and "next" common in express like middleware.', use: `

        If you're looking to use Elder.js with express/polka to build a server rendered website, then you'll be interested in this hook as it includes the familiar 'req' and 'next' objects as often used in Express middleware.

          -
        • This hook could be used to set user or session information stored on the 'req' prop anywhere it is needed such as on the Elder.js 'request' object or 'data' object.
        • +
        • Under the hook Elder.js uses this hook to power the server implementation.
        • +
        • If you want to change the route of a request, you can do so by modifying the 'request.route' to the name of the new request, and it will be picked up by the default Elder.js server.
        • +
        • If you're looking to set user or session information stored on the 'req' prop we recommend using a hook to modify the 'request' object or 'data' objects. Change to the request object will be passed down.
        • If you're looking to pass in details about the query string deeper into your application, you could use this hook to do so.
        • Anything you'd use an Express 'req' or 'next' for you can do and customize other parts of the Elder.js on this hook.
        `, diff --git a/src/hooks.ts b/src/hooks.ts index fc24b49f..990a830b 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -49,6 +49,7 @@ const hooks: Array = [ req, next, res, + request, }) => { if (req.path) { let reqPath = req.path; @@ -71,15 +72,20 @@ const hooks: Array = [ requestObject = serverLookupObject[reqPath]; } + let route = routes[requestObject.route]; + if (request && request.route) { + route = routes[request.route]; + } + // if we have a requestObject then we know it is for ElderGuide if (requestObject) { const forPage = { - request: requestObject, + request: { ...requestObject, ...request }, settings, query, helpers, data, - route: routes[requestObject.route], + route, runHook, allRequests, routes, diff --git a/src/utils/prepareServer.ts b/src/utils/prepareServer.ts index 32855721..0b0ad1f7 100644 --- a/src/utils/prepareServer.ts +++ b/src/utils/prepareServer.ts @@ -9,6 +9,7 @@ function prepareServer({ bootstrapComplete }) { req, next, res, + request: {}, }); }; } From bb8db097a06d1c86e80049ef1abc6302e527b7f0 Mon Sep 17 00:00:00 2001 From: halafi Date: Tue, 22 Sep 2020 13:11:26 +0200 Subject: [PATCH 61/75] fix: prepareServer.spec --- src/utils/__tests__/prepareServer.spec.ts | 146 +++++----------------- 1 file changed, 33 insertions(+), 113 deletions(-) diff --git a/src/utils/__tests__/prepareServer.spec.ts b/src/utils/__tests__/prepareServer.spec.ts index 194b1dd1..b46d44e8 100644 --- a/src/utils/__tests__/prepareServer.spec.ts +++ b/src/utils/__tests__/prepareServer.spec.ts @@ -1,125 +1,45 @@ import { prepareServer } from '../prepareServer'; -jest.mock('../Page', () => { - return { - default: jest.fn().mockImplementation(() => { - return {}; - }), - html: () => 'html', - }; -}); - describe('#prepareServer', () => { it('works', async () => { const hooks = []; - const runHook = (hookName) => { - hooks.push(hookName); + const runHook = async (name, props) => { + hooks.push({ name, props }); }; - - const input = { - serverLookupObject: { - '/dev/north-dakota/': { - id: 37, - slug: 'north-dakota', - random: 82, - route: 'state', - type: 'server', - premalink: '/north-dakota/', - }, + const nextMock = jest.fn(); + const prepServer = prepareServer({ + bootstrapComplete: Promise.resolve({ + runHook, + foo: 'bar', + bar: 'foo', + }), + }); + await prepServer( + { + desc: 'req', }, - settings: { server: { prefix: '/dev' } }, - query: { - db: { - db: {}, - pool: {}, - cnString: { - connectionString: 'postgresql://user:user@localhost:5099/db', - }, - }, - }, - helpers: { - permalinks: {}, - metersInAMile: 0.00062137119224, + { + desc: 'res', }, - data: {}, - routes: { - state: { - hooks: [], - permalink: jest.fn(), - all: jest.fn(), - template: 'State.svelte', - parent: 'home', - breadcrumbLabel: jest.fn(), - templateComponent: jest.fn(), - data: jest.fn(), - layout: jest.fn(), - $$meta: { type: 'route', addedBy: 'routejs' }, + nextMock, + ); + expect(hooks).toEqual([ + { + name: 'middleware', + props: { + runHook, + bar: 'foo', + foo: 'bar', + next: nextMock, + req: { + desc: 'req', + }, + request: {}, + res: { + desc: 'res', + }, }, }, - allRequests: [ - { - id: 37, - slug: 'north-dakota', - random: 82, - route: 'state', - type: 'server', - premalink: '/north-dakota/', - }, - ], - runHook, - errors: [], - customProps: {}, - }; - - const bootstrapComplete = Promise.resolve(input); - - const prepServerFn = prepareServer({ bootstrapComplete }); - const nextMock = jest.fn(() => 'nextMockResult'); - const setHeaderMock = jest.fn(); - const endMock = jest.fn(); - - const res = { - setHeader: setHeaderMock, - end: endMock, - }; - expect(await prepServerFn({}, res, nextMock)).toEqual(undefined); - // path doesn't include server prefix - expect( - await prepServerFn( - { - path: '/north-dakota', - }, - res, - nextMock, - ), - ).toEqual('nextMockResult'); - expect(nextMock).toHaveBeenCalledTimes(1); - // request for path - expect( - await prepServerFn( - { - path: '/dev/north-dakota', - }, - res, - nextMock, - ), - ).toEqual(undefined); - expect(hooks).toEqual(['middleware']); - expect(endMock).toHaveBeenCalledTimes(1); - expect(nextMock).toHaveBeenCalledTimes(1); // no new calls - // no requestObject - expect( - await prepServerFn( - { - path: '/dev/south-dakota', - }, - res, - nextMock, - ), - ).toEqual(undefined); - expect(setHeaderMock).toHaveBeenCalledTimes(2); - expect(endMock).toHaveBeenCalledTimes(2); - expect(setHeaderMock).toHaveBeenCalledTimes(1); - expect(nextMock).toHaveBeenCalledTimes(2); // new call + ]); }); }); From 27a0f94483f0d05312f717dcbbbf7864c22a4e5c Mon Sep 17 00:00:00 2001 From: halafi Date: Tue, 22 Sep 2020 13:18:21 +0200 Subject: [PATCH 62/75] fix: elder.spec --- src/__tests__/__snapshots__/Elder.spec.ts.snap | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/__tests__/__snapshots__/Elder.spec.ts.snap b/src/__tests__/__snapshots__/Elder.spec.ts.snap index b488ec42..30c632d4 100644 --- a/src/__tests__/__snapshots__/Elder.spec.ts.snap +++ b/src/__tests__/__snapshots__/Elder.spec.ts.snap @@ -106,6 +106,7 @@ Elder { "req", "next", "res", + "request", ], "props": Array [ "errors", @@ -121,10 +122,13 @@ Elder { "serverLookupObject", "runHook", "shortcodes", + "request", ], "use": "

        If you're looking to use Elder.js with express/polka to build a server rendered website, then you'll be interested in this hook as it includes the familiar 'req' and 'next' objects as often used in Express middleware.

          -
        • This hook could be used to set user or session information stored on the 'req' prop anywhere it is needed such as on the Elder.js 'request' object or 'data' object.
        • +
        • Under the hook Elder.js uses this hook to power the server implementation.
        • +
        • If you want to change the route of a request, you can do so by modifying the 'request.route' to the name of the new request, and it will be picked up by the default Elder.js server.
        • +
        • If you're looking to set user or session information stored on the 'req' prop we recommend using a hook to modify the 'request' object or 'data' objects. Change to the request object will be passed down.
        • If you're looking to pass in details about the query string deeper into your application, you could use this hook to do so.
        • Anything you'd use an Express 'req' or 'next' for you can do and customize other parts of the Elder.js on this hook.
        ", @@ -753,6 +757,7 @@ Elder { "req", "next", "res", + "request", ], "props": Array [ "errors", @@ -768,10 +773,13 @@ Elder { "serverLookupObject", "runHook", "shortcodes", + "request", ], "use": "

        If you're looking to use Elder.js with express/polka to build a server rendered website, then you'll be interested in this hook as it includes the familiar 'req' and 'next' objects as often used in Express middleware.

          -
        • This hook could be used to set user or session information stored on the 'req' prop anywhere it is needed such as on the Elder.js 'request' object or 'data' object.
        • +
        • Under the hook Elder.js uses this hook to power the server implementation.
        • +
        • If you want to change the route of a request, you can do so by modifying the 'request.route' to the name of the new request, and it will be picked up by the default Elder.js server.
        • +
        • If you're looking to set user or session information stored on the 'req' prop we recommend using a hook to modify the 'request' object or 'data' objects. Change to the request object will be passed down.
        • If you're looking to pass in details about the query string deeper into your application, you could use this hook to do so.
        • Anything you'd use an Express 'req' or 'next' for you can do and customize other parts of the Elder.js on this hook.
        ", From 2e987560a84e66b5a0e8cfe8bb59b6c539caf2c9 Mon Sep 17 00:00:00 2001 From: halafi Date: Tue, 22 Sep 2020 13:56:54 +0200 Subject: [PATCH 63/75] test: hooks.spec.ts --- .../__snapshots__/hooks.spec.ts.snap | 9 -- src/__tests__/hooks.spec.ts | 85 ++++++++++++++++++- 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/src/__tests__/__snapshots__/hooks.spec.ts.snap b/src/__tests__/__snapshots__/hooks.spec.ts.snap index 76bdb7d3..29d9458a 100644 --- a/src/__tests__/__snapshots__/hooks.spec.ts.snap +++ b/src/__tests__/__snapshots__/hooks.spec.ts.snap @@ -70,15 +70,6 @@ Object { } `; -exports[`#hooks elderProcessShortcodes 1`] = ` -Object { - "helpers": Object { - "old": [MockFunction], - "permalink": [MockFunction], - }, -} -`; - exports[`#hooks matchesSnapshot 1`] = ` Array [ Object { diff --git a/src/__tests__/hooks.spec.ts b/src/__tests__/hooks.spec.ts index a4e085a7..a390d307 100644 --- a/src/__tests__/hooks.spec.ts +++ b/src/__tests__/hooks.spec.ts @@ -2,6 +2,21 @@ import hooks from '../hooks'; jest.mock('../externalHelpers', () => () => Promise.resolve({ permalink: jest.fn() })); +jest.mock('../utils/prepareShortcodeParser', () => ({ customJsStack, cssStack, headStack }) => ({ + parse: (templateHtml) => { + customJsStack.push('console.log("test");'); + cssStack.push('body{display:none;}'); + headStack.push('Hello'); + return Promise.resolve(`..${templateHtml}..`); + }, +})); + +jest.mock('../utils/Page', () => { + return jest.fn(() => ({ + html: () => Promise.resolve(`new page`), + })); +}); + process.cwd = () => 'test'; jest.mock('path', () => ({ @@ -30,11 +45,73 @@ describe('#hooks', () => { const hook = hooks.find((h) => h.name === 'elderAddExternalHelpers'); expect(await hook.run({ helpers: { old: jest.fn() }, query: {}, settings: {} })).toMatchSnapshot(); }); + it('elderExpressLikeMiddleware', async () => { + const hook = hooks.find((h) => h.name === 'elderExpressLikeMiddleware'); + const next = () => 'next() was called'; + const settings = { + server: { + prefix: '/dev', + }, + }; + // prefix not found + expect( + await hook.run({ + next, + req: { path: '/' }, + settings, + }), + ).toEqual('next() was called'); + const headers = []; + const end = jest.fn(); + // route found with slash added + expect( + await hook.run({ + next, + req: { path: '/dev' }, + res: { + headerSent: false, + setHeader: (key, val) => { + headers.push(`${key}-${val}`); + }, + end, + }, + routes: { + Home: { + data: { foo: 'bar' }, + }, + }, + serverLookupObject: { + '/dev/': { + route: 'Home', + }, + }, + settings, + }), + ).toEqual({}); + expect(end).toHaveBeenCalledTimes(1); + expect(headers).toEqual(['Content-Type-text/html']); + }); it('elderProcessShortcodes', async () => { - const hook = hooks.find((h) => h.name === 'elderAddExternalHelpers'); - expect(await hook.run({ helpers: { old: jest.fn() }, query: {}, settings: {} })).toMatchSnapshot(); - - // TODO!!! + const hook = hooks.find((h) => h.name === 'elderProcessShortcodes'); + const headStack = []; + const cssStack = []; + const customJsStack = []; + expect( + await hook.run({ + headStack, + cssStack, + customJsStack, + templateHtml: 'hi', + helpers: {}, + query: {}, + settings: {}, + }), + ).toEqual({ + cssStack: ['body{display:none;}'], + customJsStack: ['console.log("test");'], + headStack: ['Hello'], + templateHtml: '..hi..', + }); }); it('elderAddMetaCharsetToHead', async () => { const hook = hooks.find((h) => h.name === 'elderAddMetaCharsetToHead'); From 0372e1ef04416fd2df75ab088e9b342b6ec50305 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 22 Sep 2020 08:04:18 -0400 Subject: [PATCH 64/75] =?UTF-8?q?fix:=20=F0=9F=90=9B=20check=20for=20reque?= =?UTF-8?q?st=20object?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/hooks.ts b/src/hooks.ts index 990a830b..6cd1e7b8 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -72,13 +72,12 @@ const hooks: Array = [ requestObject = serverLookupObject[reqPath]; } - let route = routes[requestObject.route]; - if (request && request.route) { - route = routes[request.route]; - } - // if we have a requestObject then we know it is for ElderGuide if (requestObject) { + let route = routes[requestObject.route]; + if (request && request.route) { + route = routes[request.route]; + } const forPage = { request: { ...requestObject, ...request }, settings, From 168baf0f779c9cfa63eb1d8055776d4c88101934 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 22 Sep 2020 08:16:07 -0400 Subject: [PATCH 65/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20can=20use=20/compo?= =?UTF-8?q?ntents/name/Name.svelte=20or=20without=20folder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/getRollupConfig.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/utils/getRollupConfig.ts b/src/utils/getRollupConfig.ts index c444406a..d6cc783b 100644 --- a/src/utils/getRollupConfig.ts +++ b/src/utils/getRollupConfig.ts @@ -208,7 +208,7 @@ export default function getRollupConfig({ svelteConfig }) { if (fs.existsSync(path.resolve(srcDir, `./components/`))) { configs.push( createBrowserConfig({ - input: [`${relSrcDir}/components/*/*.svelte`], + input: [`${relSrcDir}/components/*/*.svelte`, `${relSrcDir}/components/*.svelte`], output: { dir: clientComponents, entryFileNames: 'entry[name]-[hash].js', @@ -224,7 +224,7 @@ export default function getRollupConfig({ svelteConfig }) { ); configs.push( createSSRConfig({ - input: [`${relSrcDir}/components/*/*.svelte`], + input: [`${relSrcDir}/components/*/*.svelte`, `${relSrcDir}/components/*.svelte`], output: { dir: ssrComponents, format: 'cjs', @@ -240,9 +240,11 @@ export default function getRollupConfig({ svelteConfig }) { } } else { // watch/dev build bundles each component individually for faster reload times during dev. - if (fs.existsSync(path.resolve(srcDir, `./components/`))) { - glob.sync(path.resolve(srcDir, './components/*/*.svelte')).forEach((cv) => { + [ + ...glob.sync(path.resolve(srcDir, './components/*/*.svelte')), + ...glob.sync(path.resolve(srcDir, './components/*.svelte')), + ].forEach((cv) => { const file = cv.replace(`${rootDir}/`, ''); configs.push( createBrowserConfig({ From 936a8f5a0d2173b64a8d8fe212320462719bf474 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 22 Sep 2020 08:17:01 -0400 Subject: [PATCH 66/75] =?UTF-8?q?fix:=20=F0=9F=90=9B=20fix=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/__tests__/__snapshots__/getRollupConfig.spec.ts.snap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils/__tests__/__snapshots__/getRollupConfig.spec.ts.snap b/src/utils/__tests__/__snapshots__/getRollupConfig.spec.ts.snap index f9a690a3..54c3338f 100644 --- a/src/utils/__tests__/__snapshots__/getRollupConfig.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/getRollupConfig.spec.ts.snap @@ -246,6 +246,7 @@ Array [ "cache": true, "input": Array [ "rc/components/*/*.svelte", + "rc/components/*.svelte", ], "output": Object { "dir": "test/public/svelte", @@ -310,6 +311,7 @@ Array [ "cache": true, "input": Array [ "rc/components/*/*.svelte", + "rc/components/*.svelte", ], "output": Object { "dir": "test/___ELDER___/compiled", From 467369334d0ffe766f08daf4bb0b580b06bdd4a6 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 22 Sep 2020 08:17:32 -0400 Subject: [PATCH 67/75] 0.1.6-next.10 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 439e355e..f7148ac6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.9", + "version": "0.1.6-next.10", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8e53337d..dcf51773 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.9", + "version": "0.1.6-next.10", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From 6f65dd19e025c3f5eef7b1b67c13262ce67fcbbb Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 22 Sep 2020 08:40:34 -0400 Subject: [PATCH 68/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20warning=20for=20no?= =?UTF-8?q?=20origin=20in=20elder.config.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/getConfig.ts | 6 ++++++ src/utils/types.ts | 1 + 2 files changed, 7 insertions(+) diff --git a/src/utils/getConfig.ts b/src/utils/getConfig.ts index eb06c8f4..13c9272f 100644 --- a/src/utils/getConfig.ts +++ b/src/utils/getConfig.ts @@ -28,6 +28,12 @@ function getConfig(): ConfigOptions { clientComponents, }; + if (config.origin === '') { + console.error( + `Remember to put a valid origin in your elder.config.js. This should be a fully qualified domain. This is frequently used plugins and leaving it blank can cause SEO headaches.`, + ); + } + return config; } diff --git a/src/utils/types.ts b/src/utils/types.ts index 91373fc8..b394aa8f 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -50,6 +50,7 @@ export type ConfigOptions = { distDir: string; srcDir: string; rootDir: string; + origin: string; server: ServerOptions; build: BuildOptions; From 5b244196fb0552fc21316826c1dce83c94283229 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 22 Sep 2020 08:40:45 -0400 Subject: [PATCH 69/75] 0.1.6-next.11 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f7148ac6..bcf8c041 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.10", + "version": "0.1.6-next.11", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index dcf51773..30ec5745 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.10", + "version": "0.1.6-next.11", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From 021848a7ec505426b6eaaa2ab0b45593d566a6ed Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 22 Sep 2020 12:40:50 -0400 Subject: [PATCH 70/75] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20shortcodeSch?= =?UTF-8?q?ema=20to=20export?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 3 +-- src/utils/getConfig.ts | 2 +- src/utils/validations.ts | 4 +--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/index.ts b/src/index.ts index 27fff3cb..813fcdee 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,5 @@ /* istanbul ignore file */ -export { configSchema, hookSchema, routeSchema, pluginSchema } from './utils/validations'; - +export { configSchema, hookSchema, routeSchema, pluginSchema, shortcodeSchema } from './utils/validations'; export { Elder, build, partialHydration } from './Elder'; export * from './utils/types'; export * from './utils/index'; diff --git a/src/utils/getConfig.ts b/src/utils/getConfig.ts index 13c9272f..9defce0f 100644 --- a/src/utils/getConfig.ts +++ b/src/utils/getConfig.ts @@ -30,7 +30,7 @@ function getConfig(): ConfigOptions { if (config.origin === '') { console.error( - `Remember to put a valid origin in your elder.config.js. This should be a fully qualified domain. This is frequently used plugins and leaving it blank can cause SEO headaches.`, + `WARN: Remember to put a valid "origin" in your elder.config.js. This should be a fully qualified domain. This is frequently used plugins and leaving it blank can cause SEO headaches.`, ); } diff --git a/src/utils/validations.ts b/src/utils/validations.ts index 81849c23..67f31840 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -117,9 +117,7 @@ const routeSchema = yup.object({ .mixed() .notRequired() .default({}) - .label( - `Async/sync function that returns a JS object. Can also be a plain JS object. Important: If this is a function it is passed a '{data}' parameter. This parameter should be mutated and returned to pick up any data populated via hooks or plugins.`, - ), + .label(`Async/sync function that returns a JS object. Can also be a plain JS object.`), }); const pluginSchema = yup.object({ From 50fbb16994f548fe5e3785c2550ef149b070db74 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 22 Sep 2020 12:41:35 -0400 Subject: [PATCH 71/75] 0.1.6-next.12 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index bcf8c041..e041bc97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.11", + "version": "0.1.6-next.12", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 30ec5745..0ad30bba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.11", + "version": "0.1.6-next.12", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From 39ef2f277a31e6f3663275e123747732a056414c Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 22 Sep 2020 13:42:47 -0400 Subject: [PATCH 72/75] =?UTF-8?q?fix:=20=F0=9F=90=9B=20fix=20validation=20?= =?UTF-8?q?so=20the=20documentation=20is=20accurate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/validations.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/validations.ts b/src/utils/validations.ts index 67f31840..6e8d4bf2 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -141,7 +141,7 @@ const pluginSchema = yup.object({ .default({}) .notRequired() .label('(optional) An object of default configs. These will be used when none are set in their elder.config.js.'), - shortcodes: yup.mixed().notRequired().default([]).label('Array of shortcodes'), + shortcodes: yup.array().notRequired().default([]).label('Array of shortcodes'), }); const hookSchema = yup From 8d2bd6cff33e1dbdc898758b2c44af075fc32f93 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 22 Sep 2020 14:01:39 -0400 Subject: [PATCH 73/75] 0.1.6-next.13 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e041bc97..b0efd7fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.12", + "version": "0.1.6-next.13", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0ad30bba..84aafdf8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.6-next.12", + "version": "0.1.6-next.13", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, From a3c105e059515cbd2f3520593af3acb1790d7759 Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 22 Sep 2020 14:19:56 -0400 Subject: [PATCH 74/75] =?UTF-8?q?docs:=20=E2=9C=8F=EF=B8=8F=20better=20doc?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 04e9d542..c8a2e75c 100644 --- a/README.md +++ b/README.md @@ -21,33 +21,35 @@
        +[Elder.js](https://github.com/elderjs/elderjs) is an opinionated static site generator and web framework built with SEO in mind. (Supports SSR and Static Site Generation.) -Elder.js is an opinionated static site generator and web framework built with SEO in mind. :rocket: +- [Full Docs](https://elderguide.com/tech/elderjs/) +- [Template](https://github.com/Elderjs/template) +- [Plugins](https://github.com/Elderjs/plugins) -Full documentation here: https://elderguide.com/tech/elderjs/ +**Features:** -The quickest way to get started is here: https://github.com/Elderjs/template/ +- [**Build hooks**](https://elderguide.com/tech/elderjs/#hooks-how-to-customize-elderjs) allow you to plug into any part of entire page generation process and customize as needed. +- **A Highly Optimized Build Process:** that will span as many CPU cores as you can throw at it to make building your site as fast as possible. For reference Elder.js easily generates a data intensive 18,000 page site in 8 minutes using a budget 4 core VM. +- **Svelte Everywhere:** Use Svelte for your SSR templates and with partial hydration on the client for tiny html/bundle sizes. +- **Straightforward Data Flow:** By simply associating a `data` function in your `route.js`, you have complete control over how you fetch, prepare, and manipulate data before sending it to your Svelte template. Anything you can do in Node.js, you can do to fetch your data. Multiple data sources, no problem. +- **Community Plugins:** Easily extend what your Elder.js site can do by adding [prebuilt plugins](https://github.com/Elderjs/plugins) to your site. +- **Shortcodes:** Future proof your content, whether it lives in a CMS or in static files using smart placeholders. +- **0KB JS**: Defaults to 0KB of JS if your page doesn't need JS. +- **Partial Hydration**: Unlike most frameworks, Elder.js lets you hydrate just the parts of the client that need to be interactive allowing you to dramatically reduce your payloads while still having full control over component lazy-loading, preloading, and eager-loading. -If you find bugs please open an issue. +**Context** -**We consider Elder.js to be in 'beta' in terms of API stability but are using it in production on https://elderguide.com.** +Elder.js is the result of our team's work to build this site ([ElderGuide.com](https://elderguide.com)) and was purpose built to solve the unique challenges of building flagship SEO sites with 10-100k+ pages. -## Features: +Elder Guide Co-Founder [Nick Reese](https://nicholasreese.com) has built or managed 5 major SEO properties over the past 14 years. After leading the transition of several complex sites to static site generators he loved the benefits of the JAM stack, but wished there was a better solution for complex, data intensive, projects. Elder.js is his vision for how static site generators can become viable for sites of all sizes regardless of the number of pages or how complex the data being presented is. -* [**Build hooks**](https://elderguide.com/tech/elderjs/#hooks-how-to-customize-elderjs) allow you to plug into any part of entire page generation process and build process and customize as needed. -* **A Highly Optimized Build Process:** that will span as many CPU cores as you can throw at it to make building your site as fast as possible. For reference Elder.js easily generates a data intensive 18,000 page site in 8 minutes using a budget 4 core VM. -* **Svelte Everywhere:** Use Svelte for your SSR templates and with partial hydration on the client for tiny html/bundle sizes. -* **Straightforward Data Flow:** Each route has a `data` function and you have complete control over how you fetch, prepare, and manipulate data before sending it to your Svelte template. Anything you can do in Node.js, you can do to fetch your data. Multiple data sources, no problem. -* **Community Plugins:** Easily extend what your Elder.js site can do by adding [prebuilt plugins](https://github.com/Elderjs/plugins) to your site. +We hope you find this project useful whether you're building a small personal blog or a flagship SEO site that impacts millions of users. +## Getting Started: -## Context - -Elder.js is the result of our team's work to build ([ElderGuide.com](https://elderguide.com)) and was purpose built to solve the unique challenges of building flagship SEO sites with 10-100k+ pages. - -Elder Guide co-Founder [Nick Reese](https://nicholasreese.com) has built or managed 5 major SEO properties over the past 14 years. After leading the transition of several complex sites to static site generators he loved the benefits of the JAM stack, but wished there was a better solution for complex, data intensive, projects. Elder.js is his vision for how static site generators can become viable for sites of all sizes regardless of the number of pages or how complex the data being presented is. - -We hope you find this project useful whether you're building a small personal blog or a flagship SEO site that impacts millions of users. +The quickest way to get started is to get started with the [Elder.js template](https://github.com/Elderjs/template) using [degit](https://github.com/Rich-Harris/degit): +Here is a demo of the template: [https://elderjs.netlify.app/](https://elderjs.netlify.app/) ## Full documentation here: https://elderguide.com/tech/elderjs/ From c571d4ad5944df06782850d73cdc2483911752ab Mon Sep 17 00:00:00 2001 From: Nick Reese Date: Tue, 22 Sep 2020 14:23:51 -0400 Subject: [PATCH 75/75] =?UTF-8?q?test:=20=F0=9F=92=8D=20update=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/validations.spec.ts.snap | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap index f877b1a1..dcac9b99 100644 --- a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap @@ -1230,7 +1230,7 @@ ObjectSchema { ], "type": "object", }, - "shortcodes": SchemaType { + "shortcodes": ArraySchema { "_blacklist": RefSet { "list": Set {}, "refs": Map {}, @@ -1245,15 +1245,19 @@ ObjectSchema { "abortEarly": true, "recursive": true, }, - "_type": "mixed", + "_subType": undefined, + "_type": "array", "_typeError": [Function], "_whitelist": RefSet { "list": Set {}, "refs": Map {}, }, + "innerType": undefined, "tests": Array [], - "transforms": Array [], - "type": "mixed", + "transforms": Array [ + [Function], + ], + "type": "array", }, }, "tests": Array [], @@ -1332,7 +1336,7 @@ ObjectSchema { "_default": Object {}, "_deps": Array [], "_exclusive": Object {}, - "_label": "Async/sync function that returns a JS object. Can also be a plain JS object. Important: If this is a function it is passed a '{data}' parameter. This parameter should be mutated and returned to pick up any data populated via hooks or plugins.", + "_label": "Async/sync function that returns a JS object. Can also be a plain JS object.", "_mutate": undefined, "_options": Object { "abortEarly": true,