website now works

This commit is contained in:
polv committed 2020-12-16 05:00:20 +07:00
1 parent ce56fcb91c
commit 3daa9f82e7
15 files changed
+241 -137

No files matched your search

+1
View File
@@ -16,5 +16,6 @@ module.exports = {
rules: {
'require-await': 0,
'vue/no-v-html': 0,
'import/order': 0,
},
}
+43
View File
@@ -1,3 +1,46 @@
import type { ITheme } from '~/server/theme'
export const THEME: ITheme = JSON.parse(process.env.THEME!)
export const api = async (
url: string,
opts: RequestInit & {
params?: Record<string, any>
} = {}
) => {
if (!url.startsWith('/api')) {
return {
error: {
message: 'malformed API route',
},
}
}
const baseURL = new URL(
typeof location !== 'undefined'
? location.origin
: `http://localhost:${process.env.PORT}`
)
baseURL.pathname = url
Object.entries(opts.params || {}).map(([k, v]) => {
if (v) {
baseURL.searchParams.set(k, v)
}
})
const r = await fetch(baseURL.href, opts)
try {
/**
* Does not rely on `r.ok`, but rather, errorhandler
*/
return r.json()
} catch (_) {}
return {
error: {
statusCode: r.status,
message: r,
},
}
}
+5 -18
View File
@@ -4,19 +4,15 @@
<nav v-if="count > 5">
<ul>
<li v-if="page > 2">
<nuxt-link :to="makePageUrl(1)" aria-label="page 1"> &lt; </nuxt-link>
</li>
<li v-if="page > 1">
<nuxt-link :to="makePageUrl(1)" aria-label="page 1">1</nuxt-link>
</li>
<li v-if="page > 4">
<li v-if="page > 3">
<span> &hellip; </span>
</li>
<li v-if="page > 3">
<li v-if="page > 2">
<nuxt-link
:to="makePageUrl(page - 1)"
:aria-label="`page ${page - 1}`"
@@ -31,7 +27,7 @@
</span>
</li>
<li v-if="page < total - 2">
<li v-if="page < total - 1">
<nuxt-link
:to="makePageUrl(page + 1)"
:aria-label="`page ${page + 1}`"
@@ -40,7 +36,7 @@
</nuxt-link>
</li>
<li v-if="page < total - 3">
<li v-if="page < total - 2">
<span> &hellip; </span>
</li>
@@ -49,15 +45,6 @@
{{ total }}
</nuxt-link>
</li>
<li v-if="page < total - 1">
<nuxt-link
:to="makePageUrl(page + 1)"
:aria-label="`page ${page + 1}`"
>
&gt;
</nuxt-link>
</li>
</ul>
</nav>
</article>
@@ -86,7 +73,7 @@ export default class PostQuery extends Vue {
...this.$route.query,
page: page.toString(),
},
})
}).href
}
}
</script>
+13 -6
View File
@@ -14,11 +14,7 @@
</ul>
<form @submit.prevent="doSearch">
<input
type="search"
:value="$route.query.q"
placeholder="Search..."
/>
<input v-model="q" type="search" placeholder="Search..." />
<div class="icon">🔎</div>
</form>
</nav>
@@ -34,9 +30,20 @@ import { THEME } from '~/assets/global'
@Component
export default class DefaultLayout extends Vue {
theme = THEME
q = this.$route.query.q || ''
doSearch() {
alert('not implemented')
let path = this.$route.path
if (['/blog', '/tag'].includes(path)) {
path = '/blog'
}
this.$router.push({
path,
query: {
q: this.q,
},
})
}
}
</script>
+7 -3
View File
@@ -1,8 +1,12 @@
<template>
<div>
<h1 v-if="error.statusCode === 404">Page not found</h1>
<h1 v-else>An error occurred</h1>
<NuxtLink to="/">Home page</NuxtLink>
<section>
<h2 v-if="error.statusCode === 404">Page not found</h2>
<pre v-else style="width: 100%">{{ error }}</pre>
</section>
<section>
<NuxtLink to="/">Home page</NuxtLink>
</section>
</div>
</template>
+3 -7
View File
@@ -4,6 +4,7 @@ import { getTheme } from './server/theme'
const config = async (): Promise<NuxtConfig> => {
const theme = getTheme()
const PORT = process.env.PORT || '3000'
return {
// Global page headers (https://go.nuxtjs.dev/config-head)
@@ -56,18 +57,13 @@ const config = async (): Promise<NuxtConfig> => {
],
// Modules (https://go.nuxtjs.dev/config-modules)
modules: [
// https://go.nuxtjs.dev/axios
'@nuxtjs/axios',
],
// Axios module configuration (https://go.nuxtjs.dev/config-axios)
axios: {},
modules: [],
// Build Configuration (https://go.nuxtjs.dev/config-build)
build: {},
env: {
THEME: JSON.stringify(theme),
PORT,
},
serverMiddleware: [{ path: '/api', handler: '~/server/index.ts' }],
}
+3 -2
View File
@@ -14,15 +14,16 @@
},
"dependencies": {
"@nuxt/typescript-runtime": "^2.0.0",
"@nuxtjs/axios": "^5.12.2",
"@patarapolw/scope-css": "^1.3.0",
"@types/express": "^4.17.9",
"@types/js-yaml": "^3.12.5",
"@types/morgan": "^1.9.2",
"better-sqlite3": "^7.1.1",
"cheerio": "^1.0.0-rc.3",
"core-js": "^3.6.5",
"express": "^4.17.1",
"js-yaml": "^3.14.1",
"morgan": "^1.10.0",
"nuxt": "^2.14.6",
"showdown": "^1.9.1",
"zod": "^1.11.11"
@@ -66,4 +67,4 @@
"pnpm": "please-use-yarn"
},
"engineStrict": true
}
}
+11 -1
View File
@@ -6,10 +6,15 @@
<script lang="ts">
import { Vue, Component } from 'nuxt-property-decorator'
import { api } from '~/assets/global'
@Component<TagPage>({
watch: {
'$route.query.q': '$fetch',
'$route.query.page': '$fetch',
},
async fetch() {
const { result, count } = await this.$axios.$get('/q', {
const { result, count, error } = await api('/api/q', {
params: {
q: this.$route.query.q,
page: this.$route.query.page,
@@ -17,6 +22,11 @@ import { Vue, Component } from 'nuxt-property-decorator'
},
})
if (error) {
this.$nuxt.error(error)
return
}
this.posts = result
this.count = count
},
+11 -1
View File
@@ -9,16 +9,26 @@
<script lang="ts">
import { Vue, Component } from 'nuxt-property-decorator'
import { api } from '~/assets/global'
@Component<BlogPage>({
watch: {
'$route.query.q': '$fetch',
'$route.query.page': '$fetch',
},
async fetch() {
const { result, count } = await this.$axios.$get('/api/q', {
const { result, count, error } = await api('/api/q', {
params: {
q: this.$route.query.q,
page: this.$route.query.page,
},
})
if (error) {
this.$nuxt.error(error)
return
}
this.posts = result
this.count = count
},
+83
View File
@@ -0,0 +1,83 @@
<template>
<p v-if="$fetchState.pending"></p>
<p v-else-if="$fetchState.error">
An error occurred {{ $fetchState.error.message }}
</p>
<section v-else>
<section>
<h2>
{{ post.title }}
</h2>
<small>
<span>
by
<a
v-if="theme.author.url"
:href="theme.author.url"
target="_blank"
rel="noopener"
>
{{ theme.author.name }}
</a>
<span v-else>
{{ theme.author.name }}
</span>
</span>
<span v-if="post.date" style="float: right">
{{ post.date | formatDate }}
</span>
</small>
</section>
<section v-html="post.content"></section>
<section class="tags-container">
<span>Tags:</span>
<span v-for="t in post.tag || []" :key="t">
<nuxt-link :to="`/tag/${t}`">
{{ t }}
</nuxt-link>
</span>
</section>
</section>
</template>
<script lang="ts">
import { Vue, Component } from 'nuxt-property-decorator'
import { api, THEME } from '~/assets/global'
@Component<PostPage>({
async fetch() {
const r = await api('/api', {
params: {
path: this.$route.params.pathMatch,
},
})
if (r.error) {
this.$nuxt.error(r.error)
return
}
this.post = r
},
})
export default class PostPage extends Vue {
post: {
date?: string
title: string
image?: string
tag?: string[]
category?: string
content: string
} | null = null
theme = THEME
}
</script>
<style scoped>
.tags-container > span + span {
margin-left: 0.6em;
}
</style>
+4 -4
View File
@@ -73,7 +73,7 @@ export class MakeHTML {
.update(filename)
.digest()
.toString('hex')
.substr(8)
.substr(0, 8)
const $div = this.$(`<div id="${id}">`)
$div.html(await this.getHTML(filename))
@@ -87,10 +87,10 @@ export class MakeHTML {
return {
$: $div,
html() {
return $div.html() || ''
html: () => {
return this.$('<div>').append($div).html() || ''
},
clean() {
clean: () => {
return jieba.cutForSearch($div.text() || '').join(' ')
},
}
+14 -12
View File
@@ -132,7 +132,6 @@ export class Database {
[image],
tag,
category,
excerptHtml excerpt,
contentHtml content
FROM files f
JOIN q ON q.path = f.path
@@ -155,7 +154,6 @@ export class Database {
image?: string
tag?: string[]
category?: string
excerpt: string
content: string
}
}
@@ -167,7 +165,10 @@ export class Database {
limit: number
}
) {
return this._search(q, opts, 'RANK')
return this._search(q, {
...opts,
orderedBy: 'RANK',
})
}
public by(
@@ -177,11 +178,11 @@ export class Database {
limit: number
}
) {
return this._search(
q,
opts,
'priority DESC, [date] DESC, createdAt DESC, updatedAt DESC'
)
return this._search(q, {
...opts,
orderedBy: 'priority DESC, [date] DESC, createdAt DESC, updatedAt DESC',
where: '[date] IS NOT NULL',
})
}
private _search(
@@ -189,13 +190,14 @@ export class Database {
opts: {
offset: number
limit: number
},
orderedBy: string
orderedBy: string
where?: string
}
) {
const fromSegment = /* sql */ `
FROM files f
JOIN q ON q.path = f.path
${q ? `WHERE q = @q` : ''}
WHERE ${q ? `q = @q` : 'TRUE'} ${opts.where ? `AND ${opts.where}` : ''}
`
const count =
@@ -220,7 +222,7 @@ export class Database {
category,
excerptHtml excerpt
${fromSegment}
ORDER BY ${orderedBy}
ORDER BY ${opts.orderedBy}
LIMIT ${opts.limit} OFFSET ${opts.offset}
`
)
+12 -3
View File
@@ -1,19 +1,22 @@
import express from 'express'
import morgan from 'morgan'
import * as z from 'zod'
import { Database } from './db'
const app = express()
app.use(morgan('dev'))
const db = new Database({ readonly: true })
app.get('/', (req, res) => {
const { id } = z
const { path } = z
.object({
id: z.string(),
path: z.string(),
})
.parse(req.query)
const r = db.get(id)
const r = db.get(path)
if (!r) {
res.sendStatus(404)
return
@@ -55,4 +58,10 @@ app.get('/q', (req, res) => {
)
})
app.use((err: Error, _: express.Request, res: express.Response) => {
// eslint-disable-next-line no-console
console.error(err.stack)
res.status(500).send(err)
})
export default app
+1 -1
View File
@@ -15,7 +15,7 @@
"~/*": ["./*"],
"@/*": ["./*"]
},
"types": ["@types/node", "@nuxt/types", "@nuxtjs/axios"]
"types": ["@types/node", "@nuxt/types"]
},
"exclude": ["node_modules", ".nuxt", "dist"]
}
+30 -79
View File
@@ -1242,17 +1242,6 @@
webpack-node-externals "^2.5.2"
webpackbar "^4.0.0"
"@nuxtjs/axios@^5.12.2":
version "5.12.4"
resolved "https://registry.yarnpkg.com/@nuxtjs/axios/-/axios-5.12.4.tgz#596ed88441aaedc5e74349f34fff2a462b02d01c"
integrity sha512-NKDIkrhtteOwC163Qlglw7YyjWHfLecpC/wXax4Z2tVVDlYnvSBa1KGoH9AnDY30lfvi0gjBKWCcTnUY8PaWDA==
dependencies:
"@nuxtjs/proxy" "^2.1.0"
axios "^0.21.0"
axios-retry "^3.1.9"
consola "^2.15.0"
defu "^3.2.2"
"@nuxtjs/eslint-config-typescript@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@nuxtjs/eslint-config-typescript/-/eslint-config-typescript-3.0.0.tgz#4c307ba1d7038d3d4a6aa40ebd4e0bd80a9af512"
@@ -1284,13 +1273,6 @@
consola "^2.11.3"
eslint-loader "^4.0.2"
"@nuxtjs/proxy@^2.1.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@nuxtjs/proxy/-/proxy-2.1.0.tgz#fa7715a11d237fa1273503c4e9e137dd1bf5575b"
integrity sha512-/qtoeqXgZ4Mg6LRg/gDUZQrFpOlOdHrol/vQYMnKu3aN3bP90UfOUB3QSDghUUK7OISAJ0xp8Ld78aHyCTcKCQ==
dependencies:
http-proxy-middleware "^1.0.6"
"@nuxtjs/youch@^4.2.3":
version "4.2.3"
resolved "https://registry.yarnpkg.com/@nuxtjs/youch/-/youch-4.2.3.tgz#36f8b22df5a0efaa81373109851e1d857aca6bed"
@@ -1476,13 +1458,6 @@
"@types/relateurl" "*"
"@types/uglify-js" "*"
"@types/http-proxy@^1.17.4":
version "1.17.4"
resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.4.tgz#e7c92e3dbe3e13aa799440ff42e6d3a17a9d045b"
integrity sha512-IrSHl2u6AWXduUaDLqYpt45tLVCtYv7o4Z0s1KghBCDgIIS9oW5K1H8mZG/A2CfeLdEa7rTd1ACOiHBc1EMT2Q==
dependencies:
"@types/node" "*"
"@types/integer@*":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/integer/-/integer-1.0.1.tgz#025d87e30d97f539fcc6087372af7d3672ffbbe6"
@@ -1525,6 +1500,13 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/morgan@^1.9.2":
version "1.9.2"
resolved "https://registry.yarnpkg.com/@types/morgan/-/morgan-1.9.2.tgz#450f958a4d3fb0694a3ba012b09c8106f9a2885e"
integrity sha512-edtGMEdit146JwwIeyQeHHg9yID4WSolQPxpEorHmN3KuytuCHyn2ELNr5Uxy8SerniFbbkmgKMrGM933am5BQ==
dependencies:
"@types/node" "*"
"@types/node-sass@^4.11.1":
version "4.11.1"
resolved "https://registry.yarnpkg.com/@types/node-sass/-/node-sass-4.11.1.tgz#bda27c5181cbf7c090c3058e119633dfb2b6504c"
@@ -2306,20 +2288,6 @@ autoprefixer@^9.6.1:
postcss "^7.0.32"
postcss-value-parser "^4.1.0"
axios-retry@^3.1.9:
version "3.1.9"
resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.1.9.tgz#6c30fc9aeb4519aebaec758b90ef56fa03fe72e8"
integrity sha512-NFCoNIHq8lYkJa6ku4m+V1837TP6lCa7n79Iuf8/AqATAHYB0ISaAS1eyIenDOfHOLtym34W65Sjke2xjg2fsA==
dependencies:
is-retry-allowed "^1.1.0"
axios@^0.21.0:
version "0.21.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.0.tgz#26df088803a2350dff2c27f96fef99fe49442aca"
integrity sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==
dependencies:
follow-redirects "^1.10.0"
babel-eslint@^10.1.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232"
@@ -2372,6 +2340,13 @@ base@^0.11.1:
mixin-deep "^1.2.0"
pascalcase "^0.1.1"
basic-auth@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a"
integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==
dependencies:
safe-buffer "5.1.2"
better-sqlite3@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-7.1.1.tgz#107457a8b770cfb16be646e347c17b42bc204dd3"
@@ -3584,6 +3559,11 @@ depd@~1.1.2:
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
depd@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
des.js@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843"
@@ -4217,11 +4197,6 @@ etag@^1.8.1, etag@~1.8.1:
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
eventemitter3@^4.0.0:
version "4.0.7"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
events@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379"
@@ -4547,11 +4522,6 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
follow-redirects@^1.0.0, follow-redirects@^1.10.0:
version "1.13.1"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7"
integrity sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==
for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -5076,26 +5046,6 @@ http-errors@~1.7.2:
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
http-proxy-middleware@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-1.0.6.tgz#0618557722f450375d3796d701a8ac5407b3b94e"
integrity sha512-NyL6ZB6cVni7pl+/IT2W0ni5ME00xR0sN27AQZZrpKn1b+qRh+mLbBxIq9Cq1oGfmTc7BUq4HB77mxwCaxAYNg==
dependencies:
"@types/http-proxy" "^1.17.4"
http-proxy "^1.18.1"
is-glob "^4.0.1"
lodash "^4.17.20"
micromatch "^4.0.2"
http-proxy@^1.18.1:
version "1.18.1"
resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
dependencies:
eventemitter3 "^4.0.0"
follow-redirects "^1.0.0"
requires-port "^1.0.0"
https-browserify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
@@ -5484,11 +5434,6 @@ is-resolvable@^1.0.0:
resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88"
integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==
is-retry-allowed@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4"
integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==
is-ssh@^1.3.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.3.2.tgz#a4b82ab63d73976fd8263cceee27f99a88bdae2b"
@@ -6139,6 +6084,17 @@ mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.1:
dependencies:
minimist "^1.2.5"
morgan@^1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7"
integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==
dependencies:
basic-auth "~2.0.1"
debug "2.6.9"
depd "~2.0.0"
on-finished "~2.3.0"
on-headers "~1.0.2"
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@@ -8014,11 +7970,6 @@ require-main-filename@^2.0.0:
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
requires-port@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
reserved-words@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/reserved-words/-/reserved-words-0.1.2.tgz#00a0940f98cd501aeaaac316411d9adc52b31ab1"