diff --git a/config/default.json5 b/config/default.json5 index e56d702..20ee8f0 100644 --- a/config/default.json5 +++ b/config/default.json5 @@ -48,6 +48,7 @@ view: { cache: false, enable_asset_cache: false, + dev: true, }, magic_link: { validity_period: 20, diff --git a/config/production.json5 b/config/production.json5 index 62d02ac..fcabc23 100644 --- a/config/production.json5 +++ b/config/production.json5 @@ -21,5 +21,6 @@ view: { cache: true, enable_asset_cache: true, + dev: false, }, } diff --git a/package.json b/package.json index 1a54d80..797e74d 100644 --- a/package.json +++ b/package.json @@ -18,11 +18,13 @@ "prepare-sources": "node scripts/prepare-sources.js", "compile": "yarn clean && tsc", "build": "yarn prepare-sources && yarn compile && node scripts/dist.js", - "dev": "yarn prepare-sources && concurrently -k -n \"Typescript,Node,Webpack,Maildev\" -p \"[{name}]\" -c \"blue,green,red,yellow\" \"tsc --watch\" \"nodemon\" \"maildev\"", + "dev": "yarn prepare-sources && concurrently -k -n \"Typescript,Node,Webpack,Maildev\" -p \"[{name}]\" -c \"blue,green,red,yellow\" \"tsc --watch\" \"nodemon -i public\" \"maildev\"", "lint": "eslint .", "release": "yarn build && yarn lint && yarn test && cd dist && yarn publish" }, "devDependencies": { + "@rollup/plugin-commonjs": "^17.1.0", + "@rollup/plugin-node-resolve": "^11.2.0", "@sveltejs/eslint-config": "sveltejs/eslint-config", "@tsconfig/svelte": "^1.0.10", "@types/compression": "^1.7.0", @@ -61,6 +63,11 @@ "node-sass": "^5.0.0", "nodemon": "^2.0.6", "require-from-string": "^2.0.2", + "rollup": "^2.42.3", + "rollup-plugin-css-only": "^3.1.0", + "rollup-plugin-livereload": "^2.0.0", + "rollup-plugin-svelte": "^7.1.0", + "rollup-plugin-terser": "^7.0.2", "sass": "^1.32.8", "supertest": "^6.0.0", "svelte": "^3.35.0", diff --git a/src/TestApp.ts b/src/TestApp.ts index fa001c8..806f089 100644 --- a/src/TestApp.ts +++ b/src/TestApp.ts @@ -76,7 +76,7 @@ export default class TestApp extends Application { // Dynamic views and routes this.use(new NunjucksComponent(['test/views', 'views'])); - this.use(new FrontendToolsComponent('public', 'views', 'build')); + this.use(new FrontendToolsComponent('public', 'build')); this.use(new PreviousUrlComponent()); // Services diff --git a/src/components/FrontendToolsComponent.ts b/src/components/FrontendToolsComponent.ts index de2cca4..3f35181 100644 --- a/src/components/FrontendToolsComponent.ts +++ b/src/components/FrontendToolsComponent.ts @@ -1,4 +1,4 @@ -import {Router} from "express"; +import {Express, Router} from "express"; import * as fs from "fs"; import path from "path"; import config from "config"; @@ -6,53 +6,102 @@ import ApplicationComponent from "../ApplicationComponent"; import {logger} from "../Logger"; import {ServerError} from "../HttpError"; import * as crypto from "crypto"; -import {compile, preprocess} from "svelte/compiler"; import requireFromString from "require-from-string"; +import "svelte/register"; +import {compile, preprocess} from "svelte/compiler"; import {sveltePreprocess} from "svelte-preprocess/dist/autoProcess"; import chokidar from "chokidar"; import {CssResult} from "svelte/types/compiler/interfaces"; +import {PreRenderedChunk, rollup, RollupBuild, RollupOptions, RollupWatcher, RollupWatchOptions, watch} from "rollup"; +import svelte from "rollup-plugin-svelte"; +import resolve from "@rollup/plugin-node-resolve"; +import commonjs from "@rollup/plugin-commonjs"; +import {terser} from "rollup-plugin-terser"; +import cssOnlyRollupPlugin from "rollup-plugin-css-only"; +import livereloadRollupPlugin from "rollup-plugin-livereload"; const BACKEND_CODE_PREFIX = 'swaf.'; const COMPILED_SVELTE_EXTENSION = '.swafview'; export default class FrontendToolsComponent extends ApplicationComponent { - public static getSveltePreCompileSeparator(file: string): string { - return '\n---' + crypto.createHash('sha1').update(path.basename(path.resolve(file))).digest('base64') + '---\n'; + public static getSveltePreCompileSeparator(canonicalViewName: string): string { + return '\n---' + + crypto.createHash('sha1') + .update(path.basename(path.resolve(canonicalViewName))) + .digest('base64') + + '---\n'; } private content: Map = new Map(); + private readonly viewPaths: string[]; + private readonly svelteDevViewsPath: string; + + private readonly dependencyCache: Record> = {}; + private readonly backendCodeCache: Record = {}; + private readonly fileCache: Record = {}; + + private rollup?: RollupBuild | RollupWatcher; public constructor( private readonly publicAssetsPath: string, - private readonly svelteViewsPath: string, private readonly svelteOutputPath: string, + ...viewPaths: string[] ) { super(); + this.viewPaths = [ + ...viewPaths.map(p => path.resolve(p)), + path.resolve(__dirname, '../../../views'), + path.resolve(__dirname, '../../views'), + path.resolve(__dirname, '../views'), + ]; + this.svelteDevViewsPath = path.resolve('views'); if (!fs.existsSync(svelteOutputPath)) { fs.mkdirSync(svelteOutputPath); } } - public async start(): Promise { + public async start(app: Express): Promise { await this.cachePublicAssets(); await this.preCompileSvelteViews(); - const watcher = chokidar.watch(this.svelteViewsPath, {persistent: true}); + const watcher = chokidar.watch(this.svelteDevViewsPath, {persistent: true}); watcher.on('ready', () => { logger.debug('Watching svelte assets for changes'); watcher.on('add', (path) => { - this.preCompileSvelte(path) - .catch(logger.error); + if (path.endsWith('.svelte')) { + this.resetBundle() + .then(() => this.preCompileSvelte(path, true)) + .then(() => this.bundle(...Object.keys(this.backendCodeCache))) + .catch(err => logger.error(err)); + } }); watcher.on('change', (path) => { - this.preCompileSvelte(path) - .catch(logger.error); + if (path.endsWith('.svelte')) { + delete this.backendCodeCache[this.toCanonicalViewName(path)]; + this.preCompileSvelte(path, true) + .then(() => this.bundle(...Object.keys(this.backendCodeCache))) + .catch(err => logger.error(err)); + } }); }); + + app.engine('svelte', (path, options, callback) => { + this.renderSvelte(path, options as Record, callback) + .catch(err => callback(err)); + }); + app.set('views', this.viewPaths); + app.set('view engine', 'svelte'); + } + + public async stop(): Promise { + await this.resetBundle(); } private async cachePublicAssets(): Promise { @@ -66,11 +115,12 @@ export default class FrontendToolsComponent extends ApplicationComponent { private async preCompileSvelteViews(): Promise { logger.info('Pre-compiling svelte views...'); - await this.forEachFileInDirRecursively(this.svelteViewsPath, async file => { + await this.forEachFileInDirRecursively(this.svelteDevViewsPath, async file => { if (file.endsWith('.svelte')) { await this.preCompileSvelte(file); } }); + await this.bundle(...Object.keys(this.backendCodeCache)); } public async handle(router: Router): Promise { @@ -124,8 +174,12 @@ export default class FrontendToolsComponent extends ApplicationComponent { }); } - private async preCompileSvelte(file: string): Promise { - logger.debug('Pre-compiling', file); + private async preCompileSvelte(file: string, alsoCompileDependents: boolean = false): Promise { + file = path.relative('.', file); + const canonicalViewName = this.toCanonicalViewName(file); + const intermediateFile = path.join(this.svelteOutputPath, canonicalViewName); + + logger.debug(canonicalViewName + ' > ', 'Pre-compiling', file, '->', intermediateFile); const source = await new Promise((resolve, reject) => { fs.readFile(file, (err, data) => { if (err) return reject(err); @@ -134,54 +188,127 @@ export default class FrontendToolsComponent extends ApplicationComponent { }); }); - const {backendReplacedCode, backendLines} = this.replaceBackendCode(source); + const allBackendLines: string[] = []; + for (const dependency of this.resolveDependencies(source, canonicalViewName)) { + allBackendLines.push(...(await this.replaceBackendCode(dependency)).backendLines); + } - const preprocessed = await this.preprocessSvelte(backendReplacedCode, file); + const {backendReplacedCode, backendLines} = await this.replaceBackendCode(canonicalViewName, source); + allBackendLines.push(...backendLines); + + const preprocessedCode = await this.preProcessSvelte(backendReplacedCode, intermediateFile, canonicalViewName); // Server Side Render (initial HTML, no-js) - const ssr = this.compileSvelteSsr(preprocessed.code, file, preprocessed.sourcemap); + const ssr = this.compileSvelteSsr(preprocessedCode, intermediateFile, canonicalViewName); - // Actual svelte - const svelte = this.compileSvelteJS(preprocessed.code, preprocessed.sourcemap); - - const separator = FrontendToolsComponent.getSveltePreCompileSeparator(file); + const separator = FrontendToolsComponent.getSveltePreCompileSeparator(canonicalViewName); const finalCode = [ - [...backendLines.values()].join('\n'), + [...new Set(allBackendLines).values()].join('\n'), ssr.head, ssr.html, ssr.css.code, - ssr.css.map, - svelte.code, - svelte.map, ].join(separator); - const newFile = path.join(this.svelteOutputPath, path.basename(file) + COMPILED_SVELTE_EXTENSION); - await new Promise((resolve, reject) => fs.writeFile(newFile, finalCode, err => { + const swafViewFile = path.join(this.svelteOutputPath, canonicalViewName + COMPILED_SVELTE_EXTENSION); + await new Promise((resolve, reject) => { + fs.mkdir(path.dirname(swafViewFile), {recursive: true}, (err) => { + if (err) return reject(err); + resolve(); + }); + }); + await new Promise((resolve, reject) => fs.writeFile(swafViewFile, finalCode, err => { if (err) return reject(err); resolve(); })); + + if (alsoCompileDependents && Object.keys(this.dependencyCache).indexOf(canonicalViewName) >= 0) { + logger.debug(canonicalViewName + ' > ', 'Compiling dependents...'); + for (const dependent of [...this.dependencyCache[canonicalViewName]]) { + await this.preCompileSvelte(await this.resolveViewFromCanonicalName(dependent), true); + } + } } - private replaceBackendCode(code: string): { + private resolveDependencies(source: string, canonicalViewName: string): string[] { + const dependencies: string[] = []; + + for (const match of source.matchAll(/import .+ from ['"](.+?\.svelte)['"];/gm)) { + dependencies.push(path.join(path.dirname(canonicalViewName), match[1])); + } + + // Clear existing links from cache + for (const dependency of Object.keys(this.dependencyCache)) { + this.dependencyCache[dependency].delete(canonicalViewName); + } + + // Add new links to cache + for (const dependency of dependencies) { + if (Object.keys(this.dependencyCache).indexOf(dependency) < 0) { + this.dependencyCache[dependency] = new Set(); + } + this.dependencyCache[dependency].add(canonicalViewName); + } + + return dependencies; + } + + private async replaceBackendCode(canonicalViewName: string, code?: string): Promise<{ backendReplacedCode: string, backendLines: string[], - } { + }> { + // Cache + if (Object.keys(this.backendCodeCache).indexOf(canonicalViewName) >= 0) { + return this.backendCodeCache[canonicalViewName]; + } + + const outputFile = path.join(this.svelteOutputPath, canonicalViewName); + await new Promise((resolve, reject) => { + fs.mkdir(path.dirname(outputFile), {recursive: true}, (err) => { + if (err) return reject(err); + resolve(); + }); + }); + + // Read source file if code was not already provided + if (!code) { + const file = await this.resolveViewFromCanonicalName(canonicalViewName); + code = await new Promise((resolve, reject) => { + fs.readFile(file, (err, data) => { + if (err) return reject(err); + + resolve(data.toString()); + }); + }); + } + + // Skip replace if there is no swaf export if (code.indexOf(`export let swaf = {};`) < 0) { - return { + const generated = { backendReplacedCode: code, backendLines: [], }; + await new Promise((resolve, reject) => { + fs.writeFile(outputFile, generated.backendReplacedCode, (err) => { + if (err) return reject(err); + + resolve(); + }); + }); + this.backendCodeCache[canonicalViewName] = generated; + return generated; } + + let output = code; const backendLines = new Set(); let index = 0; - while ((index = code.indexOf(BACKEND_CODE_PREFIX, index + 1)) >= 0) { + while ((index = output.indexOf(BACKEND_CODE_PREFIX, index + 1)) >= 0) { // Escaping - if (index > 0 && code[index - 1] === '\\') { - const isEscapingEscaped = index > 1 && code[index - 2] === '\\'; - code = code.substring(0, index - 1 - (isEscapingEscaped ? 1 : 0)) + - code.substring(index, code.length); + if (index > 0 && output[index - 1] === '\\') { + const isEscapingEscaped: boolean = index > 1 && output[index - 2] === '\\'; + output = output.substring(0, index - 1 - (isEscapingEscaped ? 1 : 0)) + + output.substring(index, output.length); continue; } @@ -189,38 +316,50 @@ export default class FrontendToolsComponent extends ApplicationComponent { let endIndex = startIndex; let struct = 0; - while (endIndex < code.length) { - if (['(', '[', '{'].indexOf(code[endIndex]) >= 0) struct++; - if ([')', ']', '}'].indexOf(code[endIndex]) >= 0) { + while (endIndex < output.length) { + if (['(', '[', '{'].indexOf(output[endIndex]) >= 0) struct++; + if ([')', ']', '}'].indexOf(output[endIndex]) >= 0) { struct--; if (struct <= 0) { if (struct === 0) endIndex++; break; } } - if ([' ', '\n', '<'].indexOf(code[endIndex]) >= 0 && struct === 0) break; + if ([' ', '\n', '<'].indexOf(output[endIndex]) >= 0 && struct === 0) break; endIndex++; } - const backendLine = code.substring(startIndex, endIndex); + let backendLine = output.substring(startIndex, endIndex); + if (backendLine.match(/([^()]+)\((.+?)\)/)) { + backendLine = backendLine.replace(/([^()]+)\((.+?)\)/, "'$1', [$2]"); + } else { + backendLine = backendLine.replace(/([^()]+)/, "'$1'"); + } + backendLines.add(backendLine); - code = code.substring(0, index) + - 'swaf(`' + backendLine.replace(/([^\\])`/, '$1\\`') + '`)' + - code.substring(endIndex, code.length); + output = output.substring(0, index) + + 'swaf(' + backendLine + ')' + + output.substring(endIndex, output.length); } - logger.silly('Replaced backend code'); - - return { - backendReplacedCode: code, + const generated = { + backendReplacedCode: output, backendLines: [...backendLines], }; + await new Promise((resolve, reject) => { + fs.writeFile(outputFile, generated.backendReplacedCode, (err) => { + if (err) return reject(err); + + resolve(); + }); + }); + this.backendCodeCache[canonicalViewName] = generated; + + return generated; } - private async preprocessSvelte(code: string, filename: string): Promise<{ - code: string, - sourcemap?: SourceMap, - }> { + private async preProcessSvelte(code: string, filename: string, canonicalViewName: string): Promise { + logger.debug(canonicalViewName + ' > ', 'Preprocessing svelte', filename); const preprocessed = await preprocess( code, sveltePreprocess({ @@ -233,42 +372,249 @@ export default class FrontendToolsComponent extends ApplicationComponent { }, ); - return { - code: preprocessed.code, - sourcemap: preprocessed.map as (SourceMap | undefined), - }; + return preprocessed.code; } - private compileSvelteSsr(code: string, filename: string, sourcemap?: SourceMap): { + private compileSvelteSsr(code: string, filename: string, canonicalViewName: string): { head: string, css: CssResult, html: string, } { + logger.debug(canonicalViewName + ' > ', 'Compiling svelte ssr', filename); const svelteSsr = compile(code, { - dev: false, + dev: config.get('view.dev'), generate: 'ssr', format: 'cjs', - sourcemap: sourcemap, cssOutputFilename: filename + '.css', }); + const locals = this.getGlobals(); + return requireFromString(svelteSsr.js.code, filename).default.render({ - swaf: () => 'undefined', + swaf: (key: string, args?: unknown[]) => { + if (!args) return locals[key]; + + const f = locals[key]; + if (typeof f !== 'function') throw new Error(key + ' is not a function.'); + return f.call(locals, ...args); + }, }); } - private compileSvelteJS(code: string, sourcemap?: SourceMap): { - code: string, - map: SourceMap, - } { - const compiled = compile(code, { - dev: false, - hydratable: true, - sourcemap: sourcemap, + private async bundle(...canonicalViewNames: string[]): Promise { + logger.debug('Bundling'); + + const production = !config.get('view.dev'); + const options: RollupOptions | RollupWatchOptions = { + input: canonicalViewNames.map(name => path.join(this.svelteOutputPath, name)), + output: { + sourcemap: true, + format: 'es', + name: 'bundle', + dir: path.join(this.publicAssetsPath, 'js'), + entryFileNames: (chunkInfo: PreRenderedChunk): string => { + const name = chunkInfo.facadeModuleId ? + path.relative(this.svelteOutputPath, chunkInfo.facadeModuleId) : + chunkInfo.name; + return name + '.js'; + }, + }, + plugins: [ + svelte({ + preprocess: sveltePreprocess({ + typescript: { + tsconfigFile: 'tsconfig.views.json', + }, + }), + compilerOptions: { + // enable run-time checks when not in production + dev: !production, + hydratable: true, + }, + }), + // we'll extract any component CSS out into + // a separate file - better for performance + cssOnlyRollupPlugin({output: 'bundle.css'}), + + // If you have external dependencies installed from + // npm, you'll most likely need these plugins. In + // some cases you'll need additional configuration - + // consult the documentation for details: + // https://github.com/rollup/plugins/tree/master/packages/commonjs + resolve({ + browser: true, + dedupe: ['svelte'], + }), + commonjs(), + ], + watch: { + buildDelay: 1000, + clearScreen: false, + }, + }; + + if (production) { + // If we're building for production (npm run build + // instead of npm run dev), minify + options.plugins?.push(terser()); + } else { + // Watch the `public` directory and refresh the + // browser on changes when not in production + const plugin = livereloadRollupPlugin('public'); + options.plugins?.push(plugin); + } + + for (const name of canonicalViewNames) { + await new Promise((resolve, reject) => { + fs.mkdir(path.dirname(path.join(this.publicAssetsPath, 'js', name)), {recursive: true}, err => { + if (err) return reject(err); + resolve(); + }); + }); + } + + if (production) { + if (!this.rollup) { + this.rollup = await rollup(options); + + await this.rollup.write({ + format: 'es', + dir: path.join(this.publicAssetsPath, 'js'), + }); + } + } else { + if (!this.rollup) { + this.rollup = watch(options); + this.rollup.on('event', (event) => { + if (event.code === 'ERROR' || event.code === 'BUNDLE_END') { + event.result?.close().catch(err => logger.error(err)); + logger.debug('Bundled from watch'); + } + }); + } + } + } + + private async resetBundle(): Promise { + if (this.rollup) { + logger.debug('Stopping rollup...'); + await this.rollup.close(); + this.rollup = undefined; + } + } + + private async renderSvelte( + file: string, + locals: Record, + callback: (err: Error | null, rendered?: string) => void, + ): Promise { + const canonicalViewName = this.toCanonicalViewName(file); + const actualFile = path.join(this.svelteOutputPath, canonicalViewName + COMPILED_SVELTE_EXTENSION); + + if (!config.get('view.enable_asset_cache')) delete this.fileCache[actualFile]; + const view = await this.getFileContentsFromCache(actualFile); + + + const templateFile = await this.resolveViewFromCanonicalName('layouts/svelte_layout.html'); + + if (!config.get('view.enable_asset_cache')) delete this.fileCache[templateFile]; + let output = await this.getFileContentsFromCache(templateFile); + + + const [ + backendLines, + head, + html, + css, + ] = view.split(FrontendToolsComponent.getSveltePreCompileSeparator(canonicalViewName)); + + locals = Object.assign(this.getGlobals(), locals); + + const localMap: Record = {}; + backendLines.split('\n').forEach(line => { + const key = line.substring(1, line.indexOf(',') >= 0 ? line.indexOf(',') - 1 : line.length - 1); + if (line.indexOf('[') >= 0) { + const args = line.substring(line.indexOf('[') + 1, line.length - 1) + .split(/, *?/) + .map(arg => { + if (arg.startsWith("'")) return '"' + arg.substring(1, arg.length - 1) + '"'; + return arg; + }) + .map(arg => JSON.parse(arg)); + + const f = locals[key]; + if (typeof f !== 'function') throw new Error(key + ' is not a function.'); + localMap[`'${key}', ${JSON.stringify(args)}`] = f.call(locals, ...args); + } else { + localMap[`'${key}'`] = locals[key]; + } }); + const props = JSON.stringify(localMap); + + output = output.replace('%canonicalViewName%', canonicalViewName); + output = output.replace('%props%', props); + output = output.replace('%head%', head); + output = output.replace('%html%', html); + output = output.replace('%css%', css); + + callback(null, output); + } + + private async getFileContentsFromCache(file: string): Promise { + if (!this.fileCache[file]) { + this.fileCache[file] = await new Promise((resolve, reject) => { + fs.readFile(file, (err, data) => { + if (err) return reject(err); + resolve(data.toString()); + }); + }); + } + + return this.fileCache[file]; + } + + private toCanonicalViewName(file: string): string { + const resolvedFilePath = path.resolve(file); + + let canonicalViewName: string | null = null; + for (const viewPath of this.viewPaths) { + if (resolvedFilePath.startsWith(viewPath)) { + canonicalViewName = resolvedFilePath.substring(viewPath.length + 1); + } + } + + if (!canonicalViewName) throw new Error('view ' + file + ' not found'); + return canonicalViewName; + } + + private async resolveViewFromCanonicalName(canonicalName: string): Promise { + for (const viewPath of this.viewPaths) { + const tryPath = path.join(viewPath, canonicalName); + if (await new Promise((resolve, reject) => { + fs.stat(tryPath, (err) => { + if (err == null) { + resolve(true); + } else if (err.code === 'ENOENT') { + resolve(false); + } else { + reject(err); + } + }); + })) { + return tryPath; + } + } + + throw new Error('View not found from canonical name ' + canonicalName); + } + + /** + * TODO: add a way to add locals from anywhere + */ + private getGlobals(): Record { return { - code: compiled.js.code, - map: compiled.js.map, + route: (name: string) => 'unimplemented route ' + name, + direct: 'access', }; } } diff --git a/src/components/NunjucksComponent.ts b/src/components/NunjucksComponent.ts index 4381fb0..102a346 100644 --- a/src/components/NunjucksComponent.ts +++ b/src/components/NunjucksComponent.ts @@ -48,8 +48,12 @@ export default class NunjucksComponent extends ApplicationComponent { .addFilter('hex', (v: number) => { return v.toString(16); }); - this.environment.express(app); - app.set('view engine', 'njk'); + + app.engine('njk', (path, options, callback) => { + this.environment?.render(path, options, (err, res) => { + callback(err, res || undefined); + }); + }); } public async init(_router: Router): Promise { diff --git a/src/types/RollupPluginCssOnly.d.ts b/src/types/RollupPluginCssOnly.d.ts new file mode 100644 index 0000000..b02efc6 --- /dev/null +++ b/src/types/RollupPluginCssOnly.d.ts @@ -0,0 +1,8 @@ +declare module "rollup-plugin-css-only" { + import {Plugin} from "rollup"; + export default function cssOnlyRollupPlugin(options: CssOnlyPluginOptions): Plugin; + + export type CssOnlyPluginOptions = { + output: string; + }; +} diff --git a/src/types/RollupPluginLivereload.d.ts b/src/types/RollupPluginLivereload.d.ts new file mode 100644 index 0000000..2248137 --- /dev/null +++ b/src/types/RollupPluginLivereload.d.ts @@ -0,0 +1,4 @@ +declare module "rollup-plugin-livereload" { + import {Plugin} from "rollup"; + export default function livereloadRollupPlugin(path: string): Plugin; +} diff --git a/tsconfig.views.json b/tsconfig.views.json index 50b6338..84a7842 100644 --- a/tsconfig.views.json +++ b/tsconfig.views.json @@ -2,7 +2,7 @@ "extends": "@tsconfig/svelte/tsconfig.json", "compilerOptions": { "outDir": "public/js", - "rootDir": "./views", + "rootDir": "./build", "target": "ES6", "strict": true, "lib": [ diff --git a/views/home.svelte b/views/home.svelte index f6bfda9..f0647e9 100644 --- a/views/home.svelte +++ b/views/home.svelte @@ -1,29 +1,37 @@ - + +

Hello {count}!

+

Direct access: {swaf.direct}

+ {#if swaf.route('auth') === '/'} We're home! {:else} @@ -32,10 +40,14 @@

The route to auth is {swaf.route('auth')}

-

\$$.notcode

+

\swaf.notcode

-

{`{\\$$.escaped}`}

+

{`{\\swaf.escaped}`}

Blue!

+ + + +

Dependency test: {depTest}

diff --git a/views/home_dep.svelte b/views/home_dep.svelte new file mode 100644 index 0000000..c258474 --- /dev/null +++ b/views/home_dep.svelte @@ -0,0 +1,17 @@ + + + + + +

Simple dep test

+ +

Nested swaf call: {swaf.direct}

+

Nested swaf call: {swaf.route('auth')}

+

Nested swaf call: {swaf.route('home')}

diff --git a/views/layout.svelte b/views/layout.svelte new file mode 100644 index 0000000..c97cf66 --- /dev/null +++ b/views/layout.svelte @@ -0,0 +1,23 @@ + + + + + + + {title || 'Undefined title'} + {#if description} + + {/if} + + + + + + {#if refresh_after} + + {/if} + diff --git a/views/layouts/svelte_layout.html b/views/layouts/svelte_layout.html new file mode 100644 index 0000000..4502d74 --- /dev/null +++ b/views/layouts/svelte_layout.html @@ -0,0 +1,29 @@ + + + + %head% + + + + + +%html% + + diff --git a/yarn.lock b/yarn.lock index e0743fd..ba90024 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,7 +9,7 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== @@ -552,6 +552,48 @@ resolved "https://registry.yarnpkg.com/@phc/format/-/format-1.0.0.tgz#b5627003b3216dc4362125b13f48a4daa76680e4" integrity sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ== +"@rollup/plugin-commonjs@^17.1.0": + version "17.1.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-17.1.0.tgz#757ec88737dffa8aa913eb392fade2e45aef2a2d" + integrity sha512-PoMdXCw0ZyvjpCMT5aV4nkL0QywxP29sODQsSGeDpr/oI49Qq9tRtAsb/LbYbDzFlOydVEqHmmZWFtXJEAX9ew== + dependencies: + "@rollup/pluginutils" "^3.1.0" + commondir "^1.0.1" + estree-walker "^2.0.1" + glob "^7.1.6" + is-reference "^1.2.1" + magic-string "^0.25.7" + resolve "^1.17.0" + +"@rollup/plugin-node-resolve@^11.2.0": + version "11.2.1" + resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz#82aa59397a29cd4e13248b106e6a4a1880362a60" + integrity sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg== + dependencies: + "@rollup/pluginutils" "^3.1.0" + "@types/resolve" "1.17.1" + builtin-modules "^3.1.0" + deepmerge "^4.2.2" + is-module "^1.0.0" + resolve "^1.19.0" + +"@rollup/pluginutils@4": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.1.0.tgz#0dcc61c780e39257554feb7f77207dceca13c838" + integrity sha512-TrBhfJkFxA+ER+ew2U2/fHbebhLT/l/2pRk0hfj9KusXUuRXd2v0R58AfaZK9VXDQ4TogOSEmICVrQAA3zFnHQ== + dependencies: + estree-walker "^2.0.1" + picomatch "^2.2.2" + +"@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" + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -671,6 +713,16 @@ resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8" integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== +"@types/estree@*": + version "0.0.47" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.47.tgz#d7a51db20f0650efec24cd04994f523d93172ed4" + integrity sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg== + +"@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/express-serve-static-core@^4.17.18": version "4.17.19" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz#00acfc1632e729acac4f1530e9e16f6dd1508a1d" @@ -853,6 +905,13 @@ resolved "https://registry.yarnpkg.com/@types/require-from-string/-/require-from-string-1.2.0.tgz#c18cfc8a2c1a0259e5841d1fef2b5e9d01c64242" integrity sha512-5vE9WoOOC9/DoD3Zj53UISpM+5tSvh8k0mL4fe2zFI6vO715/W4IQ3EdVUrWVMrFi1/NZhyMvm2iKsDFkEGddQ== +"@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/sass@^1.16.0": version "1.16.0" resolved "https://registry.yarnpkg.com/@types/sass/-/sass-1.16.0.tgz#b41ac1c17fa68ffb57d43e2360486ef526b3d57d" @@ -1547,6 +1606,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.2.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887" + integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA== + bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -1727,7 +1791,7 @@ cheerio@^1.0.0-rc.3: parse5 "^6.0.1" parse5-htmlparser2-tree-adapter "^6.0.1" -"chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.2.2, chokidar@^3.4.1, chokidar@^3.5.1: +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.2.2, chokidar@^3.4.1, chokidar@^3.5.0, chokidar@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== @@ -1887,6 +1951,11 @@ commander@^5.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" @@ -2816,6 +2885,21 @@ estraverse@^5.1.0, estraverse@^5.2.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.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" + integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== + +estree-walker@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -3861,6 +3945,11 @@ is-installed-globally@^0.3.1: global-dirs "^2.0.1" is-path-inside "^3.0.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-negative-zero@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" @@ -3910,6 +3999,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.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== +is-reference@^1.2.1: + 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.2: version "1.1.2" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" @@ -4400,7 +4496,7 @@ jest-watcher@^26.6.2: jest-util "^26.6.2" string-length "^4.0.1" -jest-worker@^26.6.2: +jest-worker@^26.2.1, jest-worker@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== @@ -4638,6 +4734,21 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= +livereload-js@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-3.3.2.tgz#c88b009c6e466b15b91faa26fd7c99d620e12651" + integrity sha512-w677WnINxFkuixAoUEXOStewzLYGI76XVag+0JWMMEyjJQKs0ibWZMxkTlB96Lm3EjZ7IeOxVziBEbtxVQqQZA== + +livereload@^0.9.1: + version "0.9.3" + resolved "https://registry.yarnpkg.com/livereload/-/livereload-0.9.3.tgz#a714816375ed52471408bede8b49b2ee6a0c55b1" + integrity sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw== + dependencies: + chokidar "^3.5.0" + livereload-js "^3.3.1" + opts ">= 1.2.0" + ws "^7.4.3" + load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" @@ -4740,6 +4851,13 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +magic-string@^0.25.7: + 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" + maildev@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/maildev/-/maildev-1.1.0.tgz#8b6977f244373be00112c942ae15dd32f5c225c9" @@ -5705,6 +5823,11 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" +"opts@>= 1.2.0": + version "2.0.2" + resolved "https://registry.yarnpkg.com/opts/-/opts-2.0.2.tgz#a17e189fbbfee171da559edd8a42423bc5993ce1" + integrity sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg== + p-cancelable@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" @@ -5922,7 +6045,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.2.1, picomatch@^2.2.3: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d" integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg== @@ -6088,6 +6211,13 @@ random-bytes@~1.0.0: resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" integrity sha1-T2ih3Arli9P7lYSMMDJNt11kNgs= +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" + range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -6351,6 +6481,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" @@ -6373,7 +6508,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.10.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.18.1: +resolve@^1.10.0, resolve@^1.10.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.19.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -6412,6 +6547,52 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +rollup-plugin-css-only@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-css-only/-/rollup-plugin-css-only-3.1.0.tgz#6a701cc5b051c6b3f0961e69b108a9a118e1b1df" + integrity sha512-TYMOE5uoD76vpj+RTkQLzC9cQtbnJNktHPB507FzRWBVaofg7KhIqq1kGbcVOadARSozWF883Ho9KpSPKH8gqA== + dependencies: + "@rollup/pluginutils" "4" + +rollup-plugin-livereload@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-livereload/-/rollup-plugin-livereload-2.0.0.tgz#d3928d74e8cf2ae4286c5dd46b770fd3f3b82313" + integrity sha512-oC/8NqumGYuphkqrfszOHUUIwzKsaHBICw6QRwT5uD07gvePTS+HW+GFwu6f9K8W02CUuTvtIM9AWJrbj4wE1A== + dependencies: + livereload "^0.9.1" + +rollup-plugin-svelte@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-svelte/-/rollup-plugin-svelte-7.1.0.tgz#d45f2b92b1014be4eb46b55aa033fb9a9c65f04d" + integrity sha512-vopCUq3G+25sKjwF5VilIbiY6KCuMNHP1PFvx2Vr3REBNMDllKHFZN2B9jwwC+MqNc3UPKkjXnceLPEjTjXGXg== + dependencies: + require-relative "^0.8.7" + rollup-pluginutils "^2.8.2" + +rollup-plugin-terser@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" + integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ== + dependencies: + "@babel/code-frame" "^7.10.4" + jest-worker "^26.2.1" + serialize-javascript "^4.0.0" + terser "^5.0.0" + +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.42.3: + version "2.45.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.45.2.tgz#8fb85917c9f35605720e92328f3ccbfba6f78b48" + integrity sha512-kRRU7wXzFHUzBIv0GfoFFIN3m9oteY4uAsKllIpQDId5cfnkWF2J130l+27dzDju0E6MScKiV0ZM5Bw8m4blYQ== + optionalDependencies: + fsevents "~2.3.1" + rsvp@^4.8.4: version "4.8.5" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" @@ -6441,7 +6622,7 @@ safe-buffer@5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== -safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -6548,6 +6729,13 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" +serialize-javascript@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" + integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== + dependencies: + randombytes "^2.1.0" + serve-static@1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" @@ -6753,7 +6941,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.19, source-map-support@^0.5.6: +source-map-support@^0.5.17, source-map-support@^0.5.19, source-map-support@^0.5.6, source-map-support@~0.5.19: 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== @@ -6783,11 +6971,16 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@^0.7.3: +source-map@^0.7.3, source-map@~0.7.2: version "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: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + spawn-command@^0.0.2-1: version "0.0.2-1" resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" @@ -7170,6 +7363,15 @@ terminal-link@^2.0.0: ansi-escapes "^4.2.1" supports-hyperlinks "^2.0.0" +terser@^5.0.0: + version "5.6.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.6.1.tgz#a48eeac5300c0a09b36854bf90d9c26fb201973c" + integrity sha512-yv9YLFQQ+3ZqgWCUk+pvNJwgUTdlIxUk1WTN+RnaFJe2L7ipG2csPT0ra2XRm7Cs8cxN7QXmK1rFzEwYEQkzXw== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.19" + test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -7763,7 +7965,7 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@^7.2.3, ws@^7.4.4: +ws@^7.2.3, ws@^7.4.3, ws@^7.4.4: version "7.4.5" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.5.tgz#a484dd851e9beb6fdb420027e3885e8ce48986c1" integrity sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==