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/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/ diff --git a/package-lock.json b/package-lock.json index 395a810c..b0efd7fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.4", + "version": "0.1.6-next.13", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -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,22 +488,47 @@ } }, "@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 }, + "@elderjs/shortcodes": { + "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", - "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": { @@ -744,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", @@ -793,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 } } }, @@ -1437,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" @@ -1446,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", @@ -1510,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" @@ -1524,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", @@ -1533,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", @@ -1568,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", @@ -1578,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": { @@ -1589,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.6.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.2.tgz", - "integrity": "sha512-onlIwbaeqvZyniGPfdw/TEhKIh79pz66L1q06WUQqJLnAb6wbjvOtepLYTGHTqzdXgBYIE3ZdmqHDGsRsbBz7A==", - "dev": true + "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", @@ -1607,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", @@ -1634,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", @@ -1649,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": { @@ -1747,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": { @@ -1758,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", @@ -1777,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", @@ -1858,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", @@ -1880,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": { @@ -2164,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" } @@ -2196,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", @@ -2299,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", @@ -2383,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", @@ -2454,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", @@ -2480,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", @@ -2516,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": { @@ -2524,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", @@ -2551,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": { @@ -2644,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", @@ -2653,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", @@ -2706,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", @@ -2730,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", @@ -2746,7 +2943,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" } @@ -2825,9 +3021,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", @@ -2835,8 +3031,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", @@ -2914,13 +3111,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", @@ -2993,6 +3190,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", @@ -3005,6 +3208,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", @@ -3173,6 +3382,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 } } }, @@ -3186,12 +3401,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" } }, @@ -3202,12 +3417,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": { @@ -3219,6 +3442,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": { @@ -3245,12 +3476,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": { @@ -3259,6 +3498,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", @@ -3325,15 +3569,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" - } } } }, @@ -3621,7 +3856,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", @@ -3647,7 +3881,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" } @@ -3683,7 +3916,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" } @@ -3915,7 +4147,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": { @@ -3995,7 +4226,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" } @@ -4032,17 +4262,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": { @@ -4055,16 +4274,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" } }, @@ -4227,8 +4447,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", @@ -4315,6 +4534,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", @@ -4356,12 +4580,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", @@ -4414,11 +4632,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", @@ -4457,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": { @@ -4532,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", @@ -4550,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", @@ -4576,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", @@ -4945,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", @@ -4954,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", @@ -6516,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", @@ -6913,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", @@ -6962,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 } } }, @@ -6969,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", @@ -6979,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" } @@ -7055,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", @@ -7166,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 } } }, @@ -7180,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", @@ -7218,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", @@ -7274,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" @@ -7309,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": { @@ -7431,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": { @@ -7541,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": { @@ -7561,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": { @@ -7582,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": { @@ -7593,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": { @@ -7651,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", @@ -7714,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", @@ -7731,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", @@ -7771,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": { @@ -7873,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", @@ -8040,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" } @@ -8105,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": { @@ -8133,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.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", + "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", @@ -8160,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", @@ -8349,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", @@ -8415,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", @@ -8568,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", @@ -8588,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" @@ -8600,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", @@ -8736,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": { @@ -8746,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": { @@ -8757,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": { @@ -8775,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": { @@ -8815,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", @@ -8826,11 +9297,6 @@ "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.13.tgz", "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==" - }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", @@ -8891,6 +9357,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": { @@ -8940,8 +9433,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", @@ -8979,7 +9471,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" } @@ -9068,6 +9559,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": { @@ -9194,9 +9693,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" @@ -9316,9 +9815,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", @@ -9327,9 +9826,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 c627113d..84aafdf8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@elderjs/elderjs", - "version": "0.1.5", + "version": "0.1.6-next.13", "main": "./build/index.js", "types": "./build/index.d.ts", "engineStrict": true, @@ -21,34 +21,50 @@ "build/**/*" ], "peerDependencies": { - "svelte": "^3.24.1" + "svelte": "^3.24.1", + "intersection-observer": "^0.11.0", + "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", - "intersection-observer": "^0.11.0", "lodash.defaultsdeep": "^4.6.1", "nanoid": "^3.1.12", - "systemjs": "^6.5.0", + "rollup": "^2.21.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", + "svelte": "^3.25.1", "yup": "^0.29.3" }, "devDependencies": { "@types/fs-extra": "^9.0.1", - "@types/jest": "^26.0.12", - "@types/node": "^14.6.2", - "@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 66b02ff6..a09ed53c 100644 --- a/src/Elder.ts +++ b/src/Elder.ts @@ -17,10 +17,12 @@ import { validateHook, validateRoute, validatePlugin, + validateShortcode, permalinks, asyncForEach, getHashedSvelteComponents, getConfig, + prepareInlineShortcode, } from './utils'; import { RoutesOptions } from './routes/types'; import { HookOptions } from './hookInterface/types'; @@ -32,12 +34,12 @@ import { RequestsOptions, PluginOptions, ExcludesFalse, + ShortcodeDefs, } from './utils/types'; import createReadOnlyProxy from './utils/createReadOnlyProxy'; import workerBuild from './workerBuild'; import { inlineSvelteComponent } from './partialHydration/inlineSvelteComponent'; - -const getElderConfig = getConfig; +import elderJsShortcodes from './shortcodes'; class Elder { bootstrapComplete: Promise; @@ -54,10 +56,6 @@ class Elder { runHook: (string, Object) => Promise; - hookInterface: any; - - customProps: any; - query: QueryOptions; allRequests: Array; @@ -72,24 +70,25 @@ class Elder { builder: any; + hookInterface: any; + + shortcodes: ShortcodeDefs; + constructor({ context, worker = false }) { this.bootstrapComplete = new Promise((resolve) => { this.markBootstrapComplete = resolve; }); - const config = getConfig(context); - - const { srcFolder, buildFolder } = config.locations; + const config = getConfig(); this.settings = { ...config, server: context === 'server' && config[context], build: context === 'build' && config[context], - $$internal: { - hashedComponents: getHashedSvelteComponents(config), - }, }; + this.settings.$$internal.hashedComponents = getHashedSvelteComponents({ ...config.$$internal }); + if (context === 'build' && worker) { this.settings.worker = worker; } @@ -105,7 +104,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) { @@ -115,29 +114,24 @@ 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.rootDir, './node_modules/', pluginName); if (fs.existsSync(pkgPath)) { // eslint-disable-next-line import/no-dynamic-require const pluginPackageJson = require(path.resolve(pkgPath, './package.json')); 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; } } @@ -174,10 +168,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; @@ -225,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.$$internal.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}\``, ); } @@ -248,12 +234,29 @@ class Elder { pluginRoutes = { ...pluginRoutes, ...sanitizedRoute }; }); } + + if (plugin.shortcodes && plugin.shortcodes.length > 0) { + plugin.shortcodes.forEach((shortcode) => { + shortcode.$$meta = { + type: 'plugin', + addedBy: pluginName, + }; + shortcode.plugin = sanitizedPlugin; + pluginShortcodes.push(shortcode); + }); + } } + /** + * 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); - const routeHooks: Array = []; const userRoutes = Object.keys(userRoutesJsFile); userRoutes.forEach((routeName) => { @@ -264,20 +267,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. @@ -295,20 +284,19 @@ 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'); - - 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: { @@ -318,31 +306,13 @@ 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); } } + // validate hooks const elderJsHooks: Array = internalHooks.map((hook) => ({ ...hook, $$meta: { @@ -351,9 +321,8 @@ class Elder { }, })); - const allSupportedHooks = hookInterface; - - this.hooks = [...elderJsHooks, ...pluginHooks, ...routeHooks, ...hooksJs] + // validate hooks + this.hooks = [...elderJsHooks, ...pluginHooks, ...hooksJs] .map((hook) => validateHook(hook)) .filter((Boolean as any) as ExcludesFalse); @@ -361,20 +330,58 @@ 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? + /** + * Finalize Shortcodes + * Import User Shortcodes.js + * Validate Shortcodes + */ + + let shortcodesJs: ShortcodeDefs = []; + const shortcodeSrcPath = path.resolve(this.settings.srcDir, './shortcodes.js'); + + try { + const shortcodeReq = require(shortcodeSrcPath); + const shortcodes: ShortcodeDefs = shortcodeReq.default || shortcodeReq; + shortcodesJs = shortcodes.map((shortcode) => ({ + ...shortcode, + $$meta: { + type: 'shortcodes.js', + addedBy: 'shortcodes.js', + }, + })); + } catch (err) { + if (err.code === 'MODULE_NOT_FOUND') { + console.error( + `Could not load shortcodes file from ${shortcodeSrcPath}. They are not required, but could be useful.`, + ); + } else { + console.error(err); + } + } + + // validate shortcodes + this.shortcodes = [...elderJsShortcodes, ...pluginShortcodes, ...shortcodesJs] + .map((shortcode) => validateShortcode(shortcode)) + .filter((Boolean as any) as ExcludesFalse); + + /** + * + * Almost ready for customize hooks and bootstrap + * Just wire up the last few things. + */ this.data = {}; - this.hookInterface = allSupportedHooks; - this.customProps = {}; this.query = {}; this.allRequests = []; this.serverLookupObject = {}; this.errors = []; + this.hookInterface = hookInterface; this.helpers = { permalinks: permalinks({ routes: this.routes, settings: this.settings }), inlineSvelteComponent, + shortcode: prepareInlineShortcode({ settings: this.settings }), }; if (context === 'server') { @@ -385,15 +392,16 @@ 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, }); this.runHook('customizeHooks', this).then(async () => { - // we now have customProps and a new hookInterface. + // 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, + allSupportedHooks: hookInterface, settings: this.settings, }); @@ -405,10 +413,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; @@ -430,12 +438,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'; @@ -486,4 +503,4 @@ class Elder { } } -export { Elder, getElderConfig, build, partialHydration }; +export { Elder, build, partialHydration }; diff --git a/src/__tests__/Elder.spec.ts b/src/__tests__/Elder.spec.ts index 8e3ae1ad..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', @@ -114,6 +115,7 @@ describe('#Elder', () => { it('plugin found but invalid', async () => { jest.mock('../utils/validations', () => ({ validatePlugin: () => false, + validateShortcode: (i) => i, })); jest.mock('fs-extra', () => ({ existsSync: () => true, @@ -151,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', @@ -168,7 +169,9 @@ describe('#Elder', () => { }, }, server: { prefix: '/dev' }, - typescript: true, + distDir: 'test/public', + rootDir: 'test', + srcDir: 'test/src', }, }); }); @@ -178,6 +181,7 @@ describe('#Elder', () => { validatePlugin: (i) => i, validateHook: (i) => i, validateRoute: (i) => i, + validateShortcode: (i) => i, })); jest.mock('fs-extra', () => ({ existsSync: () => true, @@ -224,6 +228,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 9055187e..30c632d4 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 { @@ -14,26 +13,25 @@ Elder { "test-a": [Function], "test-b": [Function], }, + "shortcode": [Function], }, "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 +62,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", @@ -94,69 +92,47 @@ 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 [ "errors", - "request", "query", "helpers", "data", - "route", "settings", "allRequests", "routes", - "customProps", "req", "next", "res", + "request", ], "props": Array [ "errors", - "request", "query", "helpers", "data", - "route", "settings", "allRequests", "routes", - "customProps", "req", "next", "res", + "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.
", }, - 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.", @@ -234,6 +210,36 @@ Elder {

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", + "templateHtml", + "cssStack", + "headStack", + "customJsStack", + ], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "query", + "errors", + "cssStack", + "headStack", + "customJsStack", + "templateHtml", + "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.", @@ -294,9 +300,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 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.", @@ -382,6 +409,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.

@@ -397,7 +425,29 @@ Elder { "description": "Adds external helpers to helpers object", "hook": "bootstrap", "name": "elderAddExternalHelpers", - "priority": 100, + "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", + "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 { @@ -408,7 +458,7 @@ Elder { "description": "Adds to the head.", "hook": "stacks", "name": "elderAddMetaCharsetToHead", - "priority": 1, + "priority": 100, "run": [Function], }, Object { @@ -419,7 +469,7 @@ Elder { "description": "Adds to the head.", "hook": "stacks", "name": "elderAddMetaViewportToHead", - "priority": 10, + "priority": 90, "run": [Function], }, Object { @@ -430,7 +480,7 @@ Elder { "description": "Sets up the default polyfill for the intersection observer", "hook": "stacks", "name": "elderAddDefaultIntersectionObserver", - "priority": 1, + "priority": 100, "run": [Function], }, Object { @@ -444,6 +494,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": 50, + "run": [Function], + }, Object { "$$meta": Object { "addedBy": "elder.js", @@ -452,7 +513,7 @@ Elder { "description": "Log any errors to the console.", "hook": "error", "name": "elderConsoleLogErrors", - "priority": 100, + "priority": 1, "run": [Function], }, Object { @@ -463,7 +524,7 @@ Elder { "description": "Write the html output to public.", "hook": "requestComplete", "name": "elderWriteHtmlFileToPublic", - "priority": 100, + "priority": 1, "run": [Function], }, Object { @@ -499,26 +560,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", - "type": "hooks.js", - }, - "description": "just for testing", - "hook": "bootstrap", - "name": "test hook from file", - "run": [Function], - }, ], "markBootstrapComplete": [Function], "query": Object {}, @@ -560,28 +601,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", @@ -589,11 +625,22 @@ Elder { "htmlBucket": "elderguide.com", }, }, + "rootDir": "test", "server": Object { "prefix": "/dev", }, - "typescript": true, + "srcDir": "test/src", }, + "shortcodes": Array [ + Object { + "$$meta": Object { + "addedBy": "elder", + "type": "elder", + }, + "run": [Function], + "shortcode": "svelteComponent", + }, + ], } `; @@ -608,7 +655,6 @@ Elder { }, ], "bootstrapComplete": Promise {}, - "customProps": Object {}, "data": Object {}, "errors": Array [], "helpers": Object { @@ -618,26 +664,25 @@ Elder { "test-a": [Function], "test-b": [Function], }, + "shortcode": [Function], }, "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 +713,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", @@ -698,69 +743,47 @@ 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 [ "errors", - "request", "query", "helpers", "data", - "route", "settings", "allRequests", "routes", - "customProps", "req", "next", "res", + "request", ], "props": Array [ "errors", - "request", "query", "helpers", "data", - "route", "settings", "allRequests", "routes", - "customProps", "req", "next", "res", + "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.
", }, - 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.", @@ -838,6 +861,36 @@ Elder {

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", + "templateHtml", + "cssStack", + "headStack", + "customJsStack", + ], + "props": Array [ + "helpers", + "data", + "settings", + "request", + "query", + "errors", + "cssStack", + "headStack", + "customJsStack", + "templateHtml", + "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.", @@ -898,9 +951,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 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.", @@ -986,6 +1060,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.

@@ -1001,7 +1076,29 @@ Elder { "description": "Adds external helpers to helpers object", "hook": "bootstrap", "name": "elderAddExternalHelpers", - "priority": 100, + "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", + "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 { @@ -1012,7 +1109,7 @@ Elder { "description": "Adds to the head.", "hook": "stacks", "name": "elderAddMetaCharsetToHead", - "priority": 1, + "priority": 100, "run": [Function], }, Object { @@ -1023,7 +1120,7 @@ Elder { "description": "Adds to the head.", "hook": "stacks", "name": "elderAddMetaViewportToHead", - "priority": 10, + "priority": 90, "run": [Function], }, Object { @@ -1034,7 +1131,7 @@ Elder { "description": "Sets up the default polyfill for the intersection observer", "hook": "stacks", "name": "elderAddDefaultIntersectionObserver", - "priority": 1, + "priority": 100, "run": [Function], }, Object { @@ -1048,6 +1145,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": 50, + "run": [Function], + }, Object { "$$meta": Object { "addedBy": "elder.js", @@ -1056,7 +1164,7 @@ Elder { "description": "Log any errors to the console.", "hook": "error", "name": "elderConsoleLogErrors", - "priority": 100, + "priority": 1, "run": [Function], }, Object { @@ -1067,7 +1175,7 @@ Elder { "description": "Write the html output to public.", "hook": "requestComplete", "name": "elderWriteHtmlFileToPublic", - "priority": 100, + "priority": 1, "run": [Function], }, Object { @@ -1133,16 +1241,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", @@ -1202,28 +1300,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", @@ -1231,10 +1324,21 @@ Elder { "htmlBucket": "elderguide.com", }, }, + "rootDir": "test", "server": Object { "prefix": "/dev", }, - "typescript": true, + "srcDir": "test/src", }, + "shortcodes": Array [ + Object { + "$$meta": Object { + "addedBy": "elder", + "type": "elder", + }, + "run": [Function], + "shortcode": "svelteComponent", + }, + ], } `; diff --git a/src/__tests__/__snapshots__/externalHelpers.spec.ts.snap b/src/__tests__/__snapshots__/externalHelpers.spec.ts.snap index dbffa5b4..1483d886 100644 --- a/src/__tests__/__snapshots__/externalHelpers.spec.ts.snap +++ b/src/__tests__/__snapshots__/externalHelpers.spec.ts.snap @@ -1,25 +1,25 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`#externalHelpers works - buildHelpers 1`] = ` +exports[`#externalHelpers works - userHelpers is a function 1`] = ` Object { "userHelper": [Function], } `; -exports[`#externalHelpers works - buildHelpers 2`] = ` +exports[`#externalHelpers works - userHelpers is a function 2`] = ` Object { "userHelper": [Function], } `; -exports[`#externalHelpers works - userHelpers 1`] = ` +exports[`#externalHelpers works - userHelpers is not a function 1`] = ` Object { - "srcHelper": [MockFunction], + "userHelper": [Function], } `; -exports[`#externalHelpers works - userHelpers 2`] = ` +exports[`#externalHelpers works - userHelpers is not a function 2`] = ` Object { - "srcHelper": [MockFunction], + "userHelper": [Function], } `; diff --git a/src/__tests__/__snapshots__/hooks.spec.ts.snap b/src/__tests__/__snapshots__/hooks.spec.ts.snap index 69682f33..29d9458a 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": "", }, ], } @@ -76,28 +76,42 @@ Array [ "description": "Adds external helpers to helpers object", "hook": "bootstrap", "name": "elderAddExternalHelpers", - "priority": 100, + "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", + "name": "elderProcessShortcodes", + "priority": 50, "run": [Function], }, Object { "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 { @@ -107,18 +121,25 @@ Array [ "priority": 1, "run": [Function], }, + Object { + "description": "Creates an HTML string out of the Svelte layout and stacks.", + "hook": "compileHtml", + "name": "elderCompileHtml", + "priority": 50, + "run": [Function], + }, Object { "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__/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; diff --git a/src/__tests__/hooks.spec.ts b/src/__tests__/hooks.spec.ts index e79038c2..a390d307 100644 --- a/src/__tests__/hooks.spec.ts +++ b/src/__tests__/hooks.spec.ts @@ -2,10 +2,26 @@ 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', () => ({ resolve: (...strings) => strings.join('/').replace('./', '').replace('//', '/'), + posix: () => ({ dirname: () => '' }), })); jest.mock('fs-extra', () => ({ @@ -26,32 +42,118 @@ 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('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 === '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 () => { - 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 () => { - expect( - await hooks[3].run({ beforeHydrateStack: [], settings: { locations: { intersectionObserverPoly: 'foo' } } }), - ).toMatchSnapshot(); - expect(await hooks[3].run({ beforeHydrateStack: [], settings: {} })).toBe(null); + const hook = hooks.find((h) => h.name === 'elderAddDefaultIntersectionObserver'); + expect(await hook.run({ beforeHydrateStack: [] })).toMatchSnapshot(); }); it('elderAddSystemJs', async () => { + const hook = hooks.find((h) => h.name === 'elderAddSystemJs'); + expect(await hook.run({ beforeHydrateStack: [], headStack: [] })).toMatchSnapshot(); + }); + + it('elderCompileHtml', async () => { + const hook = hooks.find((h) => h.name === 'elderCompileHtml'); expect( - await hooks[4].run({ beforeHydrateStack: [], headStack: [], settings: { locations: { systemJs: 'foo' } } }), - ).toMatchSnapshot(); - expect(await hooks[4].run({ beforeHydrateStack: [], settings: {} })).toBe(null); + await hook.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); + const hook = hooks.find((h) => h.name === 'elderConsoleLogErrors'); + 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'); expect( - await hooks[6].run({ + await hook.run({ request: { permalink: '/foo' }, htmlString: 'string', errors: [], @@ -59,7 +161,7 @@ describe('#hooks', () => { }), ).toBe(null); expect( - await hooks[6].run({ + await hook.run({ request: { permalink: '/foo' }, htmlString: 'string', errors: [], @@ -67,7 +169,7 @@ describe('#hooks', () => { }), ).toBe(null); expect( - await hooks[6].run({ + await hook.run({ request: { permalink: '/foo' }, htmlString: 'string', errors: [], @@ -76,8 +178,9 @@ describe('#hooks', () => { ).toEqual({ errors: [new Error('Failed to write')] }); }); it('elderDisplayRequestTime', async () => { + const hook = hooks.find((h) => h.name === 'elderDisplayRequestTime'); expect( - await hooks[7].run({ + await hook.run({ request: { permalink: '/foo' }, timings: [ { name: 'foo', duration: 500 }, @@ -88,8 +191,9 @@ describe('#hooks', () => { ).toBe(undefined); }); it('elderShowParsedBuildTimes', async () => { + const hook = hooks.find((h) => h.name === 'elderShowParsedBuildTimes'); expect( - await hooks[8].run({ + await hook.run({ timings: [ [ { name: 'foo', duration: 500 }, @@ -105,8 +209,9 @@ describe('#hooks', () => { ).toBe(undefined); }); it('elderWriteBuildErrors', async () => { + const hook = hooks.find((h) => h.name === 'elderWriteBuildErrors'); expect( - await hooks[9].run({ + await hook.run({ errors: ['error1', 'error2'], settings: { debug: { performance: true } }, }), 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}', + }); + }); +}); diff --git a/src/build/__tests__/build.spec.ts b/src/build/__tests__/build.spec.ts index 1b64cf36..cfca0428 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', () => ({ @@ -86,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']); } @@ -137,6 +142,7 @@ describe('#build', () => { sent.push(i); return true; }, + exit: () => '' as never, }; // eslint-disable-next-line global-require @@ -249,17 +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(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([ - 'error-{"errors":["bornToFail","pushMeToErrors"]}', - '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/src/build/build.ts b/src/build/build.ts index 5218ce88..b16a0bb3 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 '../Elder'; +import getElderConfig from '../utils/getConfig'; +import { Elder } from '../Elder'; import shuffleArray from '../utils/shuffleArray'; import { BuildResult } from '../utils/types'; @@ -118,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 }); @@ -216,29 +218,41 @@ async function build(): Promise { } } - const time = Date.now() - start; - - if (time > 60000) { - console.log(`Build completed ${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`); - } 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; } + const time = Date.now() - start; + + if (time > 60000) { + 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 ${success ? 'Completed Successfully:' : 'Failed:'} Built ${totalRequests} pages in ${ + Math.round((time / 1000) * 100) / 100 + } seconds`, + ); + } else { + console.log( + `Build ${success ? 'Completed Successfully:' : 'Failed:'} Built ${totalRequests} pages in ${time}ms`, + ); + } + await mElder.runHook('buildComplete', { success, ...mElder, timings }); if (settings.debug.build) { console.log('Build complete. Workers:', cluster.workers); } + if (!success) { + throw new Error(`Build did not complete successfully.`); + } } else { process.on('message', async (msg) => { if (msg.cmd === 'start') { @@ -251,7 +265,10 @@ async function build(): Promise { }); } } catch (e) { - console.log(e); + if (e.message === 'Build did not complete successfully.') { + process.exit(1); + } + console.error(e); } } export default build; 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/hookInterface/hookEntityDefinitions.ts b/src/hookInterface/hookEntityDefinitions.ts index 5931d794..d521f86a 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.', @@ -34,6 +33,13 @@ 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. ", + 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 bb20cc75..da587ef9 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 @@ -53,56 +53,45 @@ export const hookInterface: Array = [ hook: 'middleware', props: [ 'errors', - 'request', 'query', 'helpers', 'data', - 'route', 'settings', 'allRequests', 'routes', - 'customProps', 'req', 'next', 'res', + 'serverLookupObject', + 'runHook', + 'shortcodes', + 'request', ], mutable: [ 'errors', - 'request', 'query', 'helpers', 'data', - 'route', 'settings', 'allRequests', 'routes', - 'customProps', 'req', 'next', 'res', + 'request', ], 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.
`, location: 'prepareServer.ts', - experimental: true, - 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, + experimental: false, advanced: true, }, @@ -168,6 +157,31 @@ export const hookInterface: Array = [ advanced: true, }, + { + hook: 'shortcodes', + props: [ + 'helpers', + 'data', + 'settings', + 'request', + 'query', + 'errors', + 'cssStack', + 'headStack', + 'customJsStack', + 'templateHtml', + 'shortcodes', + 'allRequests', + ], + 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.

`, + location: 'Page.ts', + experimental: false, + advanced: true, + }, + { hook: 'stacks', props: [ @@ -207,13 +221,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'], @@ -260,7 +285,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 diff --git a/src/hookInterface/types.ts b/src/hookInterface/types.ts index 43988a0d..cd9a75e8 100644 --- a/src/hookInterface/types.ts +++ b/src/hookInterface/types.ts @@ -3,11 +3,12 @@ export type Hook = | 'bootstrap' | 'allRequests' | 'middleware' - | 'modifyCustomProps' | 'request' | 'data' + | 'shortcodes' | 'stacks' | 'head' + | 'compileHtml' | 'html' | 'requestComplete' | 'error' diff --git a/src/hooks.ts b/src/hooks.ts index c22a2e2d..6cd1e7b8 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -3,13 +3,15 @@ import fs from 'fs-extra'; 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 = [ { hook: 'bootstrap', name: 'elderAddExternalHelpers', description: 'Adds external helpers to helpers object', - priority: 100, + priority: 1, run: async ({ helpers, query, settings }) => { let additionalHelpers = {}; try { @@ -28,11 +30,132 @@ 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, + request, + }) => { + 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) { + let route = routes[requestObject.route]; + if (request && request.route) { + route = routes[request.route]; + } + const forPage = { + request: { ...requestObject, ...request }, + settings, + query, + helpers, + data, + 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', + 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, + templateHtml, + shortcodes, + allRequests, + }) => { + const ShortcodeParser = prepareShortcodeParser({ + shortcodes, + helpers, + data, + settings, + request, + query, + cssStack, + headStack, + customJsStack, + allRequests, + }); + + const html = await ShortcodeParser.parse(templateHtml); + + return { + templateHtml: html, + headStack, + cssStack, + customJsStack, + }; + }, + }, { hook: 'stacks', name: 'elderAddMetaCharsetToHead', description: `Adds to the head.`, - priority: 1, + priority: 100, run: async ({ headStack }) => { return { headStack: [ @@ -40,7 +163,7 @@ const hooks: Array = [ { source: 'elderAddMetaCharsetToHead', string: ``, - priority: 1, + priority: 100, }, ], }; @@ -50,7 +173,7 @@ const hooks: Array = [ hook: 'stacks', name: 'elderAddMetaViewportToHead', description: `Adds to the head.`, - priority: 10, + priority: 90, run: async ({ headStack }) => { return { headStack: [ @@ -58,7 +181,7 @@ const hooks: Array = [ { source: 'elderAddMetaViewportToHead', string: ``, - priority: 10, + priority: 90, }, ], }; @@ -68,33 +191,24 @@ const hooks: Array = [ hook: 'stacks', name: 'elderAddDefaultIntersectionObserver', description: 'Sets up the default polyfill for the intersection observer', - priority: 1, - run: async ({ beforeHydrateStack, settings }) => { - if (settings && settings.locations && {}.hasOwnProperty.call(settings.locations, 'intersectionObserverPoly')) { - if (settings.locations.intersectionObserverPoly) { - return { - beforeHydrateStack: [ - { - source: 'elderAddDefaultIntersectionObserver', - string: ``, - priority: 1, - }, - ...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, + ], + }; }, }, { @@ -102,54 +216,59 @@ 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: 2, - }, - ...beforeHydrateStack, - ], + run: async ({ beforeHydrateStack, headStack }) => { + return { + beforeHydrateStack: [ + { + source: 'elderAddSystemJs', + string: ``, + priority: 99, + }, + ...beforeHydrateStack, + ], - headStack: [ - { - source: 'elderAddSystemJs', - string: ``, - priority: 2, - }, - ...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, + ], + }; }, }, + { + hook: 'compileHtml', + name: 'elderCompileHtml', + description: 'Creates an HTML string out of the Svelte layout and stacks.', + priority: 50, + run: async ({ request, headString, footerString, layoutHtml }) => { + return { + htmlString: `${headString}${layoutHtml}${footerString}`, + }; + }, + }, + { hook: 'error', name: 'elderConsoleLogErrors', description: 'Log any errors to the console.', - priority: 100, - run: async ({ errors }) => { - console.error(errors); + priority: 1, + run: async ({ errors, request, settings }) => { + if (!settings.worker) { + console.error(request.permalink, errors); + } }, }, { 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`); + const file = path.resolve(settings.distDir, `.${request.permalink}/index.html`); try { fs.outputFileSync(file, htmlString); } catch (e) { @@ -198,9 +317,16 @@ 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`); - 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/index.ts b/src/index.ts index f9410c9a..813fcdee 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,11 @@ /* istanbul ignore file */ -export { configSchema, hookSchema, routeSchema, pluginSchema } from './utils/validations'; - -export { Elder, getElderConfig, build, partialHydration } from './Elder'; +export { configSchema, hookSchema, routeSchema, pluginSchema, shortcodeSchema } from './utils/validations'; +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/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(` { diff --git a/src/shortcodes.ts b/src/shortcodes.ts new file mode 100644 index 00000000..b9ed52db --- /dev/null +++ b/src/shortcodes.ts @@ -0,0 +1,41 @@ +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.`); + + 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: parsedProps, + options: parsedOptions, + }), + }; + }, + $$meta: { + addedBy: 'elder', + type: 'elder', + }, + }, +]; + +export default shortcodes; diff --git a/src/utils/Page.ts b/src/utils/Page.ts index dd3cdc4f..9a021746 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'; @@ -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'); @@ -35,64 +38,57 @@ const buildPage = async (page) => { // start building templates page.perf.start('html.template'); - - // template building starts here - - const routeHTML = page.route.templateComponent({ + page.templateHtml = page.route.templateComponent({ 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'); + await page.runHook('shortcodes', page); + page.perf.start('html.layout'); - const layoutHtml = page.route.layout({ + page.layoutHtml = page.route.layout({ page, props: { data: page.data, helpers: page.helpers, - settings: page.settings, - request: page.request, - routeHTML, + settings: createReadOnlyProxy(page.settings, 'settings', `${page.request.route}: Svelte Layout`), + request: createReadOnlyProxy(page.request, 'request', `${page.request.route}: Svelte Layout`), + templateHtml: page.templateHtml, }, }); page.perf.end('html.layout'); - // 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); @@ -108,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); } @@ -142,7 +137,11 @@ class Page { perf: any; - customProps: any; + layoutHtml: string; + + templateHtml: string; + + cssString: string; htmlString: string; @@ -158,19 +157,9 @@ class Page { footerStack: Stack; - constructor({ - request, - settings, - query, - helpers, - data, - route, - runHook, - allRequests, - routes, - errors, - customProps = {}, - }) { + shortcodes: ShortcodeDefs; + + constructor({ request, settings, query, helpers, data, route, runHook, allRequests, routes, errors, shortcodes }) { this.uid = getUniqueId(); perf(this); this.perf.start('page'); @@ -185,36 +174,30 @@ class Page { this.query = query; this.errors = [...errors]; this.routes = routes; - this.customProps = customProps; + this.cssString = ''; this.htmlString = ''; - this.headStack = []; this.cssStack = []; this.beforeHydrateStack = []; this.hydrateStack = []; this.customJsStack = []; this.footerStack = []; + this.shortcodes = shortcodes; this.processStack = prepareProcessStack(this); - - this.runHook('modifyCustomProps', 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/__tests__/Page.spec.ts b/src/utils/__tests__/Page.spec.ts index be9a71e5..6f27961b 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, @@ -202,49 +202,23 @@ describe('#Page', () => { routes, errors: [], runHook, + shortcodes: [], }; - const expectedOutput = ` - - - headStack - - -

- beforeHydrateStack - - customJsStack - footerStack - - `; - 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', + 'shortcodes', + '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 () => { - 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__/__snapshots__/Page.spec.ts.snap b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap index 269060ba..3bbf7734 100644 --- a/src/utils/__tests__/__snapshots__/Page.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/Page.spec.ts.snap @@ -28,8 +28,8 @@ Page { ], "beforeHydrateStack": Array [], "cssStack": Array [], + "cssString": "", "customJsStack": Array [], - "customProps": Object {}, "data": Object {}, "errors": Array [], "footerStack": Array [], @@ -176,7 +176,7 @@ Page { "debug": Object { "automagic": false, "build": false, - "hooks": false, + "hooks": true, "performance": false, "stacks": false, }, @@ -206,6 +206,7 @@ Page { "typescript": false, "worker": true, }, + "shortcodes": Array [], "uid": "xxxxxxxxxx", } `; @@ -236,48 +237,37 @@ Page { "type": "build", }, ], - "beforeHydrate": "beforeHydrateStack", "beforeHydrateStack": Array [], "cssStack": Array [], "cssString": "cssStack", - "customJs": "customJsStack", "customJsStack": Array [ "customJsStack", ], - "customProps": Object {}, "data": Object { "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 [ @@ -296,9 +286,6 @@ Page { Array [ "html.layout", ], - Array [ - "html.createHtmlString", - ], Array [ "page", ], @@ -328,10 +315,6 @@ Page { "type": "return", "value": undefined, }, - Object { - "type": "return", - "value": undefined, - }, ], }, "start": [MockFunction] { @@ -354,9 +337,6 @@ Page { Array [ "html.layout", ], - Array [ - "html.createHtmlString", - ], ], "results": Array [ Object { @@ -383,10 +363,6 @@ Page { "type": "return", "value": undefined, }, - Object { - "type": "return", - "value": undefined, - }, ], }, "stop": [MockFunction] { @@ -467,7 +443,6 @@ Page { }, "type": "build", }, - "routeHTML": undefined, "settings": Object { "$$internal": Object { "hashedComponents": Object { @@ -488,7 +463,7 @@ Page { "debug": Object { "automagic": false, "build": false, - "hooks": false, + "hooks": true, "performance": false, "stacks": false, }, @@ -518,6 +493,7 @@ Page { "typescript": false, "worker": true, }, + "templateHtml": undefined, }, }, ], @@ -575,7 +551,7 @@ Page { "debug": Object { "automagic": false, "build": false, - "hooks": false, + "hooks": true, "performance": false, "stacks": false, }, @@ -663,7 +639,7 @@ Page { "debug": Object { "automagic": false, "build": false, - "hooks": false, + "hooks": true, "performance": false, "stacks": false, }, @@ -693,7 +669,9 @@ Page { "typescript": false, "worker": true, }, - "styleTag": "", + "shortcodes": Array [], + "styleTag": "", + "templateHtml": undefined, "timings": Array [], "uid": "xxxxxxxxxx", } 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..54c3338f --- /dev/null +++ b/src/utils/__tests__/__snapshots__/getRollupConfig.spec.ts.snap @@ -0,0 +1,614 @@ +// 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", + "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", + "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__/__snapshots__/validations.spec.ts.snap b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap index 2d62d34b..dcac9b99 100644 --- a/src/utils/__tests__/__snapshots__/validations.spec.ts.snap +++ b/src/utils/__tests__/__snapshots__/validations.spec.ts.snap @@ -14,13 +14,15 @@ ObjectSchema { "_mutate": undefined, "_nodes": Array [ "plugins", - "typescript", + "shortcodes", "build", "server", "hooks", "debug", - "locations", - "siteUrl", + "srcDir", + "distDir", + "rootDir", + "origin", ], "_options": Object { "abortEarly": true, @@ -136,6 +138,7 @@ ObjectSchema { "automagic", "build", "performance", + "shortcodes", "hooks", "stacks", ], @@ -240,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, @@ -292,6 +322,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 {}, @@ -401,293 +458,32 @@ ObjectSchema { ], "type": "object", }, - "locations": ObjectSchema { + "origin": StringSchema { "_blacklist": RefSet { "list": Set {}, "refs": Map {}, }, "_conditions": Array [], - "_defaultDefault": [Function], + "_default": "", "_deps": Array [], - "_excludedEdges": Array [], "_exclusive": Object {}, - "_label": "Where various files are written and read from.", + "_label": "The domain your site is hosted on. https://yourdomain.com.", "_mutate": undefined, - "_nodes": Array [ - "intersectionObserverPoly", - "buildFolder", - "srcFolder", - "systemJs", - "svelte", - "public", - "assets", - ], "_options": Object { "abortEarly": true, "recursive": true, }, - "_type": "object", + "_type": "string", "_typeError": [Function], "_whitelist": RefSet { "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", - }, - }, "tests": Array [], "transforms": Array [ [Function], ], - "type": "object", + "type": "string", }, "plugins": ObjectSchema { "_blacklist": RefSet { @@ -720,6 +516,33 @@ ObjectSchema { ], "type": "object", }, + "rootDir": StringSchema { + "_blacklist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "_conditions": Array [], + "_default": "process.cwd()", + "_deps": Array [], + "_exclusive": Object {}, + "_label": "Here your package.json lives.", + "_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", + }, "server": ObjectSchema { "_blacklist": RefSet { "list": Set {}, @@ -779,49 +602,109 @@ ObjectSchema { ], "type": "object", }, - "siteUrl": StringSchema { + "shortcodes": ObjectSchema { "_blacklist": RefSet { "list": Set {}, "refs": Map {}, }, "_conditions": Array [], - "_default": "", + "_defaultDefault": [Function], "_deps": Array [], + "_excludedEdges": Array [], "_exclusive": Object {}, - "_label": "The domain your site is hosted on. https://yourdomain.com.", "_mutate": undefined, + "_nodes": Array [ + "closePattern", + "openPattern", + ], "_options": Object { "abortEarly": true, "recursive": true, }, - "_type": "string", + "_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": "string", + "type": "object", }, - "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 {}, @@ -831,7 +714,7 @@ ObjectSchema { "transforms": Array [ [Function], ], - "type": "boolean", + "type": "string", }, }, "tests": Array [], @@ -1074,7 +957,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, @@ -1151,6 +1034,7 @@ ObjectSchema { "_exclusive": Object {}, "_mutate": undefined, "_nodes": Array [ + "shortcodes", "config", "hooks", "routes", @@ -1346,6 +1230,35 @@ ObjectSchema { ], "type": "object", }, + "shortcodes": ArraySchema { + "_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, + }, + "_subType": undefined, + "_type": "array", + "_typeError": [Function], + "_whitelist": RefSet { + "list": Set {}, + "refs": Map {}, + }, + "innerType": undefined, + "tests": Array [], + "transforms": Array [ + [Function], + ], + "type": "array", + }, }, "tests": Array [], "transforms": Array [ @@ -1368,7 +1281,7 @@ ObjectSchema { "_exclusive": Object {}, "_mutate": undefined, "_nodes": Array [ - "hooks", + "data", "permalink", "all", "template", @@ -1414,34 +1327,30 @@ 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.", "_mutate": undefined, "_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__/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__/getRollupConfig.spec.ts b/src/utils/__tests__/getRollupConfig.spec.ts new file mode 100644 index 00000000..12b71cc6 --- /dev/null +++ b/src/utils/__tests__/getRollupConfig.spec.ts @@ -0,0 +1,376 @@ +/* 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('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({ + 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('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 + .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/']); + }); + + 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(); + }); +}); 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)); +}); diff --git a/src/utils/__tests__/index.spec.ts b/src/utils/__tests__/index.spec.ts index 3495c53e..4d039fdd 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', @@ -20,5 +21,7 @@ test('includes all', () => { 'prepareServer', 'prepareProcessStack', 'getConfig', + 'getRollupConfig', + 'prepareInlineShortcode', ]); }); diff --git a/src/utils/__tests__/prepareInlineShortcode.spec.ts b/src/utils/__tests__/prepareInlineShortcode.spec.ts new file mode 100644 index 00000000..317b89ae --- /dev/null +++ b/src/utils/__tests__/prepareInlineShortcode.spec.ts @@ -0,0 +1,68 @@ +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
"); + }); + + 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__/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/__tests__/prepareRunHook.spec.ts b/src/utils/__tests__/prepareRunHook.spec.ts index fd80215d..2116bfa6 100644 --- a/src/utils/__tests__/prepareRunHook.spec.ts +++ b/src/utils/__tests__/prepareRunHook.spec.ts @@ -72,29 +72,11 @@ 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 = []; - 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/utils/__tests__/prepareServer.spec.ts b/src/utils/__tests__/prepareServer.spec.ts index f07ebc6c..b46d44e8 100644 --- a/src/utils/__tests__/prepareServer.spec.ts +++ b/src/utils/__tests__/prepareServer.spec.ts @@ -1,117 +1,45 @@ import { prepareServer } from '../prepareServer'; -jest.mock('../Page'); - 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/', - }, - }, - settings: { server: { prefix: '/dev' } }, - query: { - db: { - db: {}, - pool: {}, - cnString: { - connectionString: 'postgresql://user:user@localhost:5099/db', - }, - }, + const nextMock = jest.fn(); + const prepServer = prepareServer({ + bootstrapComplete: Promise.resolve({ + runHook, + foo: 'bar', + bar: 'foo', + }), + }); + await prepServer( + { + desc: 'req', }, - 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(setHeaderMock).toHaveBeenCalledTimes(1); - 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(nextMock).toHaveBeenCalledTimes(2); // new call + ]); }); }); diff --git a/src/utils/__tests__/prepareShortcodeParser.spec.ts b/src/utils/__tests__/prepareShortcodeParser.spec.ts new file mode 100644 index 00000000..e57b339a --- /dev/null +++ b/src/utils/__tests__/prepareShortcodeParser.spec.ts @@ -0,0 +1,216 @@ +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: { + debug: { + stacks: true, + hooks: true, + build: true, + automagic: true, + shortcodes: true, + }, + 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: { + debug: { + stacks: true, + hooks: true, + build: true, + automagic: true, + shortcodes: true, + }, + 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: { + debug: { + stacks: true, + hooks: true, + build: true, + automagic: true, + shortcodes: true, + }, + 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: { + debug: { + stacks: true, + hooks: true, + build: true, + automagic: true, + shortcodes: true, + }, + 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: { + debug: { + stacks: true, + hooks: true, + build: true, + automagic: true, + shortcodes: true, + }, + 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/__tests__/svelteComponent.spec.ts b/src/utils/__tests__/svelteComponent.spec.ts index 3507b7c9..4d1e2ca6 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,8 +110,8 @@ describe('#svelteComponent', () => { string: ` function initdatepickerSwrzsrVDCd() { - System.import('public/dist/svelte/Datepicker.a1b2c3.js').then(({ default: App }) => { - new App({ target: document.getElementById('datepicker-SwrzsrVDCd'), hydrate: true, props: {"a":"b"} }); + 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 6b69a209..10b13477 100644 --- a/src/utils/__tests__/validations.spec.ts +++ b/src/utils/__tests__/validations.spec.ts @@ -26,34 +26,29 @@ describe('#validations', () => { numberOfWorkers: -1, shuffleRequests: false, }, + rootDir: 'process.cwd()', + srcDir: 'src', + distDir: 'public', debug: { automagic: false, build: false, hooks: false, performance: false, stacks: false, + shortcodes: false, }, hooks: { 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', - }, + origin: '', plugins: {}, server: { prefix: '', }, - typescript: false, + shortcodes: { + closePattern: '}}', + openPattern: '{{', + }, }; test('getDefaultConfig', () => { expect(getDefaultConfig()).toEqual(defaultConfig); @@ -82,6 +77,7 @@ describe('#validations', () => { all: jest.fn(), permalink: jest.fn(), hooks: [], + data: {}, }; expect(validateRoute(validRoute, 'Home')).toEqual(validRoute); // works with valid hook @@ -100,6 +96,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/getConfig.ts b/src/utils/getConfig.ts index dddcc825..9defce0f 100644 --- a/src/utils/getConfig.ts +++ b/src/utils/getConfig.ts @@ -1,12 +1,10 @@ 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 tsConfigExist from './tsConfigExist'; -function getConfig(context?: string): ConfigOptions { +function getConfig(): ConfigOptions { const explorerSync = cosmiconfigSync('elder'); const explorerSearch = explorerSync.search(); let loadedConfig = {}; @@ -17,45 +15,23 @@ function getConfig(context?: string): ConfigOptions { const defaultConfig = getDefaultConfig(); const config: ConfigOptions = defaultsDeep(loadedConfig, defaultConfig); - 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'`, - ); - } + 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}`); - if (!config.typescript) { - config.typescript = tsConfigExist(); - } + const ssrComponents = path.resolve(config.rootDir, './___ELDER___/compiled/'); + const clientComponents = path.resolve(config.distDir, './svelte/'); - 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' })); + config.$$internal = { + ssrComponents, + clientComponents, + }; - 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, - ); - } - } - } + if (config.origin === '') { + console.error( + `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.`, + ); } return config; diff --git a/src/utils/getHashedSvelteComponents.ts b/src/utils/getHashedSvelteComponents.ts index 54f943d8..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 = {}; @@ -11,12 +10,12 @@ let ready = false; * * @returns {Object} */ -const getHashedSvelteComponents = (config) => { +const getHashedSvelteComponents = ({ ssrComponents, clientComponents }) => { 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(`${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 new file mode 100644 index 00000000..d6cc783b --- /dev/null +++ b/src/utils/getRollupConfig.ts @@ -0,0 +1,311 @@ +/* eslint-disable no-lonely-if */ +// 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 '../index'; +import { ConfigOptions } from './types'; + +const production = process.env.NODE_ENV === 'production' || !process.env.ROLLUP_WATCH; + +export 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; +} + +export 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: true }), + css({ + ignore: true, + }), + production && terser(), + ], + }; + // if we are bundle splitting include them. + if (multiInputConfig) { + config.plugins.unshift(multiInputConfig); + } + + return config; +} + +export 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`); + 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.`); + + 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. + [ + ['./node_modules/intersection-observer/intersection-observer.js', './static/intersection-observer.js'], + ['./node_modules/systemjs/dist/s.min.js', './static/s.min.js'], + ].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) => { + const file = cv.replace(`${rootDir}/`, ''); + out.push( + createSSRConfig({ + input: file, + output: { + dir: ssrComponents, + format: 'cjs', + exports: 'auto', + }, + svelteConfig, + }), + ); + return out; + }, []); + + // SSR /layouts/ Svelte files. + const layouts = glob.sync(`${relSrcDir}/layouts/*.svelte`).reduce((out, cv) => { + const file = cv.replace(`${rootDir}/`, ''); + out.push( + createSSRConfig({ + input: file, + output: { + dir: ssrComponents, + format: 'cjs', + exports: 'auto', + }, + svelteConfig, + }), + ); + + return out; + }, []); + + const pluginPaths = getPluginPaths(elderConfig); + + configs = [...configs, ...templates, ...layouts]; + + if (production) { + // production build does bundle splitting, minification, and babel + + if (fs.existsSync(path.resolve(srcDir, `./components/`))) { + configs.push( + createBrowserConfig({ + input: [`${relSrcDir}/components/*/*.svelte`, `${relSrcDir}/components/*.svelte`], + output: { + dir: clientComponents, + entryFileNames: 'entry[name]-[hash].js', + sourcemap: !production, + format: 'system', + }, + multiInputConfig: multiInput({ + relative: `${relSrcDir}/components`, + transformOutputPath: (output) => `${path.basename(output)}`, + }), + svelteConfig, + }), + ); + configs.push( + createSSRConfig({ + input: [`${relSrcDir}/components/*/*.svelte`, `${relSrcDir}/components/*.svelte`], + output: { + dir: ssrComponents, + format: 'cjs', + exports: 'auto', + }, + multiInputConfig: multiInput({ + relative: `${relSrcDir}/components`, + transformOutputPath: (output) => `${path.basename(output)}`, + }), + 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')), + ...glob.sync(path.resolve(srcDir, './components/*.svelte')), + ].forEach((cv) => { + const file = cv.replace(`${rootDir}/`, ''); + configs.push( + createBrowserConfig({ + input: file, + output: { + dir: clientComponents, + entryFileNames: 'entry[name].js', + sourcemap: !production, + format: 'system', + }, + svelteConfig, + }), + ); + configs.push( + createSSRConfig({ + input: file, + output: { + dir: ssrComponents, + format: 'cjs', + exports: 'auto', + }, + svelteConfig, + }), + ); + }); + } + } + + 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; +} diff --git a/src/utils/index.ts b/src/utils/index.ts index a52fc33a..03e57508 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -13,9 +13,11 @@ 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'; +import getRollupConfig from './getRollupConfig'; +import prepareInlineShortcode from './prepareInlineShortcode'; export { asyncForEach, @@ -23,6 +25,7 @@ export { svelteComponent, getHashedSvelteComponents, getUniqueId, + validateShortcode, IntersectionObserver, Page, parseBuildPerf, @@ -36,4 +39,6 @@ export { prepareServer, prepareProcessStack, getConfig, + getRollupConfig, + prepareInlineShortcode, }; diff --git a/src/utils/prepareInlineShortcode.ts b/src/utils/prepareInlineShortcode.ts new file mode 100644 index 00000000..6d4b7858 --- /dev/null +++ b/src/utils/prepareInlineShortcode.ts @@ -0,0 +1,36 @@ +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 = `${openNoEscape}${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 += `/${closeNoEscape}`; + } else { + // close the open shortcode. + shortcode += closeNoEscape; + + // add content + shortcode += content; + + // close the shortcode. + shortcode += `${openNoEscape}/${name}${closeNoEscape}`; + } + + return shortcode; +}; + +export default prepareInlineShortcode; 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 8831502d..3263d521 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.`, @@ -38,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); @@ -50,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); - - if (!hookResponse) hookResponse = {}; + try { + let hookResponse = await hook.run(hookProps); - if (settings && settings.debug && settings.debug.hooks) { - console.log(`${hook.name} ran on ${hookName} and returned`, hookResponse); - } + if (!hookResponse) 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()); @@ -81,11 +78,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..0b0ad1f7 100644 --- a/src/utils/prepareServer.ts +++ b/src/utils/prepareServer.ts @@ -1,74 +1,16 @@ -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, - customProps, - } = 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, - customProps, - }; - - 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, + request: {}, + }); }; } diff --git a/src/utils/prepareShortcodeParser.ts b/src/utils/prepareShortcodeParser.ts new file mode 100644 index 00000000..db24d54b --- /dev/null +++ b/src/utils/prepareShortcodeParser.ts @@ -0,0 +1,99 @@ +import ShortcodeParser from '@elderjs/shortcodes'; +import createReadOnlyProxy from './createReadOnlyProxy'; +// TODO: Needs TS magic. + +function prepareShortcodeParser({ + shortcodes, + helpers, + data, + settings, + request, + query, + allRequests, + 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) => { + const shortcodeResponse = await shortcode.run({ + props, + content, + 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 (settings.debug.shortcodes) { + console.log(`${shortcode.shortcode} returned`, shortcodeResponse); + } + + 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 || ''; + } + + return shortcodeResponse || ''; + }); + }); + + return shortcodeParser; +} + +export default prepareShortcodeParser; diff --git a/src/utils/svelteComponent.ts b/src/utils/svelteComponent.ts index c3dab666..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'; @@ -29,28 +30,21 @@ 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, - '/', - ); - if (clientSvelteFolder.indexOf('.') === 0) clientSvelteFolder = clientSvelteFolder.substring(1); + const ssrComponent = path.resolve(page.settings.$$internal.ssrComponents, `./${cleanComponentName}.js`); + const clientSvelteFolder = page.settings.$$internal.clientComponents.replace(page.settings.distDir, ''); // 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`, }; } 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 }); @@ -114,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, )} }); });`; 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 60ece28a..b394aa8f 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; @@ -21,39 +21,57 @@ type DebugOptions = { performance: boolean; build: boolean; automagic: boolean; + shortcodes: boolean; }; -type LocationOptions = { +// type PathOptions = { +/* assets: string; public: string; svelte: SvelteOptions; systemJs: string; intersectionObserverPoly: string; srcFolder: string; - buildFolder: string; + buildFolder: string; +*/ + +// distDir: string; +// srcDir: string; +// rootDir: string; +// }; + +type Internal = { + hashedComponents?: {}; + ssrComponents: string; + clientComponents: string; }; export type ConfigOptions = { + distDir: string; + srcDir: string; + rootDir: string; + origin: string; + server: ServerOptions; build: BuildOptions; - locations: LocationOptions; + // paths: PathOptions; debug: DebugOptions; plugins?: any; hooks: { disable?: string[]; }; - typescript: boolean; + // typescript: boolean; worker: boolean; -}; - -type Internal = { - hashedComponents: {}; + shortcodes: { + openPattern: string; + closePattern: string; + }; + $$internal: Internal; }; export type SettingOptions = { server: boolean; build: boolean; - $$internal: Internal; }; export type QueryOptions = { @@ -102,6 +120,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; @@ -109,6 +146,7 @@ export type PluginOptions = { routes?: RoutesOptions; hooks: Array; config?: Object; + shortcodes?: ShortcodeDefs; }; // eslint-disable-next-line no-undef diff --git a/src/utils/validations.ts b/src/utils/validations.ts index 7024b357..6e8d4bf2 100644 --- a/src/utils/validations.ts +++ b/src/utils/validations.ts @@ -1,85 +1,52 @@ 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'; -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.'), - - 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)`, - ), +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.`), +}); - 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/)', - ), - }) +const configSchema = yup.object({ + 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() + .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() - .label('Where various files are written and read from.'), + .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. ", + ), debug: 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() @@ -117,7 +84,10 @@ 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.'), + }), plugins: yup.object().default({}).label('Used to define Elder.js plugins.'), }); @@ -143,11 +113,11 @@ 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() + data: yup + .mixed() .notRequired() - .default([]) - .label('An array of hooks. NOTE/TODO: These run on all routes, not just the one defined on.'), + .default({}) + .label(`Async/sync function that returns a JS object. Can also be a plain JS object.`), }); const pluginSchema = yup.object({ @@ -171,6 +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.array().notRequired().default([]).label('Array of shortcodes'), }); const hookSchema = yup @@ -192,7 +163,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() @@ -277,14 +248,35 @@ 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, hookSchema, routeSchema, pluginSchema, + shortcodeSchema, }; diff --git a/src/workerBuild.ts b/src/workerBuild.ts index a7bc4f96..24cdb9b9 100644 --- a/src/workerBuild.ts +++ b/src/workerBuild.ts @@ -9,8 +9,8 @@ async function workerBuild({ bootstrapComplete, workerRequests }) { runHook, routes: workerRoutes, errors, - customProps, allRequests, + shortcodes, } = await bootstrapComplete; // potential issue that since builds are split across processes, @@ -37,21 +37,24 @@ async function workerBuild({ bootstrapComplete, workerRequests }) { runHook, routes: workerRoutes, errors, - customProps, + 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 }); + response.push({ request, errors: buildErrors.map((e) => JSON.stringify(e, Object.getOwnPropertyNames(e))) }); bErrors.push({ request, errors: buildErrors }); } else { response.push(errs); } + // } catch (e) {} if (process.send) { process.send(response); diff --git a/yarn.lock b/yarn.lock index ea16c463..20258438 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" @@ -1594,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" @@ -1820,13 +1975,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 +2056,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 +2204,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 +2363,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 +2378,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 +2509,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 +2535,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 +2656,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 +2687,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 +2729,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 +2851,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 +2868,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 +2890,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 +3395,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 +3638,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 +3653,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 +3696,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 +4052,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 +4155,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 +4208,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 +4274,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 +4407,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 +4449,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 +4488,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 +4586,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 +4645,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 +4761,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 +4789,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 +4990,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 +5005,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 +5023,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"