diff --git a/package-lock.json b/package-lock.json index cadf78c..eb30e76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,10 @@ { - "name": "fennec-be", + "name": "blog-be", "version": "0.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "fennec-be", "version": "0.0.1", "license": "UNLICENSED", "dependencies": { @@ -27,6 +26,7 @@ "graphql-tools": "^7.0.2", "ioredis": "^4.25.0", "js-yaml": "^4.0.0", + "marked": "^2.1.3", "nestjs-redis": "^1.2.8", "observable-to-async-generator": "^1.0.1-rc", "pg": "^8.5.1", @@ -43,6 +43,7 @@ "@nestjs/testing": "^7.6.15", "@types/express": "^4.17.8", "@types/jest": "^26.0.22", + "@types/marked": "^2.0.3", "@types/node": "^14.14.41", "@types/supertest": "^2.0.11", "@typescript-eslint/eslint-plugin": "^4.22.0", @@ -3392,6 +3393,12 @@ "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" }, + "node_modules/@types/marked": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-2.0.3.tgz", + "integrity": "sha512-lbhSN1rht/tQ+dSWxawCzGgTfxe9DB31iLgiT1ZVT5lshpam/nyOA1m3tKHRoNPctB2ukSL22JZI5Fr+WI/zYg==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -10298,6 +10305,17 @@ "node": ">=0.10.0" } }, + "node_modules/marked": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", + "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==", + "bin": { + "marked": "bin/marked" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -18277,6 +18295,12 @@ "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" }, + "@types/marked": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-2.0.3.tgz", + "integrity": "sha512-lbhSN1rht/tQ+dSWxawCzGgTfxe9DB31iLgiT1ZVT5lshpam/nyOA1m3tKHRoNPctB2ukSL22JZI5Fr+WI/zYg==", + "dev": true + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -23610,6 +23634,11 @@ "object-visit": "^1.0.0" } }, + "marked": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", + "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", diff --git a/package.json b/package.json index a9a7b43..7a0cfdb 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "graphql-tools": "^7.0.2", "ioredis": "^4.25.0", "js-yaml": "^4.0.0", + "marked": "^2.1.3", "nestjs-redis": "^1.2.8", "observable-to-async-generator": "^1.0.1-rc", "pg": "^8.5.1", @@ -55,6 +56,7 @@ "@nestjs/testing": "^7.6.15", "@types/express": "^4.17.8", "@types/jest": "^26.0.22", + "@types/marked": "^2.0.3", "@types/node": "^14.14.41", "@types/supertest": "^2.0.11", "@typescript-eslint/eslint-plugin": "^4.22.0", diff --git a/src/articles/articles.resolver.ts b/src/articles/articles.resolver.ts index c4a296d..6d4ca66 100644 --- a/src/articles/articles.resolver.ts +++ b/src/articles/articles.resolver.ts @@ -1,8 +1,17 @@ -import { Resolver, Query, Mutation, Args, Int } from '@nestjs/graphql'; +import { + Resolver, + Query, + Mutation, + Args, + Int, + ResolveField, + Parent, +} from '@nestjs/graphql'; import { ArticlesService } from './articles.service'; import { Article } from './entities/article.entity'; import { CreateArticleInput } from './dto/create-article.input'; import { UpdateArticleInput } from './dto/update-article.input'; +import * as marked from 'marked'; @Resolver(() => Article) export class ArticlesResolver { @@ -16,8 +25,8 @@ export class ArticlesResolver { } @Query(() => [Article], { name: 'articles' }) - findAll() { - return this.articlesService.findAll(); + async findAll() { + return await this.articlesService.findAll(); } @Query(() => Article, { name: 'article' }) @@ -37,4 +46,19 @@ export class ArticlesResolver { removeArticle(@Args('id', { type: () => String }) id: string) { return this.articlesService.remove(id); } + + @ResolveField(() => String) + async html(@Parent() article: Article) { + return marked(article.content); + } + + @ResolveField(() => String, { nullable: true }) + async description(@Parent() article: Article) { + const tokens = marked.lexer(article.content); + const token = tokens.find((token) => + ['blockquote', 'paragraph'].includes(token.type), + ) as { text: string }; + + return token?.text; + } } diff --git a/src/articles/dto/article-list-item.dto.ts b/src/articles/dto/article-list-item.dto.ts new file mode 100644 index 0000000..41cf256 --- /dev/null +++ b/src/articles/dto/article-list-item.dto.ts @@ -0,0 +1,7 @@ +import { ObjectType, OmitType } from '@nestjs/graphql'; +import { Article } from '../entities/article.entity'; + +@ObjectType() +export class ArticleListItemDto extends OmitType(Article, [ + 'content', +] as const) {}