remove pug

This commit is contained in:
polv committed 2020-12-16 01:12:41 +07:00
1 parent e397c9ae1e
commit 68840c9c60
49 files changed
+1421 -806

No files matched your search

+1
View File
@@ -15,5 +15,6 @@ module.exports = {
// add your custom rules here
rules: {
'require-await': 0,
'vue/no-v-html': 0,
},
}
+6
View File
@@ -0,0 +1,6 @@
interface IPostTeaser {
title: string
path: string
date?: string
excerpt: string
}
-35
View File
@@ -1,35 +0,0 @@
<template>
<svg
class="NuxtLogo"
width="245"
height="180"
viewBox="0 0 452 342"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M139 330l-1-2c-2-4-2-8-1-13H29L189 31l67 121 22-16-67-121c-1-2-9-14-22-14-6 0-15 2-22 15L5 303c-1 3-8 16-2 27 4 6 10 12 24 12h136c-14 0-21-6-24-12z"
fill="#00C58E"
/>
<path
d="M447 304L317 70c-2-2-9-15-22-15-6 0-15 3-22 15l-17 28v54l39-67 129 230h-49a23 23 0 0 1-2 14l-1 1c-6 11-21 12-23 12h76c3 0 17-1 24-12 3-5 5-14-2-26z"
fill="#108775"
/>
<path
d="M376 330v-1l1-2c1-4 2-8 1-12l-4-12-102-178-15-27h-1l-15 27-102 178-4 12a24 24 0 0 0 2 15c4 6 10 12 24 12h190c3 0 18-1 25-12zM256 152l93 163H163l93-163z"
fill="#2F495E"
/>
</svg>
</template>
<style>
.NuxtLogo {
animation: 1s appear;
margin: auto;
}
@keyframes appear {
0% {
opacity: 0;
}
}
</style>
+92
View File
@@ -0,0 +1,92 @@
<template>
<article>
<post-teaser v-for="p in posts" :key="p.path" :post="p"></post-teaser>
<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">
<span> &hellip; </span>
</li>
<li v-if="page > 3">
<nuxt-link
:to="makePageUrl(page - 1)"
:aria-label="`page ${page - 1}`"
>
{{ page - 1 }}
</nuxt-link>
</li>
<li>
<span>
{{ page }}
</span>
</li>
<li v-if="page < total - 2">
<nuxt-link
:to="makePageUrl(page + 1)"
:aria-label="`page ${page + 1}`"
>
{{ page + 1 }}
</nuxt-link>
</li>
<li v-if="page < total - 3">
<span> &hellip; </span>
</li>
<li v-if="page < total">
<nuxt-link :to="makePageUrl(total)" :aria-label="`page ${total}`">
{{ 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>
</template>
<script lang="ts">
import { Vue, Component, Prop } from 'nuxt-property-decorator'
@Component
export default class PostQuery extends Vue {
@Prop({ required: true }) posts!: IPostTeaser[]
@Prop({ required: true }) count!: number
get page() {
return parseInt((this.$route.query.page as string) || '1')
}
get total() {
return Math.ceil(this.count / 5)
}
makePageUrl(page: number) {
return this.$router.resolve({
path: this.$route.path,
query: {
...this.$route.query,
page: page.toString(),
},
})
}
}
</script>
+48
View File
@@ -0,0 +1,48 @@
<template>
<section>
<h2>
<nuxt-link :to="'post/' + post.path">
{{ post.title }}
</nuxt-link>
</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>
<article v-html="post.excerpt"></article>
</section>
</template>
<script lang="ts">
import { Vue, Component, Prop } from 'nuxt-property-decorator'
import { THEME } from '~/assets/global'
@Component
export default class PostTeaser extends Vue {
@Prop() post!: IPostTeaser
theme = THEME
}
</script>
<style scoped>
article {
margin-top: 2em;
}
</style>
-7
View File
@@ -1,7 +0,0 @@
# COMPONENTS
**This directory is not required, you can delete it if you don't want to use it.**
The components directory contains your Vue.js Components.
_Nuxt.js doesn't supercharge these components._
+15
View File
@@ -0,0 +1,15 @@
<template>
<div>
<h1 v-if="error.statusCode === 404">Page not found</h1>
<h1 v-else>An error occurred</h1>
<NuxtLink to="/">Home page</NuxtLink>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/require-prop-types
props: ['error'],
layout: 'error', // you can set a custom layout for the error page
}
</script>
+13 -1
View File
@@ -27,13 +27,24 @@ const config = async (): Promise<NuxtConfig> => {
: 'https://unpkg.com/awsm.css/dist/awsm.min.css',
},
],
script: [
{
src:
'https://unpkg.com/@webcomponents/webcomponentsjs/webcomponents-loader.js',
defer: true,
},
{
type: 'module',
src: '/webcomponents.js',
},
],
},
// Global CSS (https://go.nuxtjs.dev/config-css)
css: [],
// Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins)
plugins: [],
plugins: ['~/plugins/format.ts'],
// Auto import components (https://go.nuxtjs.dev/config-components)
components: true,
@@ -58,6 +69,7 @@ const config = async (): Promise<NuxtConfig> => {
env: {
THEME: JSON.stringify(theme),
},
serverMiddleware: [{ path: '/api', handler: '~/server/index.ts' }],
}
}
+2
View File
@@ -35,11 +35,13 @@
"@nuxtjs/eslint-module": "^2.0.0",
"@types/better-sqlite3": "^5.4.1",
"@types/cheerio": "^0.22.23",
"@types/ejs": "^3.0.5",
"@types/fs-extra": "^9.0.5",
"@types/rimraf": "^3.0.0",
"@types/showdown": "^1.9.3",
"babel-eslint": "^10.1.0",
"dotenv": "^8.2.0",
"ejs": "^3.1.5",
"eslint": "^7.10.0",
"eslint-config-prettier": "^6.12.0",
"eslint-plugin-nuxt": "^1.0.0",
+28
View File
@@ -0,0 +1,28 @@
<template>
<p v-if="$fetchState.pending"></p>
<p v-else-if="$fetchState.error">An error occurred {{ $fetchState.error }}</p>
<post-query v-else :posts="posts" :count="count" />
</template>
<script lang="ts">
import { Vue, Component } from 'nuxt-property-decorator'
@Component<TagPage>({
async fetch() {
const { result, count } = await this.$axios.$get('/q', {
params: {
q: this.$route.query.q,
page: this.$route.query.page,
tag: this.$route.params.tag,
},
})
this.posts = result
this.count = count
},
})
export default class TagPage extends Vue {
posts: IPostTeaser[] = []
count = 0
}
</script>
+30
View File
@@ -0,0 +1,30 @@
<template>
<p v-if="$fetchState.pending"></p>
<p v-else-if="$fetchState.error">
An error occurred {{ $fetchState.error.message }}
</p>
<p v-else-if="!posts.length">No posts found.</p>
<post-query v-else :posts="posts" :count="count" />
</template>
<script lang="ts">
import { Vue, Component } from 'nuxt-property-decorator'
@Component<BlogPage>({
async fetch() {
const { result, count } = await this.$axios.$get('/api/q', {
params: {
q: this.$route.query.q,
page: this.$route.query.page,
},
})
this.posts = result
this.count = count
},
})
export default class BlogPage extends Vue {
posts: IPostTeaser[] = []
count = 0
}
</script>
+5 -26
View File
@@ -1,30 +1,9 @@
<template>
<div class="container">
<div>
<div class="links">
<a
href="https://nuxtjs.org/"
target="_blank"
rel="noopener noreferrer"
class="button--green"
>
Documentation
</a>
<a
href="https://github.com/nuxt/nuxt.js"
target="_blank"
rel="noopener noreferrer"
class="button--grey"
>
GitHub
</a>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({})
export default Vue.extend({
middleware: (ctx) => {
ctx.redirect('/blog')
},
})
</script>
-7
View File
@@ -1,7 +0,0 @@
# PLUGINS
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains Javascript plugins that you want to run before mounting the root Vue.js application.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins).
+12
View File
@@ -0,0 +1,12 @@
import Vue from 'vue'
Vue.filter('formatDate', (s: string) => {
return s
? new Date(s).toLocaleDateString([], {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'short',
})
: ''
})
+1 -7
View File
@@ -14,12 +14,6 @@ export const CONTENT_PATH = path.resolve(
)
export const srcPath = (
root: '_post' | '_media' | typeof THEME_FILENAME,
root: '_posts' | '_media' | typeof THEME_FILENAME,
...ps: string[]
): string => path.join(CONTENT_PATH, root, ...ps)
export const builtPath = (...ps: string[]): string =>
path.join(__dirname, '../built', ...ps)
export const dstMediaPath = (...ps: string[]): string =>
path.join(__dirname, '../static/media', ...ps)
+39 -12
View File
@@ -2,6 +2,7 @@ import crypto from 'crypto'
import scopeCss from '@patarapolw/scope-css'
import cheerio from 'cheerio'
import ejs from 'ejs'
import jieba from 'nodejieba'
import showdown from 'showdown'
@@ -16,7 +17,7 @@ export class MakeHTML {
strikethrough: true,
tables: true,
tasklists: true,
simpleLineBreaks: true,
// simpleLineBreaks: true,
openLinksInNewWindow: true,
backslashEscapesHTMLTags: true,
emoji: true,
@@ -24,7 +25,7 @@ export class MakeHTML {
metadata: true,
})
constructor(private slug: string) {
constructor() {
/**
* ! For some reasons default underscore italic fails to render...
*/
@@ -38,18 +39,24 @@ export class MakeHTML {
)
}
parse(md: string): string {
async parse(
filename: string
): Promise<{
$: cheerio.Cheerio
html(): string
clean(): string
}> {
const id =
'md-' +
crypto
.createHash('sha256')
.update(this.slug || md)
.update(filename)
.digest()
.toString('hex')
.substr(8)
const $div = this.$(`<div id="${id}">`)
$div.html(this.mdConverter.makeHtml(md))
$div.html(await this.getHTML(filename))
$div.find('style').each((_, el) => {
const $el = this.$(el)
const html = $el.html() || ''
@@ -58,14 +65,34 @@ export class MakeHTML {
}
})
return this.$('<div>').append($div).html() || ''
return {
$: $div,
html() {
return $div.html() || ''
},
clean() {
return jieba.cutForSearch($div.text() || '').join(' ')
},
}
}
clean(md: string): string {
const $div = this.$('<div>')
$div.html(this.mdConverter.makeHtml(md))
$div.remove('style')
return jieba.cutForSearch($div.html() || '').join(' ')
private async getHTML(filename: string) {
return this.mdConverter.makeHtml(
await ejs.renderFile(filename, {
youtube: (id: string) =>
this.$('<div>')
.html(
/* html */ `
<div style="padding-top:56.25%">
<iframe src="https://www.youtube.com/embed/${id}"
frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
style="width:100%; height:100%"></iframe>
</div>`
)
.html(),
})
)
}
}
+24 -25
View File
@@ -4,8 +4,9 @@ import yaml from 'js-yaml'
import rimraf from 'rimraf'
import { Database, IMatter } from '../server/db'
import { builtPath, dstMediaPath } from '../server/dir'
import { THEME_FILENAME } from '../server/theme'
import { builtPath, dstMediaPath, srcPath } from './dir'
import { srcPath } from './dir'
import { MakeHTML } from './make-html'
async function main() {
@@ -17,40 +18,38 @@ async function main() {
await fs.copyFile(srcPath(THEME_FILENAME), builtPath(THEME_FILENAME))
const db = new Database(builtPath('data.db'))
const db = new Database()
db.init()
const files = await fg('**/*.md', {
cwd: srcPath('_post'),
cwd: srcPath('_posts'),
})
// eslint-disable-next-line array-callback-return
files.map((f) => {
const path = f.replace(/\.md$/, '')
let markdown = fs.readFileSync(srcPath('_post', f), 'utf8')
const makeHtml = new MakeHTML()
const [h, c = ''] = markdown.substr(4).split(/---\n(.*)$/s)
const header = yaml.safeLoad(h, {
schema: yaml.JSON_SCHEMA,
}) as IMatter
markdown = c
await Promise.all(
files.map(async (f) => {
const path = f.replace(/\.md$/, '')
const markdown = fs.readFileSync(srcPath('_posts', f), 'utf8')
const makeHtml = new MakeHTML(path)
const [h] = markdown.substr(4).split(/---\n(.*)$/s)
const header = yaml.safeLoad(h) as IMatter
const content = makeHtml.clean(markdown)
const excerptHtml = makeHtml.parse(
markdown.split(/<!-- excerpt(?:_separator)? -->/)[0]
)
const contentHtml = makeHtml.parse(markdown)
const r = await makeHtml.parse(srcPath('_posts', f))
const contentHtml = r.html()
const excerptHtml = contentHtml.split(
/<!-- excerpt(?:_separator)? -->/
)[0]
db.insert({
...header,
path,
content,
excerptHtml,
contentHtml,
db.insert({
...header,
path,
content: r.clean(),
excerptHtml,
contentHtml,
})
})
})
)
}
if (require.main === module) {
+151 -11
View File
@@ -1,6 +1,8 @@
import sqlite3 from 'better-sqlite3'
import * as z from 'zod'
import { builtPath } from './dir'
const zMatter = z.object({
date: z.date().optional(),
createdAt: z.date().optional(),
@@ -31,8 +33,8 @@ export type IPost = z.infer<typeof zPost>
export class Database {
db: sqlite3.Database
constructor(public filepath: string, opts?: sqlite3.Options) {
this.db = sqlite3(filepath, opts)
constructor(opts?: sqlite3.Options) {
this.db = sqlite3(builtPath('data.db'), opts)
}
public init(): void {
@@ -40,8 +42,8 @@ export class Database {
CREATE TABLE IF NOT EXISTS files (
[path] TEXT PRIMARY KEY,
[date] INT, -- epoch milli
[createdAt] INT, -- epoch milli
[updatedAt] INT, -- epoch milli
createdAt INT, -- epoch milli
updatedAt INT, -- epoch milli
priority INT,
-- q.title
[image] TEXT,
@@ -83,20 +85,158 @@ export class Database {
this.db.transaction(() => {
// eslint-disable-next-line array-callback-return
ps.map((p) => {
p = zPost.parse(p)
const {
path,
date,
createdAt,
updatedAt,
priority,
image,
excerptHtml,
contentHtml,
title,
tag,
category,
content,
} = zPost.parse(p)
fStmt.run({
...p,
date: p.date ? p.date.getTime() : undefined,
createdAt: p.createdAt ? p.createdAt.getTime() : undefined,
updatedAt: p.updatedAt ? p.updatedAt.getTime() : undefined,
path,
priority,
image,
excerptHtml,
contentHtml,
date: date ? date.getTime() : null,
createdAt: createdAt ? createdAt.getTime() : null,
updatedAt: updatedAt ? updatedAt.getTime() : null,
})
qStmt.run({
...p,
tag: p.tag ? p.tag.join(' ') : undefined,
path,
title,
category,
content,
tag: tag ? tag.join(' ') : undefined,
})
})
})()
}
public get(id: string) {
const r = this.db
.prepare(
/* sql */ `
SELECT
[date],
title,
[image],
tag,
category,
excerptHtml excerpt,
contentHtml content
FROM files f
JOIN q ON q.path = f.path
WHERE f.path = @id
`
)
.get({ id })
if (!r) {
return null
}
return {
...r,
date: r.date ? new Date(r.date) : undefined,
tag: r.tag ? r.tag.split(/ /g) : undefined,
} as {
date?: Date
title: string
image?: string
tag?: string[]
category?: string
excerpt: string
content: string
}
}
public q(
q: string,
opts: {
offset: number
limit: number
}
) {
return this._search(q, opts, 'RANK')
}
public by(
q: string,
opts: {
offset: number
limit: number
}
) {
return this._search(
q,
opts,
'priority DESC, [date] DESC, createdAt DESC, updatedAt DESC'
)
}
private _search(
q: string,
opts: {
offset: number
limit: number
},
orderedBy: string
) {
const fromSegment = /* sql */ `
FROM files f
JOIN q ON q.path = f.path
${q ? `WHERE q = @q` : ''}
`
const count =
this.db
.prepare(
/* sql */ `
SELECT COUNT(f.path) [count]
${fromSegment}
`
)
.get({ q })?.count || 0
const result = this.db
.prepare(
/* sql */ `
SELECT
f.path [path],
[date],
title,
[image],
tag,
category,
excerptHtml excerpt
${fromSegment}
ORDER BY ${orderedBy}
LIMIT ${opts.limit} OFFSET ${opts.offset}
`
)
.all({ q }) as {
path: string
date?: Date
title: string
image?: string
tag?: string[]
category?: string
excerpt: string
}[]
return {
result,
count,
}
}
}
+7
View File
@@ -0,0 +1,7 @@
import path from 'path'
export const builtPath = (...ps: string[]): string =>
path.join(__dirname, '../built', ...ps)
export const dstMediaPath = (...ps: string[]): string =>
path.join(__dirname, '../static/media', ...ps)
+58
View File
@@ -0,0 +1,58 @@
import express from 'express'
import * as z from 'zod'
import { Database } from './db'
const app = express()
const db = new Database({ readonly: true })
app.get('/', (req, res) => {
const { id } = z
.object({
id: z.string(),
})
.parse(req.query)
const r = db.get(id)
if (!r) {
res.sendStatus(404)
return
}
res.json(r)
})
app.get('/q', (req, res) => {
const { q, tag, page: _page = '1' } = z
.object({
q: z.string().optional(),
tag: z.string().optional(),
page: z
.string()
.refine((s) => /^\d+$/.test(s))
.optional(),
})
.parse(req.query)
const perPage = 5
const offset = (parseInt(_page) - 1) * perPage
if (q) {
res.json(
db.q(`${q} ${tag ? `tag:${tag}` : ''}`, {
offset,
limit: perPage,
})
)
return
}
res.json(
db.by(tag ? `tag:${tag}` : '', {
offset,
limit: perPage,
})
)
})
export default app
+11
View File
@@ -0,0 +1,11 @@
/* global WebComponents */
WebComponents.waitFor(() => {
// At this point we are guaranteed that all required polyfills have
// loaded, and can use web components API's.
// The standard pattern is to load element definitions that call
// `customElements.define` here.
// Note: returning the import's promise causes the custom elements
// polyfill to wait until all definitions are loaded and then upgrade
// the document in one batch, for better performance.
return import('https://unpkg.com/@patarapolw/make-html-x-card')
})
+5 -20
View File
@@ -3,11 +3,7 @@
"target": "ES2018",
"module": "ESNext",
"moduleResolution": "Node",
"lib": [
"ESNext",
"ESNext.AsyncIterable",
"DOM"
],
"lib": ["ESNext", "ESNext.AsyncIterable", "DOM"],
"esModuleInterop": true,
"allowJs": true,
"sourceMap": true,
@@ -16,21 +12,10 @@
"experimentalDecorators": true,
"baseUrl": ".",
"paths": {
"~/*": [
"./*"
],
"@/*": [
"./*"
]
"~/*": ["./*"],
"@/*": ["./*"]
},
"types": [
"@types/node",
"@nuxt/types"
]
"types": ["@types/node", "@nuxt/types", "@nuxtjs/axios"]
},
"exclude": [
"node_modules",
".nuxt",
"dist"
]
"exclude": ["node_modules", ".nuxt", "dist"]
}
+34
View File
@@ -1404,6 +1404,11 @@
dependencies:
"@types/node" "*"
"@types/ejs@^3.0.5":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@types/ejs/-/ejs-3.0.5.tgz#95a3a1c3d9603eba80fe67ff56da1ba275ef2eda"
integrity sha512-k4ef69sS4sIqAPW9GoBnN+URAON2LeL1H0duQvL4RgdEBna19/WattYSA1qYqvbVEDRTSWzOw56tCLhC/m/IOw==
"@types/eslint-visitor-keys@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
@@ -2273,6 +2278,11 @@ async-limiter@~1.0.0:
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
async@0.9.x:
version "0.9.2"
resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=
at-least-node@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
@@ -3749,6 +3759,13 @@ ejs@^2.6.1:
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba"
integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==
ejs@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.5.tgz#aed723844dc20acb4b170cd9ab1017e476a0d93b"
integrity sha512-dldq3ZfFtgVTJMLjOe+/3sROTzALlL9E34V4/sDtUd/KlBSS0s6U1/+WPE1B4sj9CXHJpL1M6rhNJnc9Wbal9w==
dependencies:
jake "^10.6.1"
electron-to-chromium@^1.3.621:
version "1.3.626"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.626.tgz#48acdf322be07feb2c1330ba05e4bf6327f721a3"
@@ -4417,6 +4434,13 @@ file-uri-to-path@1.0.0:
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
filelist@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.1.tgz#f10d1a3ae86c1694808e8f20906f43d4c9132dbb"
integrity sha512-8zSK6Nu0DQIC08mUC46sWGXi+q3GGpKydAG36k+JDba6VRpkevvOWUW5a/PhShij4+vHT9M+ghgG7eM+a9JDUQ==
dependencies:
minimatch "^3.0.4"
filesize@^3.6.1:
version "3.6.1"
resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317"
@@ -5528,6 +5552,16 @@ isobject@^3.0.0, isobject@^3.0.1:
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
jake@^10.6.1:
version "10.8.2"
resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b"
integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==
dependencies:
async "0.9.x"
chalk "^2.4.2"
filelist "^1.0.1"
minimatch "^3.0.4"
jest-worker@^25.4.0:
version "25.5.0"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.5.0.tgz#2611d071b79cea0f43ee57a3d118593ac1547db1"