diff --git a/.editorconfig b/.editorconfig index 81eba8c..f9366fa 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,4 +6,3 @@ indent_size = 4 charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -end_of_line = lf diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +node_modules diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..b41d7cf --- /dev/null +++ b/.eslintrc @@ -0,0 +1,23 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint", "prettier"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:prettier/recommended" + ], + "settings": { + "react": { + "pragma": "createElement" + } + }, + "rules": { + "@typescript-eslint/no-namespace": "off", + "@typescript-eslint/ban-types": "off", + "react/prop-types": "off", + "react/jsx-key": "off" + } +} diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml deleted file mode 100644 index bba8ffd..0000000 --- a/.forgejo/workflows/ci.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: CI - -on: - push: - branches: [main] - pull_request: - branches: [main] - workflow_dispatch: - -jobs: - check: - runs-on: node-24 - steps: - - uses: https://code.forgejo.org/actions/checkout@v4 - - name: Cache npm dependencies - uses: https://code.forgejo.org/actions/cache@v4 - with: - path: ~/.npm - key: node-24-${{ hashFiles('**/package-lock.json') }} - - run: npm ci - - run: npm run check - - build: - needs: check - strategy: - matrix: - node: [22, 24] - runs-on: node-${{ matrix.node }} - steps: - - uses: https://code.forgejo.org/actions/checkout@v4 - - name: Cache npm dependencies - uses: https://code.forgejo.org/actions/cache@v4 - with: - path: ~/.npm - key: node-${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }} - - run: npm ci - - run: npm run build - - run: npm test diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 6c309eb..0000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Ensure that git uses lf line-endings for text files. -* text=auto eol=lf diff --git a/.gitignore b/.gitignore index b116fef..d8dfd90 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ /dist -/.temp public/ node_modules/ diff --git a/.nvmrc b/.nvmrc index 3c03207..e1fcd1e 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -18 +lts/erbium diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..02d1ad0 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: node_js +node_js: + - node + - lts/* + - 14 + - 13 + - 12 + - 11 + - 10 diff --git a/CHANGELOG.md b/CHANGELOG.md index b242641..d5ad529 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,34 +1,5 @@ # Changelog -## [0.2.0](https://github.com/websnacksjs/websnacks/releases/tag/v0.2.0) (2021-02-28) - -### Features - -- add dangerouslySetInnerHTML attr ([#15](https://github.com/websnacksjs/websnacks/issues/15), [3f356dd](https://github.com/websnacksjs/websnacks/commit/3f356ddfeeb38e8a60c32d26c3e9e8715d0246c3)) - -### Misc - -- **BREAKING CHANGE** update node-watch optional dep to major v0.7.1 - -## [0.1.5](https://github.com/websnacksjs/websnacks/releases/tag/v0.1.5) (2020-06-14) - -### Bugfixes - -- stack size exceed error on purging module cache ([32eee9b](https://github.com/websnacksjs/websnacks/commit/32eee9b2e04475452905e3478f0fa2a21ad3ccf4)) - -## [0.1.4](https://github.com/websnacksjs/websnacks/releases/tag/v0.1.4) (2020-06-10) - -### Bugfixes - -- dev cmd didn't watch files due to import mangling ([4e44d83](https://github.com/websnacksjs/websnacks/commit/4e44d8369451e19af616a8c03c2ff7f4065b3f50)) -- dont require config file ([5520bb3](https://github.com/websnacksjs/websnacks/commit/5520bb3571189726df73a2945d9a6e7f5671e7ff)) - -## [0.1.3](https://github.com/websnacksjs/websnacks/releases/tag/v0.1.3) (2020-06-04) - -### Features - -- provide Fragment component ([#9](https://github.com/websnacksjs/websnacks/issues/9), [f1aca35](https://github.com/websnacksjs/websnacks/commit/f1aca350ed7e63e277fae7f9cc01039a29442bcb)) - ## [0.1.2](https://github.com/websnacksjs/websnacks/releases/tag/v0.1.2) (2020-06-03) ### Bugfixes diff --git a/LICENSE b/LICENSE index a612ad9..14e2f77 100644 --- a/LICENSE +++ b/LICENSE @@ -35,7 +35,7 @@ Mozilla Public License Version 2.0 means any form of the work other than Source Code Form. 1.7. "Larger Work" - means a work that combines Covered Software with other material, in + means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" diff --git a/README.md b/README.md index 8fcd5f3..1031410 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,20 @@ # websnacks: Minimal Dependency Server-Side JSX for Static Sites -[![NPM release](https://badges.git.theinnerlimit.ch/npm/v/@websnacksjs/websnacks?style=flat-square)](https://www.npmjs.com/package/@websnacksjs/websnacks "NPM release") -[![NPM](https://badges.git.theinnerlimit.ch/npm/l/@websnacksjs/websnacks?style=flat-square)](https://www.mozilla.org/en-US/MPL/2.0/FAQ/ "License info") -[![Build status](https://git.theinnerlimit.ch/websnacksjs/websnacks/badges/workflows/ci.yml/badge.svg?event=push&label=ci&style=flat-square)](https://git.theinnerlimit.ch/websnacksjs/websnacks/actions?workflow=ci.yml "CI status for main branch") -![Dependency status](https://badges.git.theinnerlimit.ch/librariesio/release/npm/%40websnacksjs%2Fwebsnacks?style=flat-square) +
+ +[![NPM release](https://img.shields.io/npm/v/@websnacksjs/websnacks)](https://www.npmjs.com/package/@websnacksjs/websnacks "NPM release") +[![NPM](https://img.shields.io/npm/l/@websnacksjs/websnacks)](https://www.mozilla.org/en-US/MPL/2.0/FAQ/ "License info") +[![Build status](https://img.shields.io/travis/websnacksjs/websnacks?style=flat-square)](https://travis-ci.org/websnacksjs/websnacks "Build status for master branch") + +
+ +
+ +[![Dependency status](https://img.shields.io/david/websnacksjs/websnacks?style=flat-square)](https://david-dm.org/websnacksjs/websnacks "Dependency status") +[![Optional dependency status](https://img.shields.io/david/optional/websnacksjs/websnacks?style=flat-square)](https://david-dm.org/websnacksjs/websnacks?type=optional "Optional dependency status") +[![Dev dependency status](https://img.shields.io/david/dev/websnacksjs/websnacks?style=flat-square)](https://david-dm.org/websnacksjs/websnacks?type=dev "Dev dependency status") + +
Develop fully static websites using typesafe JSX templates on the server without the complex build system and dependency management of server-side rendered React frameworks. diff --git a/biome.json b/biome.json deleted file mode 100644 index 0226807..0000000 --- a/biome.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "$schema": "https://biomejs.dev/schemas/2.4.14/schema.json", - "files": { - "includes": ["**", "!dist", "!node_modules", "!.temp"] - }, - "assist": { - "enabled": true, - "actions": { - "source": { - "organizeImports": "on" - } - } - }, - "formatter": { - "enabled": true - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true, - "style": { - "useShorthandFunctionType": "off" - }, - "correctness": { - "useJsxKeyInIterable": "off" - } - } - }, - "overrides": [ - { - "includes": ["test/**"], - "linter": { - "rules": { - "a11y": { - "useHtmlLang": "off" - } - } - } - } - ] -} diff --git a/examples/personal-site/components/header.tsx b/examples/personal-site/components/header.tsx index 7eb8d29..31cbc73 100644 --- a/examples/personal-site/components/header.tsx +++ b/examples/personal-site/components/header.tsx @@ -1,29 +1,25 @@ import { stylesheet } from "typestyle"; -import { - type Component, - // biome-ignore lint/correctness/noUnusedImports: required to support JSX - createElement, -} from "websnacks"; +import { Component, createElement } from "websnacks"; const styles = stylesheet({ - header: { - background: "#6c42bd", - color: "#fff", - padding: "32px", - textAlign: "center", - boxShadow: "0 1px 8px -3px #000", - }, - headline: { - fontSize: "28px", - }, + header: { + background: "#6c42bd", + color: "#fff", + padding: "32px", + textAlign: "center", + boxShadow: "0 1px 8px -3px #000", + }, + headline: { + fontSize: "28px", + }, }); export interface HeaderProps { - headline: string; + headline: string; } export const Header: Component = ({ headline }) => ( -
-

{headline}

-
+
+

{headline}

+
); diff --git a/examples/personal-site/components/layout.tsx b/examples/personal-site/components/layout.tsx index 9cdc3df..3ca9dbf 100644 --- a/examples/personal-site/components/layout.tsx +++ b/examples/personal-site/components/layout.tsx @@ -1,10 +1,6 @@ import { normalize } from "csstips"; import { stylesheet } from "typestyle"; -import { - type Component, - // biome-ignore lint/correctness/noUnusedImports: required to support JSX - createElement, -} from "websnacks"; +import { Component, createElement } from "websnacks"; import { stylesheetPath } from "../config"; import { Header } from "./header"; @@ -13,57 +9,60 @@ import { Navbar } from "./navbar"; normalize(); const styles = stylesheet({ - html: { - height: "100%", - }, - wrapper: { - height: "100%", - display: "flex", - flexDirection: "row", - margin: 0, - }, - main: { - flex: 1, - }, - mainBody: { - padding: "16px", - }, - navbar: { - display: "flex", - flex: "0 0 auto", - zIndex: 9, - }, + html: { + height: "100%", + }, + wrapper: { + height: "100%", + display: "flex", + flexDirection: "row", + margin: 0, + }, + main: { + flex: 1, + }, + mainBody: { + padding: "16px", + }, + navbar: { + display: "flex", + flex: "0 0 auto", + zIndex: 9, + }, }); const SITE_TITLE = "Example Site"; export interface LayoutProps { - headline?: string; + headline?: string; } export const Layout: Component = ({ children, headline }) => ( - - - - - {SITE_TITLE} - {headline && ` | ${headline}`} - - - - - + + + + + {SITE_TITLE} + {headline && ` | ${headline}`} + + + + + - -
- -
+ +
+ +
-
-
+
+
-
{children}
-
- - +
{children}
+
+ + ); diff --git a/examples/personal-site/components/navbar.tsx b/examples/personal-site/components/navbar.tsx index 5fc6997..044241d 100644 --- a/examples/personal-site/components/navbar.tsx +++ b/examples/personal-site/components/navbar.tsx @@ -1,47 +1,43 @@ import { stylesheet } from "typestyle"; -import { - type Component, - // biome-ignore lint/correctness/noUnusedImports: required to support JSX - createElement, -} from "websnacks"; +import { Component, createElement } from "websnacks"; const styles = stylesheet({ - navbar: { - minWidth: "140px", - borderRight: "1px solid #ddd", - background: "#fff", - }, - sectionTitle: { - color: "#333", - textAlign: "center", - borderBottom: "1px solid #333", - padding: "6px", - margin: "0 4px", - fontSize: "18px", - }, - linksList: { - padding: "3px 16px 0", - }, - linksListItem: { - padding: "6px", - }, + navbar: { + minWidth: "140px", + borderRight: "1px solid #ddd", + background: "#fff", + }, + sectionTitle: { + color: "#333", + textAlign: "center", + borderBottom: "1px solid #333", + padding: "6px", + margin: "0 4px", + fontSize: "18px", + }, + linksList: { + padding: "3px 16px 0", + }, + linksListItem: { + padding: "6px", + }, }); const links = [ - { title: "Home", href: "/" }, - { title: "Projects", href: "/projects" }, + { title: "Home", href: "/" }, + { title: "Projects", href: "/projects" }, ]; export const Navbar: Component = () => ( - ); diff --git a/examples/personal-site/package-lock.json b/examples/personal-site/package-lock.json index 8acf90d..2139edb 100644 --- a/examples/personal-site/package-lock.json +++ b/examples/personal-site/package-lock.json @@ -1,246 +1,1263 @@ { - "name": "websnacks-example-personal-site", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "websnacks-example-personal-site", - "dependencies": { - "csstips": "^1.2.0", - "ts-node": "^8.10.1", - "typestyle": "^2.1.0", - "websnacks": "../../" - } - }, - "../..": { - "name": "@websnacksjs/websnacks", - "version": "0.2.0", - "license": "MPL-2.0", - "bin": { - "websnacks": "bin/websnacks.js" - }, - "devDependencies": { - "@biomejs/biome": "2.4.14", - "@types/node": "~18", - "@types/ws": "^7.4.0", - "ts-node": "^10.9.2", - "typescript": "~4.9.5" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "node-watch": "^0.7.1", - "ws": "^7.4.3" - } - }, - "../../node_modules/@types/node": { - "version": "12.12.38", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.38.tgz", - "integrity": "sha512-75eLjX0pFuTcUXnnWmALMzzkYorjND0ezNEycaKesbUBg9eGZp4GHPuDmkRc4mQQvIpe29zrzATNRA6hkYqwmA==", - "dev": true - }, - "../../node_modules/@types/ws": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.2.4.tgz", - "integrity": "sha512-9S6Ask71vujkVyeEXKxjBSUV8ZUB0mjL5la4IncBoheu04bDaYyUKErh1BQcY9+WzOUOiKqz/OnpJHYckbMfNg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "../../node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "../../node_modules/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 - }, - "../../node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "../../node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "../../node_modules/node-watch": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.6.4.tgz", - "integrity": "sha512-cI6CHzivIFESe8djiK3Wh90CtWQBxLwMem8x8S+2GSvCvFgoMuOKVlfJtQ/2v3Afg3wOnHl/+tXotEs8z5vOrg==", - "optional": true - }, - "../../node_modules/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 - }, - "../../node_modules/source-map-support": { - "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, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "../../node_modules/ts-node": { - "version": "8.10.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.1.tgz", - "integrity": "sha512-bdNz1L4ekHiJul6SHtZWs1ujEKERJnHs4HxN7rjTyyVOFf3HaJ6sLqe6aPG62XTzAB/63pKRh5jTSWL0D7bsvw==", - "dev": true, - "dependencies": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - } - }, - "../../node_modules/typescript": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", - "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", - "dev": true - }, - "../../node_modules/ws": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.5.tgz", - "integrity": "sha512-C34cIU4+DB2vMyAbmEKossWq2ZQDr6QEyuuCzWrM9zfw1sGc0mYiJ0UnG9zzNykt49C2Fi34hvr2vssFQRS6EA==", - "optional": true - }, - "../../node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" - }, - "node_modules/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==" - }, - "node_modules/csstips": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/csstips/-/csstips-1.2.0.tgz", - "integrity": "sha512-2KgBibTljubrEuaiCNdJ0zcy6BmJck+J9YUufb+Hwz3T0XANLfevVIabHtCO9T5Zr2kHyvpT+0XM9vk44nmsZg==", - "peerDependencies": { - "typestyle": "^2.0.0" - } - }, - "node_modules/csstype": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.9.tgz", - "integrity": "sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==" - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/free-style": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/free-style/-/free-style-3.1.0.tgz", - "integrity": "sha512-vJujYSIyT30iDoaoeigNAxX4yB1RUrh+N2ZMhIElMr3BvCuGXOw7XNJMEEJkDUeamK2Rnb/IKFGKRKlTWIGRWA==" - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/ts-node": { - "version": "8.10.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.1.tgz", - "integrity": "sha512-bdNz1L4ekHiJul6SHtZWs1ujEKERJnHs4HxN7rjTyyVOFf3HaJ6sLqe6aPG62XTzAB/63pKRh5jTSWL0D7bsvw==", - "dependencies": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "engines": { - "node": ">=6.0.0" - }, - "peerDependencies": { - "typescript": ">=2.7" - } - }, - "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typestyle": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/typestyle/-/typestyle-2.1.0.tgz", - "integrity": "sha512-6uCYPdG4xWLeEcl9O0GtNFnNGhami+irKiLsXSuvWHC/aTS7wdj49WeikWAKN+xHN3b1hm+9v0svwwgSBhCsNA==", - "dependencies": { - "csstype": "2.6.9", - "free-style": "3.1.0" - } - }, - "node_modules/websnacks": { - "resolved": "../..", - "link": true - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "engines": { - "node": ">=6" - } - } - } + "name": "websnacks-example-personal-site", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, + "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==" + }, + "csstips": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/csstips/-/csstips-1.2.0.tgz", + "integrity": "sha512-2KgBibTljubrEuaiCNdJ0zcy6BmJck+J9YUufb+Hwz3T0XANLfevVIabHtCO9T5Zr2kHyvpT+0XM9vk44nmsZg==" + }, + "csstype": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.9.tgz", + "integrity": "sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==" + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, + "free-style": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/free-style/-/free-style-3.1.0.tgz", + "integrity": "sha512-vJujYSIyT30iDoaoeigNAxX4yB1RUrh+N2ZMhIElMr3BvCuGXOw7XNJMEEJkDUeamK2Rnb/IKFGKRKlTWIGRWA==" + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "ts-node": { + "version": "8.10.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.1.tgz", + "integrity": "sha512-bdNz1L4ekHiJul6SHtZWs1ujEKERJnHs4HxN7rjTyyVOFf3HaJ6sLqe6aPG62XTzAB/63pKRh5jTSWL0D7bsvw==", + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, + "typestyle": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/typestyle/-/typestyle-2.1.0.tgz", + "integrity": "sha512-6uCYPdG4xWLeEcl9O0GtNFnNGhami+irKiLsXSuvWHC/aTS7wdj49WeikWAKN+xHN3b1hm+9v0svwwgSBhCsNA==", + "requires": { + "csstype": "2.6.9", + "free-style": "3.1.0" + } + }, + "websnacks": { + "version": "file:../..", + "requires": { + "node-watch": "^0.6.3", + "ws": "^7.2.5" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", + "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==" + }, + "@babel/highlight": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "requires": { + "@babel/helper-validator-identifier": "^7.9.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==" + }, + "@types/json-schema": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", + "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==" + }, + "@types/node": { + "version": "12.12.38", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.38.tgz", + "integrity": "sha512-75eLjX0pFuTcUXnnWmALMzzkYorjND0ezNEycaKesbUBg9eGZp4GHPuDmkRc4mQQvIpe29zrzATNRA6hkYqwmA==" + }, + "@types/ws": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.2.4.tgz", + "integrity": "sha512-9S6Ask71vujkVyeEXKxjBSUV8ZUB0mjL5la4IncBoheu04bDaYyUKErh1BQcY9+WzOUOiKqz/OnpJHYckbMfNg==", + "requires": { + "@types/node": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.31.0.tgz", + "integrity": "sha512-iIC0Pb8qDaoit+m80Ln/aaeu9zKQdOLF4SHcGLarSeY1gurW6aU4JsOPMjKQwXlw70MvWKZQc6S2NamA8SJ/gg==", + "requires": { + "@typescript-eslint/experimental-utils": "2.31.0", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.31.0.tgz", + "integrity": "sha512-MI6IWkutLYQYTQgZ48IVnRXmLR/0Q6oAyJgiOror74arUMh7EWjJkADfirZhRsUMHeLJ85U2iySDwHTSnNi9vA==", + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.31.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.31.0.tgz", + "integrity": "sha512-uph+w6xUOlyV2DLSC6o+fBDzZ5i7+3/TxAsH4h3eC64tlga57oMb96vVlXoMwjR/nN+xyWlsnxtbDkB46M2EPQ==", + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.31.0", + "@typescript-eslint/typescript-estree": "2.31.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.31.0.tgz", + "integrity": "sha512-vxW149bXFXXuBrAak0eKHOzbcu9cvi6iNcJDzEtOkRwGHxJG15chiAQAwhLOsk+86p9GTr/TziYvw+H9kMaIgA==", + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^6.3.0", + "tsutils": "^3.17.1" + } + }, + "acorn": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==" + }, + "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==" + }, + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "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==", + "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==" + } + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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==" + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "csstype": { + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.10.tgz", + "integrity": "sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==" + }, + "csx": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/csx/-/csx-10.0.1.tgz", + "integrity": "sha512-eiumhK/Ke6KpcuaGqCcdfEW+M1R7dJBdsSeQaUq2cVpHXGe3WIQVEL7tlWUmgZlILGdPi7MqrbwXADmZg+uQgA==", + "requires": { + "csstype": "^2.5.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "requires": { + "esutils": "^2.0.2" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==" + } + } + }, + "eslint-config-prettier": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz", + "integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==", + "requires": { + "get-stdin": "^6.0.0" + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", + "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==" + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==" + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==" + }, + "free-style": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/free-style/-/free-style-3.1.0.tgz", + "integrity": "sha512-vJujYSIyT30iDoaoeigNAxX4yB1RUrh+N2ZMhIElMr3BvCuGXOw7XNJMEEJkDUeamK2Rnb/IKFGKRKlTWIGRWA==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==" + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "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==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "inquirer": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", + "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "node-watch": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.6.4.tgz", + "integrity": "sha512-cI6CHzivIFESe8djiK3Wh90CtWQBxLwMem8x8S+2GSvCvFgoMuOKVlfJtQ/2v3Afg3wOnHl/+tXotEs8z5vOrg==", + "optional": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==" + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + }, + "rxjs": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", + "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + } + } + }, + "strip-json-comments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "ts-node": { + "version": "8.10.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.1.tgz", + "integrity": "sha512-bdNz1L4ekHiJul6SHtZWs1ujEKERJnHs4HxN7rjTyyVOFf3HaJ6sLqe6aPG62XTzAB/63pKRh5jTSWL0D7bsvw==", + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "requires": { + "tslib": "^1.8.1" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + }, + "typescript": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==" + }, + "typestyle": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/typestyle/-/typestyle-2.1.0.tgz", + "integrity": "sha512-6uCYPdG4xWLeEcl9O0GtNFnNGhami+irKiLsXSuvWHC/aTS7wdj49WeikWAKN+xHN3b1hm+9v0svwwgSBhCsNA==", + "requires": { + "csstype": "2.6.9", + "free-style": "3.1.0" + }, + "dependencies": { + "csstype": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.9.tgz", + "integrity": "sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==" + } + } + }, + "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==", + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "requires": { + "mkdirp": "^0.5.1" + } + }, + "ws": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.5.tgz", + "integrity": "sha512-C34cIU4+DB2vMyAbmEKossWq2ZQDr6QEyuuCzWrM9zfw1sGc0mYiJ0UnG9zzNykt49C2Fi34hvr2vssFQRS6EA==", + "optional": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + } + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + } + } } diff --git a/examples/personal-site/package.json b/examples/personal-site/package.json index c703985..471d1cb 100644 --- a/examples/personal-site/package.json +++ b/examples/personal-site/package.json @@ -1,14 +1,13 @@ { - "name": "websnacks-example-personal-site", - "type": "module", - "scripts": { - "build": "websnacks -r ts-node/register build", - "dev": "websnacks -r ts-node/register dev" - }, - "dependencies": { - "csstips": "^1.2.0", - "ts-node": "^8.10.1", - "typestyle": "^2.1.0", - "websnacks": "../../" - } + "name": "websnacks-example-personal-site", + "scripts": { + "build": "websnacks -r ts-node/register build", + "dev": "websnacks -r ts-node/register dev" + }, + "dependencies": { + "csstips": "^1.2.0", + "ts-node": "^8.10.1", + "typestyle": "^2.1.0", + "websnacks": "../../" + } } diff --git a/examples/personal-site/pages/index.tsx b/examples/personal-site/pages/index.tsx index 568fea6..d94ed6f 100644 --- a/examples/personal-site/pages/index.tsx +++ b/examples/personal-site/pages/index.tsx @@ -1,25 +1,22 @@ -import { - type Component, - // biome-ignore lint/correctness/noUnusedImports: required to support JSX - createElement, -} from "websnacks"; +import { Component, createElement } from "websnacks"; import { Layout } from "../components/layout"; export const page: Component = () => ( - -

- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur dapibus - condimentum mauris et egestas. Quisque orci nulla, consequat at erat - laoreet, malesuada sodales nisi. Sed in lorem semper lorem placerat - fermentum a id arcu. Curabitur non aliquam tellus, sed auctor lacus. Nunc - sit amet lectus ultrices, sodales nisl sit amet, luctus nisl. Nunc mollis - imperdiet quam, eget sollicitudin leo tincidunt vel. Duis felis dui, - imperdiet aliquam bibendum sed, auctor et dolor. Vivamus odio ipsum, - venenatis in felis sed, aliquam dictum turpis. Pellentesque pellentesque - consequat neque, id imperdiet diam molestie nec. Nullam ut vestibulum est. - Pellentesque orci urna, porta vel porta quis, semper ut enim. Donec sit - amet urna arcu. Nam tincidunt fermentum ligula a pharetra.{" "} -

-
+ +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur + dapibus condimentum mauris et egestas. Quisque orci nulla, consequat + at erat laoreet, malesuada sodales nisi. Sed in lorem semper lorem + placerat fermentum a id arcu. Curabitur non aliquam tellus, sed + auctor lacus. Nunc sit amet lectus ultrices, sodales nisl sit amet, + luctus nisl. Nunc mollis imperdiet quam, eget sollicitudin leo + tincidunt vel. Duis felis dui, imperdiet aliquam bibendum sed, + auctor et dolor. Vivamus odio ipsum, venenatis in felis sed, aliquam + dictum turpis. Pellentesque pellentesque consequat neque, id + imperdiet diam molestie nec. Nullam ut vestibulum est. Pellentesque + orci urna, porta vel porta quis, semper ut enim. Donec sit amet urna + arcu. Nam tincidunt fermentum ligula a pharetra.{" "} +

+
); diff --git a/examples/personal-site/pages/projects.tsx b/examples/personal-site/pages/projects.tsx index 8d3ef5d..0586649 100644 --- a/examples/personal-site/pages/projects.tsx +++ b/examples/personal-site/pages/projects.tsx @@ -1,30 +1,26 @@ import { stylesheet } from "typestyle"; -import { - type Component, - // biome-ignore lint/correctness/noUnusedImports: required to support JSX - createElement, -} from "websnacks"; +import { Component, createElement } from "websnacks"; import { Layout } from "../components/layout"; const styles = stylesheet({ - projectsGrid: { - display: "flex", - flexWrap: "wrap", - width: "25%", - }, + projectsGrid: { + display: "flex", + flexWrap: "wrap", + width: "25%", + }, }); export const page: Component = () => ( - -

Projects

+ +

Projects

-
-
Project 1
-
Project 2
-
Project 3
-
Project 4
-
Project 5
-
-
+
+
Project 1
+
Project 2
+
Project 3
+
Project 4
+
Project 5
+
+
); diff --git a/examples/personal-site/tsconfig.json b/examples/personal-site/tsconfig.json index 4c31835..1cfeaeb 100644 --- a/examples/personal-site/tsconfig.json +++ b/examples/personal-site/tsconfig.json @@ -1,17 +1,17 @@ { - "compilerOptions": { - "esModuleInterop": true, - "module": "CommonJS", - "moduleResolution": "node", - "jsx": "react", - "jsxFactory": "createElement", - "target": "ES2018", - "lib": ["ES2018"], - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["components/**/*", "pages/**/*"] + "compilerOptions": { + "esModuleInterop": true, + "module": "CommonJS", + "moduleResolution": "node", + "jsx": "react", + "jsxFactory": "createElement", + "target": "ES2018", + "lib": ["ES2018"], + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["components/**/*", "pages/**/*"] } diff --git a/examples/personal-site/websnacks.ts b/examples/personal-site/websnacks.ts index 6fb36e3..77dbf34 100644 --- a/examples/personal-site/websnacks.ts +++ b/examples/personal-site/websnacks.ts @@ -1,25 +1,26 @@ -import { promises as fs } from "node:fs"; -import * as path from "node:path"; -import type { Config } from "websnacks"; +import { promises as fs } from "fs"; +import * as path from "path"; +import { Config } from "websnacks"; import { stylesheetPath } from "./config"; -const _config: Config = { - // Watch additional files and folders for changes when the dev server is - // running. - watch: ["components/", "config.ts"], - // Hooks to execute after certain rendering events. Currently only - // afterSiteRender is supported. - hooks: { - async afterSiteRender({ outDir }): Promise { - // NOTE: we dynamically import typestyle so that the global style - // registry is properly updated once all pages are reloaded in - // dev. We could also create a typestyle object in config.ts, - // or even multiple objects to split up our styles into e.g. a - // critical-path.css and noncrticial.css. - const { getStyles } = await import("typestyle"); - const styles = getStyles(); - await fs.writeFile(path.join(outDir, stylesheetPath), styles); - }, - }, +const config: Config = { + // Watch additional files and folders for changes when the dev server is + // running. + watch: ["components/", "config.ts"], + // Hooks to execute after certain rendering events. Currently only + // afterSiteRender is supported. + hooks: { + async afterSiteRender({ outDir }): Promise { + // NOTE: we dynamically import typestyle so that the global style + // registry is properly updated once all pages are reloaded in + // dev. We could also create a typestyle object in config.ts, + // or even multiple objects to split up our styles into e.g. a + // critical-path.css and noncrticial.css. + const { getStyles } = await import("typestyle"); + const styles = getStyles(); + await fs.writeFile(path.join(outDir, stylesheetPath), styles); + }, + }, }; +export = config; diff --git a/package-lock.json b/package-lock.json index 13c88e6..b3a14ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,445 +1,1700 @@ { - "name": "@websnacksjs/websnacks", - "version": "0.2.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@websnacksjs/websnacks", - "version": "0.2.0", - "license": "MPL-2.0", - "bin": { - "websnacks": "bin/websnacks.js" - }, - "devDependencies": { - "@biomejs/biome": "2.4.14", - "@types/node": "~18", - "@types/ws": "^8.18.1", - "ts-node": "^10.9.2", - "typescript": "~4.9.5" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "node-watch": "^0.7.4", - "ws": "^8.20.0" - } - }, - "node_modules/@biomejs/biome": { - "version": "2.4.14", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.14.tgz", - "integrity": "sha512-TmAvxOEgrpLypzVGJ8FulIZnlyA9TxrO1hyqYrCz9r+bwma9xXxuLA5IuYnj55XQneFx460KjRbx6SWGLkg3bQ==", - "dev": true, - "license": "MIT OR Apache-2.0", - "bin": { - "biome": "bin/biome" - }, - "engines": { - "node": ">=14.21.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/biome" - }, - "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "2.4.14", - "@biomejs/cli-darwin-x64": "2.4.14", - "@biomejs/cli-linux-arm64": "2.4.14", - "@biomejs/cli-linux-arm64-musl": "2.4.14", - "@biomejs/cli-linux-x64": "2.4.14", - "@biomejs/cli-linux-x64-musl": "2.4.14", - "@biomejs/cli-win32-arm64": "2.4.14", - "@biomejs/cli-win32-x64": "2.4.14" - } - }, - "node_modules/@biomejs/cli-darwin-arm64": { - "version": "2.4.14", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.14.tgz", - "integrity": "sha512-XvgoE9XOawUOQPdmvs4J7wPhi/DLwSCGks3AlPJDmh34O0awRTqCED1HRcRDdpf1Zrp4us4MGOOdIxNpbqNF5Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-darwin-x64": { - "version": "2.4.14", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.14.tgz", - "integrity": "sha512-jE7hKBCFhOx3uUh+ZkWBfOHxAcILPfhFplNkuID/eZeSTLHzfZzoZxW8fbqY9xXRnPi7jGNAf1iPVR+0yWsM/Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-arm64": { - "version": "2.4.14", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.14.tgz", - "integrity": "sha512-2TELhZnW5RSLL063l9rc5xLpA0ZIw0Ccwy/0q384rvNAgFw3yI76bd59547yxowdQr5MNPET/xDLrLuvgSeeWQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "2.4.14", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.14.tgz", - "integrity": "sha512-/z+6gqAqqUQTHazwStxSXKHg9b8UvqBmDFRp+c4wYbq2KXhELQDon9EoC9RpmQ8JWkqQx/lIUy/cs+MhzDZp6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-x64": { - "version": "2.4.14", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.14.tgz", - "integrity": "sha512-zHrlQZDBDUz4OLAraYpWKcnLS6HOewBFWYOzY91d1ZjdqZwibOyb6BEu6WuWLugyo0P3riCmsbV9UqV1cSXwQg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "2.4.14", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.14.tgz", - "integrity": "sha512-R6BWgJdQOwW9ulJatuTVrQkjnODjqHZkKNOqb1sz++3Noe5LYd0i3PchnOBUCYAPHoPWHhjJqbdZlHEu0hpjdA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-win32-arm64": { - "version": "2.4.14", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.14.tgz", - "integrity": "sha512-M3EH5hqOI/F/FUA2u4xcLoUgmxd218mvuj/6JL7Hv2toQvr2/AdOvKSpGkoRuWFCtQPVa+ZqkEV3Q5xBA9+XSA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-win32-x64": { - "version": "2.4.14", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.14.tgz", - "integrity": "sha512-WL0EG5qE+EAKomGXbf2g6VnSKJhTL3tXC0QRzWRwA5VpjxNYa6H4P7ZWfymbGE4IhZZQi1KXQ2R0YjwInmz2fA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.19.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", - "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", - "dev": true, - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk/node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/node-watch": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.4.tgz", - "integrity": "sha512-RinNxoz4W1cep1b928fuFhvAQ5ag/+1UlMDV7rbyGthBIgsiEouS4kvRayvvboxii4m8eolKOIBo3OjDqbc+uQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - } - } + "name": "@websnacksjs/websnacks", + "version": "0.1.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", + "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.1" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", + "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", + "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.1", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@babel/runtime-corejs3": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.10.2.tgz", + "integrity": "sha512-+a2M/u7r15o3dV1NEizr9bRi+KUVnrs/qYxF0Z06DAPx/4VCWaz1WA7EcbE+uqGgt39lp5akWGmHsTseIkHkHg==", + "dev": true, + "requires": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.4" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", + "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==", + "dev": true + }, + "@types/node": { + "version": "10.17.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.24.tgz", + "integrity": "sha512-5SCfvCxV74kzR3uWgTYiGxrd69TbT1I6+cMx1A5kEly/IVveJBimtAMlXiEyVFn5DvUFewQWxOOiJhlxeQwxgA==", + "dev": true + }, + "@types/ws": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.2.4.tgz", + "integrity": "sha512-9S6Ask71vujkVyeEXKxjBSUV8ZUB0mjL5la4IncBoheu04bDaYyUKErh1BQcY9+WzOUOiKqz/OnpJHYckbMfNg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.1.0.tgz", + "integrity": "sha512-D52KwdgkjYc+fmTZKW7CZpH5ZBJREJKZXRrveMiRCmlzZ+Rw9wRVJ1JAmHQ9b/+Ehy1ZeaylofDB9wwXUt83wg==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "3.1.0", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.1.0.tgz", + "integrity": "sha512-Zf8JVC2K1svqPIk1CB/ehCiWPaERJBBokbMfNTNRczCbQSlQXaXtO/7OfYz9wZaecNvdSvVADt6/XQuIxhC79w==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "3.1.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.1.0.tgz", + "integrity": "sha512-NcDSJK8qTA2tPfyGiPes9HtVKLbksmuYjlgGAUs7Ld2K0swdWibnCq9IJx9kJN8JJdgUJSorFiGaPHBgH81F/Q==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "3.1.0", + "@typescript-eslint/typescript-estree": "3.1.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "@typescript-eslint/typescript-estree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.1.0.tgz", + "integrity": "sha512-+4nfYauqeQvK55PgFrmBWFVYb6IskLyOosYEmhH3mSVhfBp9AIJnjExdgDmKWoOBHRcPM8Ihfm2BFpZf0euUZQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + } + }, + "acorn": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.2.0.tgz", + "integrity": "sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==", + "dev": true + }, + "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==", + "dev": true + }, + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "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 + } + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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 + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "core-js-pure": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz", + "integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "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.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.1.0.tgz", + "integrity": "sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0", + "eslint-visitor-keys": "^1.1.0", + "espree": "^7.0.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-config-prettier": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz", + "integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + } + }, + "eslint-plugin-prettier": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.3.tgz", + "integrity": "sha512-+HG5jmu/dN3ZV3T6eCD7a4BlAySdN7mLIbJYo0z1cFQuI+r2DiTJEFeF68ots93PsnrMxbzIZ2S/ieX+mkrBeQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-plugin-react": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.20.0.tgz", + "integrity": "sha512-rqe1abd0vxMjmbPngo4NaYxTcR3Y4Hrmc/jg4T+sYz63yqlmJRknpEQfmWY+eDWPuMmix6iUIK+mv0zExjeLgA==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.2.3", + "object.entries": "^1.1.1", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.15.1", + "string.prototype.matchall": "^4.0.2", + "xregexp": "^4.3.0" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + } + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", + "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.0.0.tgz", + "integrity": "sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", + "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "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" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "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 + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "inquirer": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", + "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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 + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "internal-slot": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz", + "integrity": "sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==", + "dev": true, + "requires": { + "es-abstract": "^1.17.0-next.1", + "has": "^1.0.3", + "side-channel": "^1.0.2" + } + }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "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 + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "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-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "jsx-ast-utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.3.0.tgz", + "integrity": "sha512-3HNoc7nZ1hpZIKB3hJ7BlFRkzCx2BynRtfSwbkqZdpRdvAPsGMnzclPwrvDBS7/lalHTj21NwIeaEpysHBOudg==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "object.assign": "^4.1.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "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 + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-watch": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.6.4.tgz", + "integrity": "sha512-cI6CHzivIFESe8djiK3Wh90CtWQBxLwMem8x8S+2GSvCvFgoMuOKVlfJtQ/2v3Afg3wOnHl/+tXotEs8z5vOrg==", + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", + "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "has": "^1.0.3" + } + }, + "object.fromentries": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.2.tgz", + "integrity": "sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "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 + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz", + "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", + "dev": true + }, + "regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "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" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "rxjs": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", + "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz", + "integrity": "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==", + "dev": true, + "requires": { + "es-abstract": "^1.17.0-next.1", + "object-inspect": "^1.7.0" + } + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, + "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 + }, + "source-map-support": { + "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" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "string.prototype.matchall": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz", + "integrity": "sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "has-symbols": "^1.0.1", + "internal-slot": "^1.0.2", + "regexp.prototype.flags": "^1.3.0", + "side-channel": "^1.0.2" + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "ts-node": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", + "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typescript": { + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz", + "integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, + "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" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "ws": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz", + "integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==", + "optional": true + }, + "xregexp": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz", + "integrity": "sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==", + "dev": true, + "requires": { + "@babel/runtime-corejs3": "^7.8.3" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } } diff --git a/package.json b/package.json index 521f7ab..063bb8a 100644 --- a/package.json +++ b/package.json @@ -1,49 +1,51 @@ { - "name": "@websnacksjs/websnacks", - "description": "Minimal dependency server-side JSX for static sites", - "version": "0.2.0", - "author": { - "name": "M. George Hansen", - "email": "mgeorge@technopolitica.com" - }, - "license": "MPL-2.0", - "repository": "github:websnacksjs/websnacks", - "engines": { - "node": ">=18" - }, - "main": "dist/index.js", - "types": "types.d.ts", - "bin": "bin/websnacks.js", - "files": [ - "/bin/websnacks.js", - "/dist/**/*.js", - "/dist/**/*.d.ts", - "/dist/**/*.map", - "/src/**/*.ts", - "/index.d.ts" - ], - "scripts": { - "build": "tsc", - "check": "biome check .", - "clean": "ts-node scripts/clean.ts", - "prepublishOnly": "npm run reset && npm test", - "pretest": "npm run build", - "preversion": "npm run reset && npm test", - "release": "npm version", - "reset": "npm run clean && npm ci", - "test": "npm run test:unit && npm run test:e2e", - "test:unit": "cd test && ts-node --script-mode ./run-tests.ts", - "test:e2e": "cd test && ts-node --script-mode ./run-e2e.ts" - }, - "devDependencies": { - "@biomejs/biome": "2.4.14", - "@types/node": "~18", - "@types/ws": "^8.18.1", - "ts-node": "^10.9.2", - "typescript": "~4.9.5" - }, - "optionalDependencies": { - "node-watch": "^0.7.4", - "ws": "^8.20.0" - } + "name": "@websnacksjs/websnacks", + "description": "Minimal dependency server-side JSX for static sites", + "version": "0.1.2", + "author": { + "name": "M. George Hansen", + "email": "mgeorge@technopolitica.com" + }, + "license": "MPL-2.0", + "engines": { + "node": ">=10" + }, + "main": "dist/index.js", + "types": "types.d.ts", + "bin": "bin/websnacks.js", + "files": [ + "/bin/websnacks.js", + "/dist/**/*.js", + "/dist/**/*.d.ts", + "/dist/**/*.map", + "/src/**/*.ts", + "/index.d.ts" + ], + "scripts": { + "build": "tsc", + "clean": "ts-node scripts/clean.ts", + "prepublishOnly": "npm run reset && npm test", + "pretest": "npm run build", + "preversion": "npm run reset && npm test", + "release": "npm version", + "reset": "npm run clean && npm ci", + "test": "ts-node --project=test/tsconfig.json test/run-tests.ts" + }, + "devDependencies": { + "@types/node": "~10", + "@types/ws": "^7.2.4", + "@typescript-eslint/eslint-plugin": "^3.0.2", + "@typescript-eslint/parser": "^3.0.2", + "eslint": "^7.1.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-prettier": "^3.1.3", + "eslint-plugin-react": "^7.20.0", + "prettier": "^2.0.5", + "ts-node": "^8.10.2", + "typescript": "~3.9.3" + }, + "optionalDependencies": { + "node-watch": "^0.6.4", + "ws": "^7.3.0" + } } diff --git a/scripts/clean.ts b/scripts/clean.ts index e606197..f32b5d7 100644 --- a/scripts/clean.ts +++ b/scripts/clean.ts @@ -3,29 +3,27 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import * as fs from "node:fs"; -import * as path from "node:path"; +import * as fs from "fs"; +import * as path from "path"; const ROOT_DIR = path.resolve(__dirname, ".."); const DIST_DIR = path.join(ROOT_DIR, "dist"); -const TEST_DIR = path.join(ROOT_DIR, ".temp"); const rmdirRecursive = (dirPath: string): void => { - if (!fs.existsSync(dirPath)) { - return; - } - const entryNames = fs.readdirSync(dirPath); - for (const entryName of entryNames) { - const entryPath = path.join(dirPath, entryName); - const dirent = fs.lstatSync(entryPath); - if (dirent.isDirectory()) { - rmdirRecursive(entryPath); - } else { - fs.unlinkSync(entryPath); - } - } - fs.rmdirSync(dirPath); + if (!fs.existsSync(dirPath)) { + return; + } + const entryNames = fs.readdirSync(dirPath); + for (const entryName of entryNames) { + const entryPath = path.join(dirPath, entryName); + const dirent = fs.lstatSync(entryPath); + if (dirent.isDirectory()) { + rmdirRecursive(entryPath); + } else { + fs.unlinkSync(entryPath); + } + } + fs.rmdirSync(dirPath); }; rmdirRecursive(DIST_DIR); -rmdirRecursive(TEST_DIR); diff --git a/src/build.ts b/src/build.ts index 1f60755..aa676f6 100644 --- a/src/build.ts +++ b/src/build.ts @@ -3,78 +3,80 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { promises as fs } from "node:fs"; -import * as path from "node:path"; +import { promises as fs } from "fs"; +import * as path from "path"; -import type { Config, ConfigPaths } from "./config"; +import { Config, ConfigPaths } from "./config"; import { renderPage } from "./render"; -import { decacheModule, walkDir } from "./utils"; +import { purgeModuleAndDepsFromCache, walkDir } from "./utils"; const renderPagesToHtml = async ({ - pagesDir, - outDir, + pagesDir, + outDir, }: ConfigPaths): Promise => { - const deferred = []; - for await (const srcPath of walkDir(pagesDir)) { - const ext = path.extname(srcPath); - if (ext !== ".tsx") { - continue; - } + const deferred = []; + for await (const srcPath of walkDir(pagesDir)) { + const ext = path.extname(srcPath); + if (ext !== ".tsx") { + continue; + } - // Ensure that we don't cache page modules when running in dev server. - decacheModule(srcPath); - // eslint-disable-next-line @typescript-eslint/no-var-requires - const pageSrc = require(srcPath); - if (!("page" in pageSrc)) { - throw new Error( - `page source at ${srcPath} does not export a "page" variable`, - ); - } - let compiledHtml: string; - try { - compiledHtml = renderPage(pageSrc.page()); - } catch (error) { - throw new Error(`failed to compile ${srcPath}: ${error}`); - } - const relPath = path.relative(pagesDir, path.dirname(srcPath)); - let baseName = path.basename(srcPath, ".tsx"); - if (baseName === "index") { - baseName = ""; - } - const destPath = path.join(outDir, relPath, baseName, "index.html"); - deferred.push( - (async () => { - await fs.mkdir(path.dirname(destPath), { recursive: true }); - await fs.writeFile(destPath, compiledHtml); - })(), - ); - } - await Promise.all(deferred); + // Ensure that we don't cache page modules when running in dev server. + purgeModuleAndDepsFromCache(srcPath); + // eslint-disable-next-line @typescript-eslint/no-var-requires + const pageSrc = require(srcPath); + if (!("page" in pageSrc)) { + throw new Error( + `page source at ${srcPath} does not export a "page" variable` + ); + } + let compiledHtml; + try { + compiledHtml = renderPage(pageSrc.page()); + } catch (error) { + throw new Error( + `failed to compile ${srcPath}: ${error.stack ?? error}` + ); + } + const relPath = path.relative(pagesDir, path.dirname(srcPath)); + let baseName = path.basename(srcPath, ".tsx"); + if (baseName === "index") { + baseName = ""; + } + const destPath = path.join(outDir, relPath, baseName, "index.html"); + deferred.push( + (async () => { + await fs.mkdir(path.dirname(destPath), { recursive: true }); + await fs.writeFile(destPath, compiledHtml); + })() + ); + } + await Promise.all(deferred); }; const copyStaticAssets = async ({ - staticAssetsDir, - outDir, + staticAssetsDir, + outDir, }: ConfigPaths): Promise => { - try { - await fs.access(staticAssetsDir); - } catch (_error) { - // Static assets folder doesn't exist, so no-op. - return; - } + try { + await fs.access(staticAssetsDir); + } catch (error) { + // Static assets folder doesn't exist, so no-op. + return; + } - const deferred = []; - for await (const assetPath of walkDir(staticAssetsDir)) { - const relPath = path.relative(staticAssetsDir, assetPath); - const destPath = path.join(outDir, relPath); - deferred.push( - (async () => { - await fs.mkdir(path.dirname(destPath), { recursive: true }); - await fs.copyFile(assetPath, destPath); - })(), - ); - } - await Promise.all(deferred); + const deferred = []; + for await (const assetPath of walkDir(staticAssetsDir)) { + const relPath = path.relative(staticAssetsDir, assetPath); + const destPath = path.join(outDir, relPath); + deferred.push( + (async () => { + await fs.mkdir(path.dirname(destPath), { recursive: true }); + await fs.copyFile(assetPath, destPath); + })() + ); + } + await Promise.all(deferred); }; /** @@ -84,6 +86,6 @@ const copyStaticAssets = async ({ * @param config Configuration for the site. */ export const renderSite = async ({ paths, hooks }: Config): Promise => { - await Promise.all([renderPagesToHtml(paths), copyStaticAssets(paths)]); - await hooks.afterSiteRender(paths); + await Promise.all([renderPagesToHtml(paths), copyStaticAssets(paths)]); + await hooks.afterSiteRender(paths); }; diff --git a/src/cli/commands/build.ts b/src/cli/commands/build.ts index 1dc94fc..7c14947 100644 --- a/src/cli/commands/build.ts +++ b/src/cli/commands/build.ts @@ -5,7 +5,7 @@ import { renderSite } from "../../build"; import { loadConfig } from "../../config"; -import { type Command, UsageError } from "../types"; +import { Command, UsageError } from "../types"; const helpText = `\ Usage: websnacks build [ROOT_DIR] @@ -18,16 +18,16 @@ Args: `; interface BuildArgs { - rootDir: string; + rootDir: string; } const parseArgs = (args: string[]): BuildArgs => { - if (args.length > 1) { - throw new UsageError("too many arguments provided", helpText); - } - return { - rootDir: args[0] || process.cwd(), - }; + if (args.length > 1) { + throw new UsageError("too many arguments provided", helpText); + } + return { + rootDir: args[0] || process.cwd(), + }; }; /** @@ -35,11 +35,11 @@ const parseArgs = (args: string[]): BuildArgs => { * static files. */ const buildCommand: Command = { - execute: async (args: string[]): Promise => { - const { rootDir } = parseArgs(args); - const config = await loadConfig(rootDir); - await renderSite(config); - }, - helpText, + execute: async (args: string[]): Promise => { + const { rootDir } = parseArgs(args); + const config = await loadConfig(rootDir); + await renderSite(config); + }, + helpText, }; export = buildCommand; diff --git a/src/cli/commands/dev.ts b/src/cli/commands/dev.ts index 3cbba79..4401471 100644 --- a/src/cli/commands/dev.ts +++ b/src/cli/commands/dev.ts @@ -3,250 +3,204 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { existsSync, promises as fs, watch } from "node:fs"; -import * as http from "node:http"; -import * as path from "node:path"; +import { existsSync, promises as fs, watch } from "fs"; +import * as http from "http"; +import * as path from "path"; import { renderSite } from "../../build"; -import { type Config, loadConfig } from "../../config"; -import { isErrnoException } from "../../utils/error"; -import { type Command, UsageError } from "../types"; +import { Config, loadConfig } from "../../config"; +import { Command, UsageError } from "../types"; -const DEFAULT_SERVER_PORT = 8080; +const SERVER_PORT = 8080; -const injectLiveReloadScript = (htmlContents: string, port: number): string => - htmlContents.replace( - "", - ` +const injectLiveReloadScript = (htmlContents: string): string => + htmlContents.replace( + "", + ` - `, - ); + ` + ); const guessMimeType = (ext: string): string => { - let mimeType: string; - switch (ext) { - case ".apng": - mimeType = "image/apng"; - break; - case ".bmp": - mimeType = "image/bmp"; - break; - case ".css": - mimeType = "text/css"; - break; - case ".eot": - mimeType = "application/vnd.ms-fontobject"; - break; - case ".gif": - mimeType = "image/gif"; - break; - case ".htm": - case ".html": - mimeType = "text/html"; - break; - case ".ico": - mimeType = "image/vnd.microsoft.icon"; - break; - case ".jpg": - case ".jpeg": - mimeType = "image/jpeg"; - break; - case ".js": - case ".mjs": - mimeType = "text/javascript"; - break; - case ".mp3": - mimeType = "audio/mpeg"; - break; - case ".mpeg": - mimeType = "video/mpeg"; - break; - case ".oga": - mimeType = "audio/ogg"; - break; - case ".ogv": - mimeType = "video/ogg"; - break; - case ".otf": - mimeType = "font/otf"; - break; - case ".png": - mimeType = "image/png"; - break; - case ".svg": - mimeType = "image/svg+xml"; - break; - case ".txt": - mimeType = "text/plain"; - break; - case ".tif": - case ".tiff": - mimeType = "image/tiff"; - break; - case ".ttf": - mimeType = "font/ttf"; - break; - case ".wav": - mimeType = "audio/wav"; - break; - case ".weba": - mimeType = "audio/webm"; - break; - case ".webm": - mimeType = "video/webm"; - break; - case ".webp": - mimeType = "image/webp"; - break; - case ".woff": - mimeType = "font/woff"; - break; - case ".woff2": - mimeType = "font/woff2"; - break; - default: - // Default to binary mimetype which most browsers will be able to - // correctly interpret in the right context. - mimeType = "application/octet-stream"; - } - return mimeType; + let mimeType; + switch (ext) { + case ".apng": + mimeType = "image/apng"; + break; + case ".bmp": + mimeType = "image/bmp"; + break; + case ".css": + mimeType = "text/css"; + break; + case ".eot": + mimeType = "application/vnd.ms-fontobject"; + break; + case ".gif": + mimeType = "image/gif"; + break; + case ".htm": + case ".html": + mimeType = "text/html"; + break; + case ".ico": + mimeType = "image/vnd.microsoft.icon"; + break; + case ".jpg": + case ".jpeg": + mimeType = "image/jpeg"; + break; + case ".js": + case ".mjs": + mimeType = "text/javascript"; + break; + case ".mp3": + mimeType = "audio/mpeg"; + break; + case ".mpeg": + mimeType = "video/mpeg"; + break; + case ".oga": + mimeType = "audio/ogg"; + break; + case ".ogv": + mimeType = "video/ogg"; + break; + case ".otf": + mimeType = "font/otf"; + break; + case ".png": + mimeType = "image/png"; + break; + case ".svg": + mimeType = "image/svg+xml"; + break; + case ".txt": + mimeType = "text/plain"; + break; + case ".tif": + case ".tiff": + mimeType = "image/tiff"; + break; + case ".ttf": + mimeType = "font/ttf"; + break; + case ".wav": + mimeType = "audio/wav"; + break; + case ".weba": + mimeType = "audio/webm"; + break; + case ".webm": + mimeType = "video/webm"; + break; + case ".webp": + mimeType = "image/webp"; + break; + case ".woff": + mimeType = "font/woff"; + break; + case ".woff2": + mimeType = "font/woff2"; + break; + default: + // Default to binary mimetype which most browsers will be able to + // correctly interpret in the right context. + mimeType = "application/octet-stream"; + } + return mimeType; }; -const portFromServer = ( - addrInfo: { port: number } | object | string | undefined | null, -): number => { - if ( - typeof addrInfo !== "object" || - addrInfo == null || - !("port" in addrInfo) - ) { - throw new Error( - "server address does not have a valid port (this should never happen!)", - ); - } - return addrInfo.port; -}; +const serve = (publicDir: string): http.Server => { + const server = http.createServer(async (req, res) => { + if (req.url == null) { + res.writeHead(404); + res.end(); + return; + } -const startHttpServer = async (publicDir: string): Promise => { - const httpServer = http.createServer(async (req, res) => { - if (req.url == null) { - res.writeHead(404); - res.end(); - return; - } + let reqExt = path.extname(req.url); + let reqPath = req.url; + if (!reqExt) { + reqPath = path.join(reqPath, "index.html"); + reqExt = ".html"; + } - let reqExt = path.extname(req.url); - let reqPath = req.url; - if (!reqExt) { - reqPath = path.join(reqPath, "index.html"); - reqExt = ".html"; - } - - let contents: Buffer | string; - try { - contents = await fs.readFile(path.join(publicDir, reqPath)); - } catch (_error) { - console.error(`unable to load file ${reqPath}`); - res.writeHead(404); - res.end(); - return; - } - const mimeType = guessMimeType(reqExt); - if (mimeType === "text/html") { - const port = portFromServer(req.socket.address()); - contents = injectLiveReloadScript(contents.toString("utf8"), port); - } - res.writeHead(200, { - "Content-Type": mimeType, - }); - res.end(contents); - }); - const listen = async (port?: number): Promise => - new Promise((resolve, reject) => { - httpServer - .once("error", (error) => reject(error)) - .once("listening", () => resolve()) - .listen(port); - }); - try { - await listen(DEFAULT_SERVER_PORT); - } catch (error) { - if ( - error instanceof Error && - isErrnoException(error) && - error.code !== "EADDRINUSE" - ) { - throw error; - } - await listen(); - } - const port = portFromServer(httpServer.address()); - console.log(`Listening at http://127.0.0.1:${port}`); - return httpServer; + let contents; + try { + contents = await fs.readFile(path.join(publicDir, reqPath)); + } catch (error) { + console.error(`unable to load file ${reqPath}`); + res.writeHead(404); + res.end(); + return; + } + const mimeType = guessMimeType(reqExt); + if (mimeType === "text/html") { + contents = injectLiveReloadScript(contents.toString("utf8")); + } + res.writeHead(200, { + "Content-Type": mimeType, + }); + res.end(contents); + }); + return server; }; const startWebSocketServer = async ( - httpServer: http.Server, + server: http.Server ): Promise => { - // Attempt to load the ws module, aborting if it isn't available. - let ws: typeof import("ws"); - try { - ws = await import("ws"); - } catch (error) { - if ( - error instanceof Error && - isErrnoException(error) && - error.code !== "MODULE_NOT_FOUND" - ) { - throw error; - } - console.warn(`'ws' module not found, live-reloading will be disabled`); - return; - } - const wsServer = new ws.Server({ server: httpServer }); - wsServer.on("connection", () => { - console.log("connected to dev site"); - }); - return wsServer; + // Attempt to load the ws module, aborting if it isn't available. + let ws; + try { + ws = await import("ws"); + } catch (error) { + if (error.code !== "MODULE_NOT_FOUND") { + throw error; + } + console.warn(`'ws' module not found, live-reloading will be disabled`); + return; + } + const wsServer = new ws.Server({ server }); + wsServer.on("connection", () => { + console.log("connected to dev site"); + }); + return wsServer; }; const watchFolders = async ( - folders: string[], - listener: (eventType?: "update" | "remove", fileName?: string) => void, + folders: string[], + listener: (eventType: "update" | "remove", fileName: string) => void ): Promise => { - // Try to load node-watch, falling back to fs watch if node-watch isn't - // available. - try { - const nodeWatch = await import("node-watch"); - nodeWatch.default(folders, { recursive: true }, listener); - return; - } catch (error) { - if ( - error instanceof Error && - isErrnoException(error) && - error.code !== "MODULE_NOT_FOUND" - ) { - throw error; - } - console.warn( - `'node-watch' module not found, falling back to fs.watch (may ` + - "result in file watch issues on some OSes)", - ); - } - // NOTE: fs.watch has significant cross-platform issues, including - // triggering duplicate file events on some systems. - for (const folder of folders) { - watch(folder, { recursive: true }, (_, fileName) => { - listener("update", fileName || undefined); - }); - } + // Try to load node-watch, falling back to fs watch if node-watch isn't + // available. + try { + const { default: watch } = await import("node-watch"); + watch(folders, { recursive: true }, listener); + return; + } catch (error) { + if (error.code !== "MODULE_NOT_FOUND") { + throw error; + } + console.warn( + `'node-watch' module not found, falling back to fs.watch (may ` + + `result in file watch issues on some OSes)` + ); + } + // NOTE: fs.watch has significant cross-platform issues, including + // triggering duplicate file events on some systems. + for (const folder of folders) { + watch(folder, { recursive: true }, (_, fileName) => { + listener("update", fileName); + }); + } }; const helpText = `\ @@ -259,16 +213,16 @@ Args: `; interface DevArgs { - rootDir: string; + rootDir: string; } const parseArgs = (args: string[]): DevArgs | null => { - if (args.length > 1) { - throw new UsageError("too many arguments provided", helpText); - } - return { - rootDir: args[0] || process.cwd(), - }; + if (args.length > 1) { + throw new UsageError("too many arguments provided", helpText); + } + return { + rootDir: args[0] || process.cwd(), + }; }; /** @@ -277,37 +231,38 @@ const parseArgs = (args: string[]): DevArgs | null => { * production static hosting environment as closely as possible. */ const devCommand: Command = { - async execute(args: string[]): Promise { - const parsedArgs = parseArgs(args); - if (!parsedArgs) { - return; - } - const { rootDir } = parsedArgs; - const rebuild = async (): Promise => { - const config = await loadConfig(rootDir); - await renderSite(config); - return config; - }; - const config = await rebuild(); - const { outDir } = config.paths; - const httpServer = await startHttpServer(outDir); - const wsServer = await startWebSocketServer(httpServer); - const watchedFolders = config.watch.filter((filePath) => - existsSync(filePath), - ); - await watchFolders(watchedFolders, async (event, filePath) => { - const filePathForLog = filePath || ""; - const eventForLog = event || ""; - console.log(`${filePathForLog}:${eventForLog} triggering rebuild...`); - await rebuild(); - if (wsServer != null) { - console.log("rebuild finished, reloading browsers..."); - for (const ws of wsServer.clients) { - ws.send("reload"); - } - } - }); - }, - helpText, + async execute(args: string[]): Promise { + const parsedArgs = parseArgs(args); + if (!parsedArgs) { + return; + } + const { rootDir } = parsedArgs; + const rebuild = async (): Promise => { + const config = await loadConfig(rootDir); + await renderSite(config); + return config; + }; + const config = await rebuild(); + const { outDir } = config.paths; + const httpServer = serve(outDir); + const wsServer = await startWebSocketServer(httpServer); + httpServer.listen(SERVER_PORT, () => { + console.log(`Listening at http://127.0.0.1:${SERVER_PORT}`); + }); + const watchedFolders = config.watch.filter((filePath) => + existsSync(filePath) + ); + watchFolders(watchedFolders, async (event, filePath) => { + console.log(`${filePath}:${event} triggering rebuild...`); + await rebuild(); + if (wsServer != null) { + console.log(`rebuild finished, reloading browsers...`); + for (const ws of wsServer.clients) { + ws.send("reload"); + } + } + }); + }, + helpText, }; export = devCommand; diff --git a/src/cli/index.ts b/src/cli/index.ts index 79317e6..f7a6151 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { type Command, UsageError } from "./types"; +import { Command, UsageError } from "./types"; const globalHelpText = `\ Usage: websnacks [...globalOptions] @@ -19,94 +19,97 @@ Commands: `; interface Options { - showHelp: boolean; - require: string[]; + showHelp: boolean; + require: string[]; } const parseArgs = ( - args: string[], + args: string[] ): { options: Options; commandName?: string; commandArgs: string[] } => { - const options: Options = { - showHelp: false, - require: [], - }; - // Look ahead for the first argument that doesn't start with a "-" to - // indicate the end of option parsing. - while (args.length > 0 && args[0].indexOf("-") >= 0) { - const opt = args.shift(); - switch (opt) { - case "-h": - case "--help": { - options.showHelp = true; - break; - } - case "-r": - case "--require": { - const moduleName = args.shift(); - if (moduleName == null) { - throw new UsageError( - "-r requires a valid module name", - globalHelpText, - ); - } - options.require.push(moduleName); - break; - } - default: - throw new UsageError(`unknown option ${opt}`, globalHelpText); - } - } - const commandName = args.shift(); - return { options, commandName, commandArgs: args }; + const options: Options = { + showHelp: false, + require: [], + }; + // Look ahead for the first argument that doesn't start with a "-" to + // indicate the end of option parsing. + while (args.length > 0 && args[0].indexOf("-") >= 0) { + const opt = args.shift(); + switch (opt) { + case "-h": + case "--help": { + options.showHelp = true; + break; + } + case "-r": + case "--require": { + const moduleName = args.shift(); + if (moduleName == null) { + throw new UsageError( + `-r requires a valid module name`, + globalHelpText + ); + } + options.require.push(moduleName); + break; + } + default: + throw new UsageError(`unknown option ${opt}`, globalHelpText); + } + } + const commandName = args.shift(); + return { options, commandName, commandArgs: args }; }; const _main = async (args: string[]): Promise => { - const { options, commandName, commandArgs } = parseArgs(args); - if (options.showHelp) { - console.log(`${globalHelpText}\n`); - return; - } - if (commandName == null) { - throw new UsageError("must specify a valid command", globalHelpText); - } - for (const moduleName of options.require) { - await import(moduleName); - } + const { options, commandName, commandArgs } = parseArgs(args); + if (options.showHelp) { + console.log(`${globalHelpText}\n`); + return; + } + if (commandName == null) { + throw new UsageError(`must specify a valid command`, globalHelpText); + } + for (const moduleName of options.require) { + await import(moduleName); + } - let command: Command; - switch (commandName) { - case "build": - command = await import("./commands/build"); - break; - case "dev": - command = await import("./commands/dev"); - break; - default: - throw new UsageError(`unknown command ${commandName}`, globalHelpText); - } - // NOTE: Should this just delegate to the command? - for (const arg of commandArgs) { - if (arg === "--help" || arg === "-h") { - console.log(`${command.helpText}\n`); - return; - } - } - await command.execute(commandArgs); + let command: Command; + switch (commandName) { + case "build": + command = await import("./commands/build"); + break; + case "dev": + command = await import("./commands/dev"); + break; + default: + throw new UsageError( + `unknown command ${commandName}`, + globalHelpText + ); + } + // NOTE: Should this just delegate to the command? + for (const arg of commandArgs) { + if (arg === "--help" || arg === "-h") { + console.log(`${command.helpText}\n`); + return; + } + } + await command.execute(commandArgs); }; /** * Entrypoint of the CLI app. */ export const main = (): void => { - _main(process.argv.slice(2)).catch((error) => { - if (error instanceof UsageError) { - console.error(`Error: ${error.message}\n`); - console.log(`${error.helpText}\n`); - } else { - const errorMsg = - error instanceof Error ? error.stack : JSON.stringify(error); - console.error(`Unexpected error: ${errorMsg}\n`); - } - process.exit(1); - }); + _main(process.argv.slice(2)).catch((error) => { + if (error instanceof UsageError) { + console.error(`Error: ${error.message}\n`); + console.log(`${error.helpText}\n`); + } else { + const errorMsg = + error instanceof Error ? error.stack : JSON.stringify(error); + console.error(`Unexpected error: ${errorMsg}\n`); + } + process.exit(1); + }); }; diff --git a/src/cli/types.ts b/src/cli/types.ts index 6b9656b..26234e9 100644 --- a/src/cli/types.ts +++ b/src/cli/types.ts @@ -7,16 +7,16 @@ * CLI command representing an action that the CLI program supports. */ export interface Command { - /** - * Execute the command with the specified arguments. - * - * @param args List of CLI arguments to pass to the command. - */ - execute(args: string[]): Promise; - /** - * Help text for this command. - */ - helpText: string; + /** + * Execute the command with the specified arguments. + * + * @param args List of CLI arguments to pass to the command. + */ + execute(args: string[]): Promise; + /** + * Help text for this command. + */ + helpText: string; } /** @@ -24,11 +24,11 @@ export interface Command { * text to guide the user to correct their mistake. */ export class UsageError extends Error { - public readonly helpText: string; + public readonly helpText: string; - public constructor(message: string, helpText: string) { - super(message); + public constructor(message: string, helpText: string) { + super(message); - this.helpText = helpText; - } + this.helpText = helpText; + } } diff --git a/src/component.ts b/src/component.ts index 2bf59ea..848eea3 100644 --- a/src/component.ts +++ b/src/component.ts @@ -7,46 +7,40 @@ * An in-memory representation of a renderable HTML element. */ export interface HTMLElement { - /** - * Name of the tag that gets output upon rendering. - */ - tag: string; - /** - * Record of attribute names and values that should be output in the opening - * tag. - */ - attributes: Record; - /** - * Child elements to render nested within this HTML element. - */ - children: Element[]; + /** + * Name of the tag that gets output upon rendering. + */ + tag: string; + /** + * Record of attribute names and values that should be output in the opening + * tag. + */ + attributes: Record; + /** + * Child elements to render nested within this HTML element. + */ + children: Element[]; } /** * All valid types of elements that can be rendered to HTML. */ export type Element = - | Element[] - | HTMLElement - | string - | number - | boolean - | undefined - | null; + | Element[] + | HTMLElement + | string + | number + | boolean + | undefined + | null; /** * Custom HTMLElement factory that can be parameterized by props. */ -export interface Component

> { - ( - props: P & { - children?: Element[]; - }, - ): HTMLElement; +export interface Component

{ + ( + props: P & { + children?: Element[]; + } + ): HTMLElement; } - -export const Fragment: Component = ({ children }) => ({ - tag: "#fragment", - attributes: {}, - children: children || [], -}); diff --git a/src/config.ts b/src/config.ts index b5c1d5f..6baa45c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -3,48 +3,48 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import * as path from "node:path"; +import * as path from "path"; -import { decacheModule } from "./utils"; +import { purgeModuleAndDepsFromCache } from "./utils"; /** * Paths used during configuration. */ export interface ConfigPaths { - rootDir: string; - outDir: string; - pagesDir: string; - staticAssetsDir: string; + rootDir: string; + outDir: string; + pagesDir: string; + staticAssetsDir: string; } /** * Hooks that allow user code to customize site rendering. */ export interface Hooks { - /** - * Hook that fires at the end of site rendering one all pages and assets are - * fully rendered. - */ - afterSiteRender(context: ConfigPaths): Promise | void; + /** + * Hook that fires at the end of site rendering one all pages and assets are + * fully rendered. + */ + afterSiteRender(context: ConfigPaths): Promise | void; } /** * User-provided configuration options. */ export type UserConfig = { - /** Hook implementations that allow customizing the rendering process. */ - hooks?: Partial; - /** Additional folders and files to watch by the development server. */ - watch?: string[]; + /** Hook implementations that allow customizing the rendering process. */ + hooks?: Partial; + /** Additional folders and files to watch by the development server. */ + watch?: string[]; }; /** * Fully-realized configuration for a websnacks site. */ export interface Config { - paths: ConfigPaths; - hooks: Hooks; - watch: string[]; + paths: ConfigPaths; + hooks: Hooks; + watch: string[]; } // eslint-disable-next-line @typescript-eslint/no-empty-function @@ -58,44 +58,29 @@ const noop = () => {}; * @return Fully-realized configuration. */ export const loadConfig = async (rootDir: string): Promise => { - let configPath = ""; - let userConfig: UserConfig = {}; - // Attempt to load a websnacks.ts/js file in rootDir. - try { - configPath = require.resolve(path.resolve(rootDir, "websnacks")); - decacheModule(configPath); - // TODO: validate user config. - userConfig = await import(configPath); - } catch (_error) { - // Use default config; - } - const outDir = path.join(rootDir, "public"); - const pagesDir = path.join(rootDir, "pages"); - const staticAssetsDir = path.join(rootDir, "static"); - - const watch = [pagesDir, staticAssetsDir]; - if (configPath) { - watch.push(path.relative(rootDir, configPath)); - } - if (userConfig.watch != null) { - for (const userWatch of userConfig.watch) { - watch.push(path.relative(rootDir, userWatch)); - } - } - - return { - paths: { - rootDir, - outDir, - pagesDir, - staticAssetsDir, - }, - hooks: { - afterSiteRender: noop, - ...userConfig.hooks, - }, - watch, - }; + const configPath = require.resolve(path.resolve(rootDir, "websnacks")); + purgeModuleAndDepsFromCache(configPath); + // TODO: validate user config. + const userConfig = await import(configPath); + const outDir = path.join(rootDir, "public"); + const pagesDir = path.join(rootDir, "pages"); + const staticAssetsDir = path.join(rootDir, "static"); + return { + paths: { + rootDir, + outDir, + pagesDir, + staticAssetsDir, + }, + hooks: { + afterSiteRender: noop, + ...userConfig.hooks, + }, + watch: [ + ...userConfig.watch.map((p: string) => path.relative(rootDir, p)), + path.relative(rootDir, configPath), + pagesDir, + staticAssetsDir, + ], + }; }; - -export const defineConfig = (userConfig: UserConfig): UserConfig => userConfig; diff --git a/src/create-element.ts b/src/create-element.ts index e2f4bcf..9e239cd 100644 --- a/src/create-element.ts +++ b/src/create-element.ts @@ -3,8 +3,8 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import type { Component, Element, HTMLElement } from "./component"; -import type { HTMLAttributes } from "./jsx"; +import { Component, Element, HTMLElement } from "./component"; +import { HTMLAttributes } from "./jsx"; import { flatDeep } from "./utils"; /** @@ -18,9 +18,9 @@ import { flatDeep } from "./utils"; * @return Fully-realized HTMLElement, ready for rendering. */ export function createElement

( - comp: Component

, - props: P, - ...children: Element[] + comp: Component

, + props: P, + ...children: Element[] ): HTMLElement; /** * Create an HTMLElement from a standard HTML5 tag. @@ -33,44 +33,38 @@ export function createElement

( * @return Fully-realized HTMLElement, ready for rendering. */ export function createElement( - tag: string, - attrs: HTMLAttributes | null, - ...children: Element[] + tag: string, + attrs: HTMLAttributes | null, + ...children: Element[] ): HTMLElement; export function createElement( - type: string | Component, - props: object | null, - ...children: Element[] + // eslint-disable-next-line @typescript-eslint/no-explicit-any + type: string | Component, + props: object | null, + ...children: Element[] ): HTMLElement { - // Flatten the children array so we can accept arrays as children. - const normalizedChildren = flatDeep(children); - if (type instanceof Function) { - return type({ ...props, children: normalizedChildren }); - } + // Flatten the children array so we can accept arrays as children. + const normalizedChildren = flatDeep(children); + if (type instanceof Function) { + return type({ ...props, children: normalizedChildren }); + } - if (type !== type.toLowerCase()) { - console.warn(`constructed HTML5 tag with non-lowercase name ${type}`); - } - const attrs: Record = {}; - for (const [key, value] of Object.entries(props || {})) { - if (key === "dangerouslySetInnerHTML") { - if (children.length > 0) { - throw new Error( - 'An element with children may not have a "dangerouslySetInnerHTML" prop since children would be overriden', - ); - } - attrs[key] = value.__html; - continue; - } - if ( - typeof value !== "string" && - typeof value !== "number" && - typeof value !== "boolean" - ) { - console.warn(`non-primitive attribute ${key} = ${JSON.stringify(value)}`); - continue; - } - attrs[key] = value; - } - return { tag: type, attributes: attrs, children: normalizedChildren }; + if (type !== type.toLowerCase()) { + console.warn(`constructed HTML5 tag with non-lowercase name ${type}`); + } + const attrs: Record = {}; + for (const [key, value] of Object.entries(props || {})) { + if ( + typeof value !== "string" && + typeof value !== "number" && + typeof value !== "boolean" + ) { + console.warn( + `non-primitive attribute ${key} = ${JSON.stringify(value)}` + ); + continue; + } + attrs[key] = value; + } + return { tag: type, attributes: attrs, children: normalizedChildren }; } diff --git a/src/index.ts b/src/index.ts index 51cd362..2e5606b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -export { Component, Fragment, HTMLElement } from "./component"; -export { defineConfig, UserConfig as Config } from "./config"; +export { HTMLElement, Component } from "./component"; +export { UserConfig as Config } from "./config"; export { createElement } from "./create-element"; export * from "./jsx"; diff --git a/src/jsx.ts b/src/jsx.ts index ce1c1ed..55d69a9 100644 --- a/src/jsx.ts +++ b/src/jsx.ts @@ -4,285 +4,278 @@ */ // eslint-disable-next-line @typescript-eslint/no-unused-vars -import type { HTMLElement } from "./component"; +import { HTMLElement } from "./component"; export interface RdfaAttributes { - about?: string; - datatype?: string; - inlist?: boolean; - prefix?: string; - property?: string; - resource?: string; - typeof?: string; - vocab?: string; + about?: string; + datatype?: string; + inlist?: boolean; + prefix?: string; + property?: string; + resource?: string; + typeof?: string; + vocab?: string; } export interface MicrodataAttributes { - itemProp?: string; - itemScope?: boolean; - itemType?: string; - itemID?: string; - itemRef?: string; + itemProp?: string; + itemScope?: boolean; + itemType?: string; + itemID?: string; + itemRef?: string; } -export interface SetInnerHtmlAttributes { - dangerouslySetInnerHTML?: { __html: string }; -} - -export interface HTMLAttributes - extends RdfaAttributes, - MicrodataAttributes, - SetInnerHtmlAttributes { - accept?: string; - acceptCharset?: string; - accessKey?: string; - action?: string; - allowFullScreen?: boolean; - allowTransparency?: boolean; - alt?: string; - as?: string; - async?: boolean; - autoComplete?: string; - autoCorrect?: string; - autoFocus?: boolean; - autoPlay?: boolean; - capture?: boolean; - cellPadding?: number | string; - cellSpacing?: number | string; - charSet?: string; - challenge?: string; - checked?: boolean; - class?: string; - className?: string; - cols?: number; - colSpan?: number; - content?: string; - contentEditable?: boolean; - contextMenu?: string; - controls?: boolean; - controlsList?: string; - coords?: string; - crossOrigin?: string; - data?: string; - dateTime?: string; - default?: boolean; - defer?: boolean; - dir?: "auto" | "rtl" | "ltr"; - disabled?: boolean; - disableRemotePlayback?: boolean; - download?: boolean | string; - draggable?: boolean; - encType?: string; - form?: string; - formAction?: string; - formEncType?: string; - formMethod?: string; - formNoValidate?: boolean; - formTarget?: string; - frameBorder?: number | string; - headers?: string; - height?: number | string; - hidden?: boolean; - high?: number; - href?: string; - hrefLang?: string; - for?: string; - htmlFor?: string; - httpEquiv?: string; - icon?: string; - id?: string; - inputMode?: string; - integrity?: string; - is?: string; - keyParams?: string; - keyType?: string; - kind?: string; - label?: string; - lang?: string; - list?: string; - loop?: boolean; - low?: number; - manifest?: string; - marginHeight?: number; - marginWidth?: number; - max?: number | string; - maxLength?: number; - media?: string; - mediaGroup?: string; - method?: string; - min?: number | string; - minLength?: number; - multiple?: boolean; - muted?: boolean; - name?: string; - nonce?: string; - noValidate?: boolean; - open?: boolean; - optimum?: number; - pattern?: string; - placeholder?: string; - playsInline?: boolean; - poster?: string; - preload?: string; - radioGroup?: string; - readOnly?: boolean; - rel?: string; - required?: boolean; - role?: string; - rows?: number; - rowSpan?: number; - sandbox?: string; - scope?: string; - scoped?: boolean; - scrolling?: string; - seamless?: boolean; - selected?: boolean; - shape?: string; - size?: number; - sizes?: string; - slot?: string; - span?: number; - spellcheck?: boolean; - src?: string; - srcset?: string; - srcDoc?: string; - srcLang?: string; - srcSet?: string; - start?: number; - step?: number | string; - style?: string | { [key: string]: string | number }; - summary?: string; - tabIndex?: number; - target?: string; - title?: string; - type?: string; - useMap?: string; - value?: string | string[] | number; - volume?: string | number; - width?: number | string; - wmode?: string; - wrap?: string; +export interface HTMLAttributes extends RdfaAttributes, MicrodataAttributes { + accept?: string; + acceptCharset?: string; + accessKey?: string; + action?: string; + allowFullScreen?: boolean; + allowTransparency?: boolean; + alt?: string; + as?: string; + async?: boolean; + autoComplete?: string; + autoCorrect?: string; + autoFocus?: boolean; + autoPlay?: boolean; + capture?: boolean; + cellPadding?: number | string; + cellSpacing?: number | string; + charSet?: string; + challenge?: string; + checked?: boolean; + class?: string; + className?: string; + cols?: number; + colSpan?: number; + content?: string; + contentEditable?: boolean; + contextMenu?: string; + controls?: boolean; + controlsList?: string; + coords?: string; + crossOrigin?: string; + data?: string; + dateTime?: string; + default?: boolean; + defer?: boolean; + dir?: "auto" | "rtl" | "ltr"; + disabled?: boolean; + disableRemotePlayback?: boolean; + download?: boolean | string; + draggable?: boolean; + encType?: string; + form?: string; + formAction?: string; + formEncType?: string; + formMethod?: string; + formNoValidate?: boolean; + formTarget?: string; + frameBorder?: number | string; + headers?: string; + height?: number | string; + hidden?: boolean; + high?: number; + href?: string; + hrefLang?: string; + for?: string; + htmlFor?: string; + httpEquiv?: string; + icon?: string; + id?: string; + inputMode?: string; + integrity?: string; + is?: string; + keyParams?: string; + keyType?: string; + kind?: string; + label?: string; + lang?: string; + list?: string; + loop?: boolean; + low?: number; + manifest?: string; + marginHeight?: number; + marginWidth?: number; + max?: number | string; + maxLength?: number; + media?: string; + mediaGroup?: string; + method?: string; + min?: number | string; + minLength?: number; + multiple?: boolean; + muted?: boolean; + name?: string; + nonce?: string; + noValidate?: boolean; + open?: boolean; + optimum?: number; + pattern?: string; + placeholder?: string; + playsInline?: boolean; + poster?: string; + preload?: string; + radioGroup?: string; + readOnly?: boolean; + rel?: string; + required?: boolean; + role?: string; + rows?: number; + rowSpan?: number; + sandbox?: string; + scope?: string; + scoped?: boolean; + scrolling?: string; + seamless?: boolean; + selected?: boolean; + shape?: string; + size?: number; + sizes?: string; + slot?: string; + span?: number; + spellcheck?: boolean; + src?: string; + srcset?: string; + srcDoc?: string; + srcLang?: string; + srcSet?: string; + start?: number; + step?: number | string; + style?: string | { [key: string]: string | number }; + summary?: string; + tabIndex?: number; + target?: string; + title?: string; + type?: string; + useMap?: string; + value?: string | string[] | number; + volume?: string | number; + width?: number | string; + wmode?: string; + wrap?: string; } declare global { - namespace JSX { - type Element = HTMLElement; - type IntrinsicElements = { - a: HTMLAttributes; - abbr: HTMLAttributes; - address: HTMLAttributes; - area: HTMLAttributes; - article: HTMLAttributes; - aside: HTMLAttributes; - audio: HTMLAttributes; - b: HTMLAttributes; - base: HTMLAttributes; - bdi: HTMLAttributes; - bdo: HTMLAttributes; - big: HTMLAttributes; - blockquote: HTMLAttributes; - body: HTMLAttributes; - br: HTMLAttributes; - button: HTMLAttributes; - canvas: HTMLAttributes; - caption: HTMLAttributes; - cite: HTMLAttributes; - code: HTMLAttributes; - col: HTMLAttributes; - colgroup: HTMLAttributes; - data: HTMLAttributes; - datalist: HTMLAttributes; - dd: HTMLAttributes; - del: HTMLAttributes; - details: HTMLAttributes; - dfn: HTMLAttributes; - dialog: HTMLAttributes; - div: HTMLAttributes; - dl: HTMLAttributes; - dt: HTMLAttributes; - em: HTMLAttributes; - embed: HTMLAttributes; - fieldset: HTMLAttributes; - figcaption: HTMLAttributes; - figure: HTMLAttributes; - footer: HTMLAttributes; - form: HTMLAttributes; - h1: HTMLAttributes; - h2: HTMLAttributes; - h3: HTMLAttributes; - h4: HTMLAttributes; - h5: HTMLAttributes; - h6: HTMLAttributes; - head: HTMLAttributes; - header: HTMLAttributes; - hgroup: HTMLAttributes; - hr: HTMLAttributes; - html: HTMLAttributes; - i: HTMLAttributes; - iframe: HTMLAttributes; - img: HTMLAttributes; - input: HTMLAttributes; - ins: HTMLAttributes; - kbd: HTMLAttributes; - keygen: HTMLAttributes; - label: HTMLAttributes; - legend: HTMLAttributes; - li: HTMLAttributes; - link: HTMLAttributes; - main: HTMLAttributes; - map: HTMLAttributes; - mark: HTMLAttributes; - marquee: HTMLAttributes; - menu: HTMLAttributes; - menuitem: HTMLAttributes; - meta: HTMLAttributes; - meter: HTMLAttributes; - nav: HTMLAttributes; - noscript: HTMLAttributes; - object: HTMLAttributes; - ol: HTMLAttributes; - optgroup: HTMLAttributes; - option: HTMLAttributes; - output: HTMLAttributes; - p: HTMLAttributes; - param: HTMLAttributes; - picture: HTMLAttributes; - pre: HTMLAttributes; - progress: HTMLAttributes; - q: HTMLAttributes; - rp: HTMLAttributes; - rt: HTMLAttributes; - ruby: HTMLAttributes; - s: HTMLAttributes; - samp: HTMLAttributes; - script: HTMLAttributes; - section: HTMLAttributes; - select: HTMLAttributes; - slot: HTMLAttributes; - small: HTMLAttributes; - source: HTMLAttributes; - span: HTMLAttributes; - strong: HTMLAttributes; - style: HTMLAttributes; - sub: HTMLAttributes; - summary: HTMLAttributes; - sup: HTMLAttributes; - table: HTMLAttributes; - tbody: HTMLAttributes; - td: HTMLAttributes; - textarea: HTMLAttributes; - tfoot: HTMLAttributes; - th: HTMLAttributes; - thead: HTMLAttributes; - time: HTMLAttributes; - title: HTMLAttributes; - tr: HTMLAttributes; - track: HTMLAttributes; - u: HTMLAttributes; - ul: HTMLAttributes; - var: HTMLAttributes; - video: HTMLAttributes; - wbr: HTMLAttributes; - }; - } + namespace JSX { + type Element = HTMLElement; + type IntrinsicElements = { + a: HTMLAttributes; + abbr: HTMLAttributes; + address: HTMLAttributes; + area: HTMLAttributes; + article: HTMLAttributes; + aside: HTMLAttributes; + audio: HTMLAttributes; + b: HTMLAttributes; + base: HTMLAttributes; + bdi: HTMLAttributes; + bdo: HTMLAttributes; + big: HTMLAttributes; + blockquote: HTMLAttributes; + body: HTMLAttributes; + br: HTMLAttributes; + button: HTMLAttributes; + canvas: HTMLAttributes; + caption: HTMLAttributes; + cite: HTMLAttributes; + code: HTMLAttributes; + col: HTMLAttributes; + colgroup: HTMLAttributes; + data: HTMLAttributes; + datalist: HTMLAttributes; + dd: HTMLAttributes; + del: HTMLAttributes; + details: HTMLAttributes; + dfn: HTMLAttributes; + dialog: HTMLAttributes; + div: HTMLAttributes; + dl: HTMLAttributes; + dt: HTMLAttributes; + em: HTMLAttributes; + embed: HTMLAttributes; + fieldset: HTMLAttributes; + figcaption: HTMLAttributes; + figure: HTMLAttributes; + footer: HTMLAttributes; + form: HTMLAttributes; + h1: HTMLAttributes; + h2: HTMLAttributes; + h3: HTMLAttributes; + h4: HTMLAttributes; + h5: HTMLAttributes; + h6: HTMLAttributes; + head: HTMLAttributes; + header: HTMLAttributes; + hgroup: HTMLAttributes; + hr: HTMLAttributes; + html: HTMLAttributes; + i: HTMLAttributes; + iframe: HTMLAttributes; + img: HTMLAttributes; + input: HTMLAttributes; + ins: HTMLAttributes; + kbd: HTMLAttributes; + keygen: HTMLAttributes; + label: HTMLAttributes; + legend: HTMLAttributes; + li: HTMLAttributes; + link: HTMLAttributes; + main: HTMLAttributes; + map: HTMLAttributes; + mark: HTMLAttributes; + marquee: HTMLAttributes; + menu: HTMLAttributes; + menuitem: HTMLAttributes; + meta: HTMLAttributes; + meter: HTMLAttributes; + nav: HTMLAttributes; + noscript: HTMLAttributes; + object: HTMLAttributes; + ol: HTMLAttributes; + optgroup: HTMLAttributes; + option: HTMLAttributes; + output: HTMLAttributes; + p: HTMLAttributes; + param: HTMLAttributes; + picture: HTMLAttributes; + pre: HTMLAttributes; + progress: HTMLAttributes; + q: HTMLAttributes; + rp: HTMLAttributes; + rt: HTMLAttributes; + ruby: HTMLAttributes; + s: HTMLAttributes; + samp: HTMLAttributes; + script: HTMLAttributes; + section: HTMLAttributes; + select: HTMLAttributes; + slot: HTMLAttributes; + small: HTMLAttributes; + source: HTMLAttributes; + span: HTMLAttributes; + strong: HTMLAttributes; + style: HTMLAttributes; + sub: HTMLAttributes; + summary: HTMLAttributes; + sup: HTMLAttributes; + table: HTMLAttributes; + tbody: HTMLAttributes; + td: HTMLAttributes; + textarea: HTMLAttributes; + tfoot: HTMLAttributes; + th: HTMLAttributes; + thead: HTMLAttributes; + time: HTMLAttributes; + title: HTMLAttributes; + tr: HTMLAttributes; + track: HTMLAttributes; + u: HTMLAttributes; + ul: HTMLAttributes; + var: HTMLAttributes; + video: HTMLAttributes; + wbr: HTMLAttributes; + }; + } } diff --git a/src/render.ts b/src/render.ts index 85fda2e..ef0917f 100644 --- a/src/render.ts +++ b/src/render.ts @@ -3,88 +3,72 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import type { Element, HTMLElement } from "./component"; +import { Element, HTMLElement } from "./component"; const HTML_ESCAPES: { [char: string]: string } = { - "&": "&", - "<": "<", - ">": ">", + "&": "&", + "<": "<", + ">": ">", }; const escapeHtml = (text: string): string => - text.replace(/[&<>]/g, (t) => HTML_ESCAPES[t]); + text.replace(/[&<>]/g, (t) => HTML_ESCAPES[t]); const escapeAttr = (text: string): string => text.replace(/"/g, """); const renderElement = (elem: Element): string => { - // Ignore null and true/false to support nicer JSX conditional syntax with - // &&, ||, !! operators. - if (elem == null || typeof elem === "boolean") { - return ""; - } - if (typeof elem === "number") { - return elem.toString(); - } - if (typeof elem === "string") { - return escapeHtml(elem); - } - if (Array.isArray(elem)) { - return elem.map((e) => renderElement(e)).join(""); - } + // Ignore null and true/false to support nicer JSX conditional syntax with + // &&, ||, !! operators. + if (elem == null || typeof elem === "boolean") { + return ""; + } + if (typeof elem === "number") { + return elem.toString(); + } + if (typeof elem === "string") { + return escapeHtml(elem); + } + if (Array.isArray(elem)) { + return elem.map((e) => renderElement(e)).join(""); + } - let output = ""; - output += startTag(elem); - if (elem.attributes.dangerouslySetInnerHTML != null) { - output += elem.attributes.dangerouslySetInnerHTML; - } else { - for (const child of elem.children) { - output += renderElement(child); - } - } - output += endTag(elem); - return output; + let output = ""; + output += startTag(elem); + for (const child of elem.children) { + output += renderElement(child); + } + output += endTag(elem); + return output; }; const startTag = (elem: HTMLElement): string => { - if (elem.tag === "#fragment") { - return ""; - } + let output = `<${escapeHtml(elem.tag)}`; - let output = `<${escapeHtml(elem.tag)}`; + for (const [attrName, attrValue] of Object.entries(elem.attributes)) { + // Handle boolean attributes with a false value by not outputting the + // attribute at all. + if (attrValue === false) { + continue; + } - for (const [attrName, attrValue] of Object.entries(elem.attributes)) { - // Handle boolean attributes with a false value by not outputting the - // attribute at all. - if (attrValue === false) { - continue; - } + let normalizedAttrName = escapeHtml(attrName.toLowerCase()); + if (normalizedAttrName === "classname") { + normalizedAttrName = "class"; + } + if (attrValue === true) { + output += ` ${normalizedAttrName}=""`; + } else { + output += ` ${normalizedAttrName}="${escapeAttr( + attrValue.toString() + )}"`; + } + } - // Ignore the special attr for setting raw inner HTML. - if (attrName === "dangerouslySetInnerHTML") { - continue; - } - - let normalizedAttrName = escapeHtml(attrName.toLowerCase()); - if (normalizedAttrName === "classname") { - normalizedAttrName = "class"; - } - if (attrValue === true) { - output += ` ${normalizedAttrName}=""`; - } else { - output += ` ${normalizedAttrName}="${escapeAttr(attrValue.toString())}"`; - } - } - - output += ">"; - return output; + output += ">"; + return output; }; -const endTag = (elem: HTMLElement): string => { - if (elem.tag === "#fragment") { - return ""; - } - return ``; -}; +const endTag = (elem: HTMLElement): string => ``; /** * Render a complete HTML page from an HTMLElement. Note that the root element @@ -94,24 +78,14 @@ const endTag = (elem: HTMLElement): string => { * * @return Fully rendered HTML document as a string. */ -export const renderPage = (rootElem: Element): string => { - if (rootElem == null) { - throw new Error("root page element cannot be null"); - } - if (typeof rootElem !== "object" || !("tag" in rootElem)) { - throw new Error( - `root page element must be a valid HTMLElement, got ${JSON.stringify( - rootElem, - )}`, - ); - } - if (rootElem.tag.toLowerCase() !== "html") { - throw new Error( - `attempted to render page with non-HTML root element ${rootElem.tag}`, - ); - } +export const renderPage = (rootElem: HTMLElement): string => { + if (rootElem.tag.toLowerCase() !== "html") { + throw new Error( + `attempted to render page with non-HTML root element ${rootElem.tag}` + ); + } - let output = ""; - output += renderElement(rootElem); - return output; + let output = ""; + output += renderElement(rootElem); + return output; }; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..4c5fbdf --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,71 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import { promises as fs } from "fs"; +import * as path from "path"; + +/** + * Recursively walk a directory, returning the files it finds. + * + * @param dirPath Path to the directory to walk. + * + * @return Generator that yields the files found while walking the directory. + */ +export const walkDir = async function* ( + dirPath: string +): AsyncGenerator { + const dirEnts = await fs.readdir(dirPath, { withFileTypes: true }); + for (const dirEnt of dirEnts) { + if (dirEnt.isDirectory()) { + yield* walkDir(path.join(dirPath, dirEnt.name)); + } + if (dirEnt.isFile()) { + yield path.join(dirPath, dirEnt.name); + } + } +}; + +/** + * Purge cached versions of a node module and all of its dependencies from the + * global require cache, ensuring that future imports reload the module from + * disk. + * + * @param modName Name of the module to purge from the require cache. + */ +export const purgeModuleAndDepsFromCache = (modName: string): void => { + const modPath = require.resolve(modName); + if (modPath == null) { + return; + } + const mod = require.cache[modPath]; + if (mod == null) { + return; + } + for (const child of mod.children) { + purgeModuleAndDepsFromCache(child.id); + } + delete require.cache[modPath]; +}; + +export type Flattenable = Array>; + +/** + * Flatten an arbitrarily-deeply nested array into a flat array. + * + * @param arr Array to flatten. + * + * @return Flattened array. + */ +export const flatDeep = (arr: Flattenable): T[] => { + const flattenedArr: T[] = []; + for (const val of arr) { + if (Array.isArray(val)) { + flattenedArr.push(...flatDeep(val)); + } else { + flattenedArr.push(val); + } + } + return flattenedArr; +}; diff --git a/src/utils/decache-module.ts b/src/utils/decache-module.ts deleted file mode 100644 index e0c6ac9..0000000 --- a/src/utils/decache-module.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -import { isErrnoException } from "./error"; - -const resolveModulePath = (importPath: string): string | undefined => { - try { - return require.resolve(importPath); - } catch (error) { - if ( - error instanceof Error && - isErrnoException(error) && - error.code === "MODULE_NOT_FOUND" - ) { - return; - } - throw error; - } -}; - -const removeParentModuleRef = (mod: NodeModule): void => { - const parent = mod.parent; - if (parent == null) { - return; - } - - const siblings = parent.children; - const nSiblings = siblings.length; - for (let i = nSiblings - 1; i >= 0; i--) { - const sibling = siblings[i]; - if (sibling.id === mod.id) { - siblings.splice(i, 1); - return; - } - } -}; - -/** - * Clear a module and its dependencies from node's module cache, ensuring that - * requiring the module again will reload the code from disk. - * - * @param importPath Path or name of the module to resolve (same as - * {@see require}). - * - * @throws Error if the module could not be resolved due to filesystem error. - */ -export const decacheModule = (importPath: string): void => { - const modulePath = resolveModulePath(importPath); - if (modulePath == null) { - return; - } - - // DFS the module dependency tree, using iteration to avoid stack size - // exceeded exceptions. - const modsToCheck: NodeModule[] = []; - const visited: Set = new Set(); - let currentMod: NodeModule | undefined = require.cache[modulePath]; - while (currentMod != null) { - if (visited.has(currentMod.id)) { - currentMod = modsToCheck.pop(); - continue; - } - - removeParentModuleRef(currentMod); - delete require.cache[currentMod.id]; - for (const childMod of currentMod.children) { - modsToCheck.push(childMod); - } - - visited.add(currentMod.id); - currentMod = modsToCheck.pop(); - } -}; diff --git a/src/utils/error.ts b/src/utils/error.ts deleted file mode 100644 index 76b351b..0000000 --- a/src/utils/error.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const isErrnoException = ( - error: Error, -): error is NodeJS.ErrnoException => "code" in error; diff --git a/src/utils/index.ts b/src/utils/index.ts deleted file mode 100644 index a47ffb3..0000000 --- a/src/utils/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -import { promises as fs } from "node:fs"; -import * as path from "node:path"; - -export { decacheModule } from "./decache-module"; - -/** - * Recursively walk a directory, returning the files it finds. - * - * @param dirPath Path to the directory to walk. - * - * @return Generator that yields the files found while walking the directory. - */ -export const walkDir = async function* ( - dirPath: string, -): AsyncGenerator { - const dirEnts = await fs.readdir(dirPath, { withFileTypes: true }); - for (const dirEnt of dirEnts) { - if (dirEnt.isDirectory()) { - yield* walkDir(path.join(dirPath, dirEnt.name)); - } - if (dirEnt.isFile()) { - yield path.join(dirPath, dirEnt.name); - } - } -}; - -export type Flattenable = Array>; - -/** - * Flatten an arbitrarily-deeply nested array into a flat array. - * - * @param arr Array to flatten. - * - * @return Flattened array. - */ -export const flatDeep = (arr: Flattenable): T[] => { - const flattenedArr: T[] = []; - for (const val of arr) { - if (Array.isArray(val)) { - flattenedArr.push(...flatDeep(val)); - } else { - flattenedArr.push(val); - } - } - return flattenedArr; -}; diff --git a/test/e2e/build.tsx b/test/e2e/build.tsx deleted file mode 100644 index f6b324f..0000000 --- a/test/e2e/build.tsx +++ /dev/null @@ -1,151 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -import { promises as fs } from "node:fs"; -import * as path from "node:path"; - -import { - npmCmd, - runCommand, - WEBSNACKS_BIN_PATH, - WEBSNACKS_REPO_ROOT, - withTempDir, -} from "../helpers/e2e"; -import { testSuite } from "../lib"; - -testSuite("build command", ({ test }) => { - test("runs without throwing error", async () => { - await withTempDir(async (tempDirPath) => { - await fs.writeFile( - path.join(tempDirPath, "tsconfig.json"), - JSON.stringify({ - compilerOptions: { - esModuleInterop: true, - module: "CommonJS", - moduleResolution: "node", - jsx: "react", - jsxFactory: "createElement", - target: "ES2018", - lib: ["ES2018"], - strict: true, - noUnusedLocals: true, - noUnusedParameters: true, - noImplicitReturns: true, - noFallthroughCasesInSwitch: true, - }, - include: ["components/**/*", "pages/**/*"], - }), - { - encoding: "utf8", - }, - ); - await fs.writeFile( - path.join(tempDirPath, "websnacks.ts"), - ` - import { Config } from "websnacks"; - const config: Config = { - watch: [], - }; - export = config; - `, - { - encoding: "utf8", - }, - ); - const pagesPath = path.join(tempDirPath, "pages"); - await fs.mkdir(pagesPath); - await fs.writeFile( - path.join(pagesPath, "index.tsx"), - ` - import { createElement } from "websnacks"; - export const page = () => ; - `, - { - encoding: "utf8", - }, - ); - await fs.writeFile( - path.join(tempDirPath, "package.json"), - JSON.stringify({ - devDependencies: { - websnacks: `file:${WEBSNACKS_REPO_ROOT}`, - }, - }), - { encoding: "utf8" }, - ); - await runCommand(npmCmd, ["install", "--silent"], { - cwd: tempDirPath, - }).complete; - const cmd = runCommand( - "node", - [WEBSNACKS_BIN_PATH, "-r", "ts-node/register", "build"], - { - cwd: tempDirPath, - }, - ); - await cmd.complete; - }); - }); - - test("works without config file", async () => { - await withTempDir(async (tempDirPath) => { - await fs.writeFile( - path.join(tempDirPath, "tsconfig.json"), - JSON.stringify({ - compilerOptions: { - esModuleInterop: true, - module: "CommonJS", - moduleResolution: "node", - jsx: "react", - jsxFactory: "createElement", - target: "ES2018", - lib: ["ES2018"], - strict: true, - noUnusedLocals: true, - noUnusedParameters: true, - noImplicitReturns: true, - noFallthroughCasesInSwitch: true, - }, - include: ["components/**/*", "pages/**/*"], - }), - { - encoding: "utf8", - }, - ); - const pagesPath = path.join(tempDirPath, "pages"); - await fs.mkdir(pagesPath); - await fs.writeFile( - path.join(pagesPath, "index.tsx"), - ` - import { createElement } from "websnacks"; - export const page = () => ; - `, - { - encoding: "utf8", - }, - ); - await fs.writeFile( - path.join(tempDirPath, "package.json"), - JSON.stringify({ - devDependencies: { - websnacks: `file:${WEBSNACKS_REPO_ROOT}`, - }, - }), - { encoding: "utf8" }, - ); - await runCommand(npmCmd, ["install", "--silent"], { - cwd: tempDirPath, - }).complete; - const cmd = runCommand( - "node", - [WEBSNACKS_BIN_PATH, "-r", "ts-node/register", "build"], - { - cwd: tempDirPath, - }, - ); - await cmd.complete; - }); - }); -}); diff --git a/test/e2e/dev.tsx b/test/e2e/dev.tsx deleted file mode 100644 index f8fd9eb..0000000 --- a/test/e2e/dev.tsx +++ /dev/null @@ -1,160 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -import { promises as fs } from "node:fs"; -import * as path from "node:path"; - -import { - npmCmd, - runCommand, - WEBSNACKS_BIN_PATH, - WEBSNACKS_REPO_ROOT, - wait, - withTempDir, -} from "../helpers/e2e"; -import { testSuite } from "../lib"; - -testSuite("dev command", ({ test, expect }) => { - test("starts without throwing error", async () => { - await withTempDir(async (tempDirPath) => { - await fs.writeFile( - path.join(tempDirPath, "tsconfig.json"), - JSON.stringify({ - compilerOptions: { - esModuleInterop: true, - module: "CommonJS", - moduleResolution: "node", - jsx: "react", - jsxFactory: "createElement", - target: "ES2018", - lib: ["ES2018"], - strict: true, - noUnusedLocals: true, - noUnusedParameters: true, - noImplicitReturns: true, - noFallthroughCasesInSwitch: true, - }, - include: ["components/**/*", "pages/**/*"], - }), - { - encoding: "utf8", - }, - ); - await fs.writeFile( - path.join(tempDirPath, "websnacks.ts"), - ` - import { Config } from "websnacks"; - const config: Config = { - watch: [], - }; - export = config; - `, - { - encoding: "utf8", - }, - ); - const pagesPath = path.join(tempDirPath, "pages"); - await fs.mkdir(pagesPath); - await fs.writeFile( - path.join(pagesPath, "index.tsx"), - ` - import { createElement } from "websnacks"; - export const page = () => ; - `, - { - encoding: "utf8", - }, - ); - await fs.writeFile( - path.join(tempDirPath, "package.json"), - JSON.stringify({ - devDependencies: { - websnacks: `file:${WEBSNACKS_REPO_ROOT}`, - }, - }), - { encoding: "utf8" }, - ); - await runCommand(npmCmd, ["install", "--silent"], { - cwd: tempDirPath, - }).complete; - const cmd = runCommand( - "node", - [WEBSNACKS_BIN_PATH, "-r", "ts-node/register", "dev"], - { - cwd: tempDirPath, - }, - ); - // FIXME: This test is a bit brittle due to relying on timeouts. - await wait(10_000); - cmd.process.kill(); - const stdout = await cmd.complete; - expect(stdout).toStartWith("Listening at"); - }); - }); - - test("works without config file", async () => { - await withTempDir(async (tempDirPath) => { - await fs.writeFile( - path.join(tempDirPath, "tsconfig.json"), - JSON.stringify({ - compilerOptions: { - esModuleInterop: true, - module: "CommonJS", - moduleResolution: "node", - jsx: "react", - jsxFactory: "createElement", - target: "ES2018", - lib: ["ES2018"], - strict: true, - noUnusedLocals: true, - noUnusedParameters: true, - noImplicitReturns: true, - noFallthroughCasesInSwitch: true, - }, - include: ["components/**/*", "pages/**/*"], - }), - { - encoding: "utf8", - }, - ); - const pagesPath = path.join(tempDirPath, "pages"); - await fs.mkdir(pagesPath); - await fs.writeFile( - path.join(pagesPath, "index.tsx"), - ` - import { createElement } from "websnacks"; - export const page = () => ; - `, - { - encoding: "utf8", - }, - ); - await fs.writeFile( - path.join(tempDirPath, "package.json"), - JSON.stringify({ - devDependencies: { - websnacks: `file:${WEBSNACKS_REPO_ROOT}`, - }, - }), - { encoding: "utf8" }, - ); - await runCommand(npmCmd, ["install", "--silent"], { - cwd: tempDirPath, - }).complete; - const cmd = runCommand( - "node", - [WEBSNACKS_BIN_PATH, "-r", "ts-node/register", "dev"], - { - cwd: tempDirPath, - }, - ); - // FIXME: This test is a bit brittle due to relying on timeouts. - await wait(10_000); - cmd.process.kill(); - const stdout = await cmd.complete; - expect(stdout).toStartWith("Listening at"); - }); - }); -}); diff --git a/test/helpers/e2e.ts b/test/helpers/e2e.ts deleted file mode 100644 index c1e2097..0000000 --- a/test/helpers/e2e.ts +++ /dev/null @@ -1,168 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -import { type ChildProcess, spawn } from "node:child_process"; -import { promises as fs } from "node:fs"; -import * as os from "node:os"; -import * as path from "node:path"; - -/** - * Set a timeout and wait for at least the specified number of milliseconds, - * resolving the promise once the event loop meets or exceeds timeMs. - * - * @param timeMs Time in milliseconds to wait. - */ -export const wait = async (timeMs: number): Promise => { - return new Promise((resolve) => { - setTimeout(() => resolve(), timeMs); - }); -}; - -const TEMP_PATH = path.resolve(__dirname, "..", "..", ".temp"); - -/** - * Perform an operation within a unique temporary directory created within a - * special .test-dist folder within this websnacks repository. - * - * @note Currently the temporary folder is **not** cleaned up once the operation - * has finished. I've had issues with losing work due to buggy removal - * code and haven't been willing to risk it again. To cleanup these - * temporary folders it should be as easy as removing the whole - * ".test-dist" folder from your checkout. - * - * @param op Operation to perform which receives the fully resolved temp - * directory path as its only argument. - */ -export const withTempDir = async ( - op: (tempDirPath: string) => Promise | void, -): Promise => { - await fs.mkdir(TEMP_PATH, { recursive: true }); - const tempDirPath = await fs.mkdtemp(`${TEMP_PATH}/`); - try { - await op(tempDirPath); - } catch (error) { - throw new Error(`(${tempDirPath}): ${error}`); - } -}; - -/** - * Fully resolved path to the root of this websnacks repository. - */ -export const WEBSNACKS_REPO_ROOT = path.resolve(__dirname, "..", ".."); -/** - * Fully resolved path to the websnacks CLI script in this repository. - */ -export const WEBSNACKS_BIN_PATH = path.join( - WEBSNACKS_REPO_ROOT, - "bin", - "websnacks.js", -); - -/** - * A handle to an asynchronous shell command run in a subprocess. - */ -export interface AsyncCommand { - /** - * Promise that resolves with the stdout of the subprocess once the - * subprocess exits with a zero-code. - * - * The promise rejects if the subprocess exits with a non-zero code, the - * subprocess writes to its stderr, or the command failed to spawn. - */ - complete: Promise; - /** - * Handle to to child process for event-based process manipulation. - */ - process: ChildProcess; -} - -/** - * Options used to configure {@link runCommand}. - */ -export interface CliOptions { - /** - * Working directory where the command should be run. Defaults to the - * current working directory. - */ - cwd?: string; - /** - * Timeout in milliseconds after which a command that hasn't exited will - * reject the promise and kill the subprocess. - */ - timeoutMs?: number; -} - -const DEFAULT_CLI_OPTIONS = { - timeoutMs: 15_000, -}; - -/** - * Execute a shell command in a subprocess. - * - * This provides a more user-friendly promise-based interface to - * {@link child_process.spawn}. The obj - * - * @param command Name of the shell command to run. - * @param args Array of arguments to pass to the command. - * @param options Parameters to change how the command is run and resolved. - * - * @returns Command object for handling in client code. - */ -export const runCommand = ( - command: string, - args: string[] = [], - options?: CliOptions, -): AsyncCommand => { - const optionsWithDefaults = { ...DEFAULT_CLI_OPTIONS, ...options }; - const process = spawn(command, args, { - ...optionsWithDefaults, - stdio: "pipe", - }); - const complete = new Promise((resolve, reject) => { - let threwError = false; - - let stdout = ""; - process.stdout.on("data", (data) => { - stdout += data.toString(); - }); - process.stderr.on("data", (data) => { - threwError = true; - process.kill(); - reject(new Error(`command output to stderr: ${data.toString()}`)); - }); - - const timer = setTimeout(() => { - threwError = true; - process.kill(); - reject( - new Error(`max timeout of ${optionsWithDefaults.timeoutMs}ms reached`), - ); - }, optionsWithDefaults.timeoutMs); - process.on("exit", (code) => { - if (threwError) { - return; - } - clearTimeout(timer); - if (code !== null && code !== 0) { - reject(new Error(`command exited with non-zero code: ${code}`)); - return; - } - resolve(stdout); - }); - process.on("error", (error) => { - clearTimeout(timer); - if (!threwError) { - reject(new Error(`command errored: ${error}`)); - threwError = true; - } - }); - }); - return { - complete, - process, - }; -}; - -export const npmCmd = os.platform() === "win32" ? "npm.cmd" : "npm"; diff --git a/test/lib/expect.ts b/test/lib/expect.ts index 8d6dd41..3744310 100644 --- a/test/lib/expect.ts +++ b/test/lib/expect.ts @@ -6,13 +6,13 @@ import { areEqual, displayValue, matches } from "./utils"; class ExpectError extends Error { - public constructor(reason: string, expected: unknown, actual: unknown) { - super( - `${reason}\n` + - `\texpected: ${displayValue(expected)}\n` + - `\tactual : ${displayValue(actual)}`, - ); - } + public constructor(reason: string, expected: unknown, actual: unknown) { + super( + `${reason}\n` + + `\texpected: ${displayValue(expected)}\n` + + `\tactual : ${displayValue(actual)}` + ); + } } /** @@ -24,134 +24,138 @@ class ExpectError extends Error { * Expect. */ export class Expect { - protected readonly value: T; + protected readonly value: T; - /** - * Create a new expectation around a value. - * - * @param value Value to place assertions upon. - */ - public constructor(value: T) { - this.value = value; - } + /** + * Create a new expectation around a value. + * + * @param value Value to place assertions upon. + */ + public constructor(value: T) { + this.value = value; + } - /** - * Expect the value to equal an expected value. - * - * Note that strict equality checking is used for primitives and structural - * equality is used for objects. - * - * @param expected Expected value. - * - * @throws ExpectError If the actual value does not equal the expected value. - */ - public toEqual(expected: T): void { - if (!areEqual(this.value, expected)) { - throw new ExpectError( - "value does not equal expected", - expected, - this.value, - ); - } - } + /** + * Expect the value to equal an expected value. + * + * Note that strict equality checking is used for primitives and structural + * equality is used for objects. + * + * @param expected Expected value. + * + * @throws ExpectError If the actual value does not equal the expected value. + */ + public toEqual(expected: T): void { + if (!areEqual(this.value, expected)) { + throw new ExpectError( + `value does not equal expected`, + expected, + this.value + ); + } + } } /** * String-specific Expect assertions. */ export class StringExpect extends Expect { - /** - * Expect the string value to match a RegExp pattern. - * - * @param pattern Regular expression to match against. - * - * @throws ExpectError If the actual value does not match the expected - * RegExp pattern. - */ - public toMatch(pattern: RegExp): void { - if (!this.value.match(pattern)) { - throw new ExpectError( - "value does not match expected pattern", - pattern, - this.value, - ); - } - } + /** + * Expect the string value to match a RegExp pattern. + * + * @param pattern Regular expression to match against. + * + * @throws ExpectError If the actual value does not match the expected + * RegExp pattern. + */ + public toMatch(pattern: RegExp): void { + if (!this.value.match(pattern)) { + throw new ExpectError( + `value does not match expected pattern`, + pattern, + this.value + ); + } + } - /** - * Expect the string value to start with a particular prefix. - * - * @param prefix Prefix that the string is expected to start with. - * - * @throws ExpectError If the actual value does not start with the expected - * prefix. - */ - public toStartWith(prefix: string): void { - if (!this.value.startsWith(prefix)) { - throw new ExpectError( - "value does not start with expected prefix", - prefix, - this.value, - ); - } - } + /** + * Expect the string value to start with a particular prefix. + * + * @param prefix Prefix that the string is expected to start with. + * + * @throws ExpectError If the actual value does not start with the expected + * prefix. + */ + public toStartWith(prefix: string): void { + if (!this.value.startsWith(prefix)) { + throw new ExpectError( + `value does not start with expected prefix`, + prefix, + this.value + ); + } + } - /** - * Expect the string value to end with a particular suffix. - * - * @param suffix Suffix that the string is expected to end with. - * - * @throws ExpectError If the actual value does not end with the expected - * suffix. - */ - public toEndWith(suffix: string): void { - if (!this.value.endsWith(suffix)) { - throw new ExpectError( - "value does not end with expected suffix", - suffix, - this.value, - ); - } - } + /** + * Expect the string value to end with a particular suffix. + * + * @param suffix Suffix that the string is expected to end with. + * + * @throws ExpectError If the actual value does not end with the expected + * suffix. + */ + public toEndWith(suffix: string): void { + if (!this.value.endsWith(suffix)) { + throw new ExpectError( + `value does not end with expected suffix`, + suffix, + this.value + ); + } + } } /** * Function-specific Expect assertions. */ export class FunctionExpect extends Expect<() => T> { - /** - * Expect the function to throw an Error with error message matching a - * string or pattern. - * - * @param pattern String that exactly matches the error message or RegExp - * that should match the error message. - * - * @throws ExpectError If the function does not throw an error, throws a - * non-Error value, or throws an Error whose message does not match - * the expected pattern. - */ - public toThrowErrorMatching(pattern: string | RegExp): void { - try { - this.value(); - } catch (error) { - if (!(error instanceof Error)) { - throw new ExpectError("function threw non-Error value", pattern, error); - } - if (!matches(error.message, pattern)) { - throw new ExpectError( - `thrown Error's message does not match pattern`, - pattern, - error.message, - ); - } - return; - } - throw new ExpectError( - "function did not throw expected error", - pattern, - null, - ); - } + /** + * Expect the function to throw an Error with error message matching a + * string or pattern. + * + * @param pattern String that exactly matches the error message or RegExp + * that should match the error message. + * + * @throws ExpectError If the function does not throw an error, throws a + * non-Error value, or throws an Error whose message does not match + * the expected pattern. + */ + public toThrowErrorMatching(pattern: string | RegExp): void { + try { + this.value(); + } catch (error) { + if (!(error instanceof Error)) { + throw new ExpectError( + `function threw non-Error value`, + pattern, + error + ); + } + if (!matches(error.message, pattern)) { + throw new ExpectError( + `thrown Error's message does not match pattern`, + pattern, + error.message + ); + } + return; + } + throw new ExpectError( + `function did not throw expected error`, + pattern, + null + ); + } } /** @@ -198,11 +202,11 @@ export function expect(fn: () => T): FunctionExpect; * @param value Value to place expectations upon. */ export function expect(value: unknown): Expect { - if (typeof value === "string") { - return new StringExpect(value); - } - if (typeof value === "function") { - return new FunctionExpect(value as () => unknown); - } - return new Expect(value); + if (typeof value === "string") { + return new StringExpect(value); + } + if (typeof value === "function") { + return new FunctionExpect(value as () => unknown); + } + return new Expect(value); } diff --git a/test/lib/harness.ts b/test/lib/harness.ts index d371e39..3650145 100644 --- a/test/lib/harness.ts +++ b/test/lib/harness.ts @@ -7,66 +7,68 @@ import { expect } from "./expect"; import { displayValue, shuffle } from "./utils"; interface Test { - readonly name: string; + readonly name: string; - runTest(): void | Promise; + runTest(): void | Promise; } type TestResult = { - testName: string; + testName: string; } & ( - | { - result: "pass"; - } - | { - result: "fail"; - error: Error; - } + | { + result: "pass"; + } + | { + result: "fail"; + error: Error; + } ); const runTest = async (test: Test): Promise => { - let result: TestResult; - try { - await test.runTest(); - result = { - testName: test.name, - result: "pass", - }; - } catch (error) { - result = { - testName: test.name, - result: "fail", - error: - error instanceof Error - ? error - : new Error(`threw non-error object: ${displayValue(error)}`), - }; - } - return result; + let result: TestResult; + try { + await test.runTest(); + result = { + testName: test.name, + result: "pass", + }; + } catch (error) { + result = { + testName: test.name, + result: "fail", + error: + error instanceof Error + ? error + : new Error( + `threw non-error object: ${displayValue(error)}` + ), + }; + } + return result; }; /** * Context object that is passed into a test suite definition. */ export interface TestSuiteContext { - /** - * Define a test in this test suite. - * - * Tests are functions that pass if they are executed and don't throw (or - * that resolve for async tests), and that fail if they throw an error (or - * reject for async tests). - * - * Note that tests are executed in a random order within a test suite in - * order to prevent accidentally creating order dependencies between tests, - * which can result in brittle tests and is a code smell that might indicate - * that the code under test is also brittle. - */ - test: (name: string, def: () => void | Promise) => void; - /** - * Expectation builder function used to build human-readable assertions and - * errors. - */ - expect: typeof expect; + /** + * Define a test in this test suite. + * + * Tests are functions that pass if they are executed and don't throw (or + * that resolve for async tests), and that fail if they throw an error (or + * reject for async tests). + * + * Note that tests are executed in a random order within a test suite in + * order to prevent accidentally creating order dependencies between tests, + * which can result in brittle tests and is a code smell that might indicate + * that the code under test is also brittle. + */ + test: (name: string, def: () => void | Promise) => void; + /** + * Expectation builder function used to build human-readable assertions and + * errors. + */ + expect: typeof expect; } /** @@ -83,36 +85,36 @@ export interface TestSuiteContext { * @param def Function used to declare the tests */ export const testSuite = ( - suiteName: string, - def: (ctx: TestSuiteContext) => void, + suiteName: string, + def: (ctx: TestSuiteContext) => void ): void => { - const tests: Test[] = []; - const test = (name: string, runTest: () => void | Promise): void => { - tests.push({ name, runTest }); - }; - def({ test, expect }); + const tests: Test[] = []; + const test = (name: string, runTest: () => void | Promise): void => { + tests.push({ name, runTest }); + }; + def({ test, expect }); - // Randomly shuffle the tests so that we can catch accidental order - // dependencies. - shuffle(tests); - (async () => { - const results = await Promise.all(tests.map((test) => runTest(test))); - let passed = 0; - for (const testResult of results) { - if (testResult.result === "fail") { - console.error( - `[TEST FAILURE] "${suiteName}": "${testResult.testName}": ` + - `${testResult.error.stack}\n`, - ); - continue; - } - passed += 1; - } - console.info( - `[TEST] suite "${suiteName}": ${passed} of ${tests.length} succeeded\n\n`, - ); - if (passed < tests.length) { - process.exitCode = 1; - } - })(); + // Randomly shuffle the tests so that we can catch accidental order + // dependencies. + shuffle(tests); + (async () => { + const results = await Promise.all(tests.map((test) => runTest(test))); + let passed = 0; + for (const testResult of results) { + if (testResult.result === "fail") { + console.error( + `[TEST FAILURE] "${suiteName}": "${testResult.testName}": ` + + `${testResult.error.stack}\n` + ); + continue; + } + passed += 1; + } + console.info( + `[TEST] suite "${suiteName}": ${passed} of ${tests.length} succeeded\n\n` + ); + if (passed < tests.length) { + process.exitCode = 1; + } + })(); }; diff --git a/test/lib/utils.ts b/test/lib/utils.ts index 2c77e1c..cdccd73 100644 --- a/test/lib/utils.ts +++ b/test/lib/utils.ts @@ -9,43 +9,43 @@ * @param arr Array to shuffle. */ export const shuffle = (arr: T[]): void => { - let j: number; - let x: T; - for (let i = arr.length - 1; i > 0; i--) { - j = Math.floor(Math.random() * (i + 1)); - x = arr[i]; - arr[i] = arr[j]; - arr[j] = x; - } + let j: number; + let x: T; + for (let i = arr.length - 1; i > 0; i--) { + j = Math.floor(Math.random() * (i + 1)); + x = arr[i]; + arr[i] = arr[j]; + arr[j] = x; + } }; const areArraysEqual = (a: T[], b: T[]): boolean => { - if (a.length !== b.length) { - return false; - } - for (let i = 0; i < a.length; i++) { - if (!areEqual(a[i], b[i])) { - return false; - } - } - return true; + if (a.length != b.length) { + return false; + } + for (let i = 0; i < a.length; i++) { + if (!areEqual(a[i], b[i])) { + return false; + } + } + return true; }; const areObjectsEqual = >( - a: T, - b: T, + a: T, + b: T ): boolean => { - const aKeys = Object.keys(a) as Array; - const bKeys = Object.keys(b) as Array; - if (aKeys.length !== bKeys.length) { - return false; - } - for (const key of aKeys) { - if (!areEqual(a[key], b[key])) { - return false; - } - } - return true; + const aKeys = Object.keys(a) as Array; + const bKeys = Object.keys(b) as Array; + if (aKeys.length !== bKeys.length) { + return false; + } + for (const key of aKeys) { + if (!areEqual(a[key], b[key])) { + return false; + } + } + return true; }; /** @@ -58,19 +58,19 @@ const areObjectsEqual = >( * @return Whether the two values are structurally equal. */ export const areEqual = (a: T, b: T): boolean => { - if (Array.isArray(a) && Array.isArray(b)) { - return areArraysEqual(a, b); - } - if (a instanceof RegExp && b instanceof RegExp) { - return a.source === b.source; - } - if (typeof a === "object" && typeof b === "object") { - return areObjectsEqual( - a as Record, - b as Record, - ); - } - return a === b; + if (Array.isArray(a) && Array.isArray(b)) { + return areArraysEqual(a, b); + } + if (a instanceof RegExp && b instanceof RegExp) { + return a.source === b.source; + } + if (typeof a === "object" && typeof b === "object") { + return areObjectsEqual( + a as Record, + b as Record + ); + } + return a === b; }; /** @@ -84,10 +84,10 @@ export const areEqual = (a: T, b: T): boolean => { * @param pattern String or RegExp pattern to match value against. */ export const matches = (value: string, pattern: string | RegExp): boolean => { - if (typeof pattern === "string") { - return value === pattern; - } - return pattern.test(value); + if (typeof pattern === "string") { + return value === pattern; + } + return pattern.test(value); }; /** @@ -102,11 +102,11 @@ export const matches = (value: string, pattern: string | RegExp): boolean => { * @return Rendered value to display. */ export const displayValue = (value: unknown): string => { - if (value === undefined) { - return "undefined"; - } - if (value instanceof RegExp) { - return value.toString(); - } - return JSON.stringify(value); + if (value === undefined) { + return "undefined"; + } + if (value instanceof RegExp) { + return value.toString(); + } + return JSON.stringify(value); }; diff --git a/test/run-e2e.ts b/test/run-e2e.ts deleted file mode 100644 index 1fdfc96..0000000 --- a/test/run-e2e.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -import { fork } from "node:child_process"; -import * as fs from "node:fs"; -import * as path from "node:path"; - -import { shuffle } from "./lib/utils"; - -const TEST_SUITES_DIR = path.join(__dirname, "e2e"); -const files = fs.readdirSync(TEST_SUITES_DIR); -// Shuffle test suites to detect ordering dependencies between them. -shuffle(files); -for (const file of files) { - const fullPath = path.join(TEST_SUITES_DIR, file); - fork(path.relative(process.cwd(), fullPath)).on("exit", (code) => { - if (code !== 0) { - process.exitCode = 1; - } - }); -} diff --git a/test/run-tests.ts b/test/run-tests.ts index a928ed2..6850b60 100644 --- a/test/run-tests.ts +++ b/test/run-tests.ts @@ -3,21 +3,22 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { fork } from "node:child_process"; -import * as fs from "node:fs"; -import * as path from "node:path"; +import { fork } from "child_process"; +import * as fs from "fs"; +import * as path from "path"; import { shuffle } from "./lib/utils"; const TEST_SUITES_DIR = path.join(__dirname, "test-suites"); + const files = fs.readdirSync(TEST_SUITES_DIR); // Shuffle test suites to detect ordering dependencies between them. shuffle(files); for (const file of files) { - const fullPath = path.join(TEST_SUITES_DIR, file); - fork(path.relative(process.cwd(), fullPath)).on("exit", (code) => { - if (code !== 0) { - process.exitCode = 1; - } - }); + const fullPath = path.join(TEST_SUITES_DIR, file); + fork(path.relative(process.cwd(), fullPath)).on("exit", (code) => { + if (code !== 0) { + process.exitCode = 1; + } + }); } diff --git a/test/test-suites/rendering.tsx b/test/test-suites/rendering.tsx index ef2e89b..b4cb3b2 100644 --- a/test/test-suites/rendering.tsx +++ b/test/test-suites/rendering.tsx @@ -3,147 +3,104 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { type Component, createElement, Fragment } from "../../dist"; +import { Component, createElement } from "../../dist"; import { renderPage } from "../../dist/render"; import { testSuite } from "../lib"; testSuite("renderPage", ({ test, expect }) => { - test("throws an Error when root elem is not html tag", () => { - expect(() => renderPage(

)).toThrowErrorMatching( - "attempted to render page with non-HTML root element div", - ); - }); + test("throws an Error when root elem is not html tag", () => { + expect(() => renderPage(
)).toThrowErrorMatching( + "attempted to render page with non-HTML root element div" + ); + }); - test("outputs a HTML5 DOCTYPE declaration", () => { - const html = renderPage(); - expect(html).toStartWith(""); - }); + test("outputs a HTML5 DOCTYPE declaration", () => { + const html = renderPage(); + expect(html).toStartWith(""); + }); - test("escapes HTML in tag names", () => { - const html = renderPage({createElement("div>); - expect(html).toEqual( - "", - ); - }); + test("escapes HTML in tag names", () => { + const html = renderPage( + {createElement("div> + ); + expect(html).toEqual( + "" + ); + }); - test("renders html attributes", () => { - const html = renderPage( - -
- , - ); - expect(html).toEqual( - '
', - ); - }); + test("renders html attributes", () => { + const html = renderPage( + +
+ + ); + expect(html).toEqual( + '
' + ); + }); - test("renders common html tags", () => { - const html = renderPage( - - - - </head> - <body> - <div /> - </body> - </html>, - ); - expect(html).toEqual( - "<!DOCTYPE html><html><head><title>
", - ); - }); + test("renders common html tags", () => { + const html = renderPage( + + + + </head> + <body> + <div /> + </body> + </html> + ); + expect(html).toEqual( + "<!DOCTYPE html><html><head><title>
" + ); + }); - test("renders text nodes", () => { - const html = renderPage(There are three lights!); - expect(html).toEqual("There are three lights!"); - }); + test("renders text nodes", () => { + const html = renderPage(There are three lights!); + expect(html).toEqual( + "There are three lights!" + ); + }); - test("renders spliced number nodes", () => { - const nLights = 3; - const html = renderPage(There are {nLights} lights!); - expect(html).toEqual("There are 3 lights!"); - }); + test("renders spliced number nodes", () => { + const nLights = 3; + const html = renderPage(There are {nLights} lights!); + expect(html).toEqual("There are 3 lights!"); + }); - test("renders spliced arrays", () => { - const Light: Component<{ lightN: number }> = ({ lightN }) => ( -
{lightN}
- ); - const lights = [1, 2, 3]; - const html = renderPage( - - There are{" "} - {lights.map((lightN) => ( - - ))}{" "} - lights! - , - ); - expect(html).toEqual( - "There are
1
2
3
lights!", - ); - }); + test("renders spliced arrays", () => { + const Light: Component<{ lightN: number }> = ({ lightN }) => ( +
{lightN}
+ ); + const lights = [1, 2, 3]; + const html = renderPage( + + There are{" "} + {lights.map((lightN) => ( + + ))}{" "} + lights! + + ); + expect(html).toEqual( + "There are
1
2
3
lights!" + ); + }); - test("renders components w/ custom properties", () => { - interface LightProps { - nLights: number; - } - const Light: Component = ({ nLights }) => ( -
{nLights} lights
- ); - const html = renderPage( - - There are ! - , - ); - expect(html).toEqual( - "There are
3 lights
!", - ); - }); - - test("renders fragment children only", () => { - const html = renderPage( - - -
test of
-
fragments
-
- , - ); - expect(html).toEqual( - "
test of
fragments
", - ); - }); - - test("renders unescaped HTML via dangerouslySetInnerHTML", () => { - const html = renderPage( - -
red alert!
", - }} - /> - , - ); - expect(html).toEqual( - "
red alert!
", - ); - }); - - test("throws error when both dangerouslySetInnerHTML and children prop present", () => { - expect(() => - renderPage( - -
set phasers to kill
", - }} - > -
set phasers to stun
-
- , - ), - ).toThrowErrorMatching( - 'An element with children may not have a "dangerouslySetInnerHTML" prop since children would be overriden', - ); - }); + test("renders components w/ custom properties", () => { + interface LightProps { + nLights: number; + } + const Light: Component = ({ nLights }) => ( +
{nLights} lights
+ ); + const html = renderPage( + + There are ! + + ); + expect(html).toEqual( + "There are
3 lights
!" + ); + }); }); diff --git a/test/tsconfig.json b/test/tsconfig.json index 6996e0f..e6edc8b 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -1,7 +1,7 @@ { - "extends": "../tsconfig-base.json", - "compilerOptions": { - "jsx": "react", - "jsxFactory": "createElement" - } + "extends": "../tsconfig-base.json", + "compilerOptions": { + "jsx": "react", + "jsxFactory": "createElement" + } } diff --git a/tsconfig-base.json b/tsconfig-base.json index c4a0bb4..821f547 100644 --- a/tsconfig-base.json +++ b/tsconfig-base.json @@ -1,13 +1,14 @@ { - "compilerOptions": { - "module": "CommonJS", - "moduleResolution": "node", - "target": "ES2018", - "lib": ["ES2018"], - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - } + "compilerOptions": { + "esModuleInterop": true, + "module": "CommonJS", + "moduleResolution": "node", + "target": "ES2018", + "lib": ["ES2018"], + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + } } diff --git a/tsconfig.json b/tsconfig.json index 0b67cbd..10006e4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,9 @@ { - "extends": "./tsconfig-base.json", - "compilerOptions": { - "declaration": true, - "sourceMap": true, - "outDir": "./dist" - }, - "include": ["src/**/*.ts"] + "extends": "./tsconfig-base.json", + "compilerOptions": { + "declaration": true, + "sourceMap": true, + "outDir": "./dist" + }, + "include": ["src/**/*.ts"] }