Skip to content

Commit

Permalink
Merge pull request #955 from seancdavis/new-blocks
Browse files Browse the repository at this point in the history
Skip toggle blocks and inline mentions
  • Loading branch information
seancdavis authored Feb 22, 2024
2 parents ee517aa + 62b7c5e commit 087a60f
Show file tree
Hide file tree
Showing 21 changed files with 155 additions and 131 deletions.
10 changes: 6 additions & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"cSpell.words": [
"octokit"
]
}
"cSpell.words": ["octokit"],
"editor.codeActionsOnSave": {
"source.organizeImports": true,
"source.addMissingImports": true
}
}
23 changes: 23 additions & 0 deletions packages/notion-post-publisher/__mocks__/ToggleBlock.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { faker } from "@faker-js/faker";

import { NotionToggleBlock } from "../src/types/notion";

import { mockUser } from "./User.mock";
import { mockRichText } from "./RichText.mock";

export function mockToggleBlock(): NotionToggleBlock {
const user = mockUser();

return {
object: "block",
id: faker.datatype.uuid(),
created_time: "2022-04-04T19:49:00.000Z",
last_edited_time: "2022-04-04T19:50:00.000Z",
created_by: user,
last_edited_by: user,
has_children: false,
archived: false,
type: "toggle",
toggle: { rich_text: [mockRichText()], color: "default" },
};
}
7 changes: 4 additions & 3 deletions packages/notion-post-publisher/__tests__/lib/Post.spec.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { format as formatDate } from "date-fns";
import fs from "fs";
import path from "path";
import { Post } from "../../src/lib/Post";
import {
mockBulletedListItemBlock,
mockNumberedListItemBlock,
mockPageBlocksApiResponse,
mockPagePropertiesResponse,
mockParagraphBlock,
} from "../../__mocks__";
import { Block, CreatableBlock } from "../../src/lib/Block";
import { Post } from "../../src/lib/Post";
import {
getAllPageBlocks,
getPageProperties,
} from "../../src/utils/notion-utils";
import { Block, CreatableBlock } from "../../src/lib/Block";

jest.mock("../../src/utils/notion-utils", () => {
return { getAllPageBlocks: jest.fn(), getPageProperties: jest.fn() };
Expand Down Expand Up @@ -44,7 +45,7 @@ describe("Post", () => {
title: "Hello World",
});
const post = await Post.create("SOME_PAGE_ID");
const dateStr = new Date().toISOString().split("T")[0];
const dateStr = formatDate(new Date(), "yyyy-MM-dd");
const slug = "hello-world";
const expFilename = `${dateStr}-${slug}.md`;
expect(post.date).toEqual(dateStr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,16 @@ describe("EmbedBlock", () => {
});
it("Supports twitter embeds", async () => {
const data = mockEmbedBlock({
url: "https://twitter.com/seancdavis29/status/1550468441533870080",
url: "https://twitter.com/seancdavis29/status/1756294848431149188",
});
const block = new EmbedBlock(data);
await block.prerender();
const result = block.render();
expect(result).toBe(
prettier.format(
`<blockquote class="twitter-tweet">
<p lang="en" dir="ltr">
Every time I get close to wrapping up a project working with a new designer,
I’m reminded of the benefit of considering extremes early on. We require so
much flexibility and variability today that it’s impossible to capture a
single, idealistic design. https://t.co/qTphiBEbNf
</p>
&mdash; Sean C Davis (@seancdavis29)
<a href="https://twitter.com/seancdavis29/status/1550468441533870080"
>July 22, 2022</a
>
</blockquote>
<script
async
src="https://platform.twitter.com/widgets.js"
charset="utf-8"
></script>`,
<a href="https://twitter.com/username/status/1756294848431149188"></a>
</blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>`,
{ parser: "html" }
)
);
Expand All @@ -47,7 +33,6 @@ describe("EmbedBlock", () => {
"https://stackblitz.com/edit/nextjs-ehvtnq?ctl=1&embed=1&file=components/Link.jsx";
const data = mockEmbedBlock({ url });
const block = new EmbedBlock(data);
await block.prerender();
const result = block.render();
expect(result).toBe(`{% code_playground url="${url}" %}`);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ToggleBlock } from "../../../src/lib/blocks/ToggleBlock";
import { mockToggleBlock } from "../../../__mocks__/ToggleBlock.mock";

describe("ToggleBlock", () => {
it("Renders nothing", () => {
const data = mockToggleBlock();
const block = new ToggleBlock(data);
const result = block.render();
expect(result).toBeNull();
});
});
1 change: 1 addition & 0 deletions packages/notion-post-publisher/dist/lib/Block.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const BlockMap = {
paragraph: blocks_1.ParagraphBlock,
quote: blocks_1.QuoteBlock,
table_of_contents: blocks_1.TableOfContentsBlock,
toggle: blocks_1.ToggleBlock,
video: blocks_1.VideoBlock,
};
class Block {
Expand Down
65 changes: 40 additions & 25 deletions packages/notion-post-publisher/dist/lib/blocks/EmbedBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EmbedBlock = void 0;
const twitter_api_sdk_1 = require("twitter-api-sdk");
const axios_1 = __importDefault(require("axios"));
const date_fns_1 = require("date-fns");
const prettier_1 = __importDefault(require("prettier"));
class EmbedBlock {
Expand Down Expand Up @@ -51,31 +51,46 @@ class TwitterEmbedBlock {
this.id = id;
}
prerender() {
var _a, _b, _c, _d, _e;
return __awaiter(this, void 0, void 0, function* () {
const client = new twitter_api_sdk_1.Client(process.env.TWITTER_BEARER_TOKEN);
const tweet = yield client.tweets.findTweetById(this.id, {
"tweet.fields": ["created_at", "text", "author_id"],
});
if (!((_a = tweet.data) === null || _a === void 0 ? void 0 : _a.author_id) ||
!((_b = tweet.data) === null || _b === void 0 ? void 0 : _b.created_at) ||
!((_c = tweet.data) === null || _c === void 0 ? void 0 : _c.text)) {
throw new Error(`Could not find appropriate attributes for tweet: ${this.id}`);
}
const author = yield client.users.findUserById(tweet.data.author_id, {
"user.fields": ["name", "username"],
});
if (!((_d = author.data) === null || _d === void 0 ? void 0 : _d.name) || !((_e = author.data) === null || _e === void 0 ? void 0 : _e.username)) {
throw new Error(`Could not find appropriate attributes for author: ${tweet.data.author_id}`);
}
this.tweet = {
created_at: new Date(tweet.data.created_at),
text: tweet.data.text,
author: {
name: author.data.name,
username: author.data.username,
},
};
// const client = new Client(process.env.TWITTER_BEARER_TOKEN!);
// console.log(process.env.TWITTER_BEARER_TOKEN);
const tweetUrl = `https://twitter.com/_/status/${this.id}`;
const response = yield axios_1.default.get(tweetUrl);
console.log(response.data, response.status);
// let tweet: any;
// try {
// tweet = await client.tweets.findTweetById(this.id, {
// "tweet.fields": ["created_at", "text", "author_id"],
// });
// } catch (error) {
// console.log(error);
// throw new Error(`Could not find tweet: ${this.id}`);
// }
// if (
// !tweet.data?.author_id ||
// !tweet.data?.created_at ||
// !tweet.data?.text
// ) {
// throw new Error(
// `Could not find appropriate attributes for tweet: ${this.id}`
// );
// }
// const author = await client.users.findUserById(tweet.data.author_id, {
// "user.fields": ["name", "username"],
// });
// if (!author.data?.name || !author.data?.username) {
// throw new Error(
// `Could not find appropriate attributes for author: ${tweet.data.author_id}`
// );
// }
// this.tweet = {
// created_at: new Date(tweet.data.created_at),
// text: tweet.data.text,
// author: {
// name: author.data.name,
// username: author.data.username,
// },
// };
});
}
render() {
Expand Down
10 changes: 10 additions & 0 deletions packages/notion-post-publisher/dist/lib/blocks/ToggleBlock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ToggleBlock = void 0;
class ToggleBlock {
constructor(_) { }
render() {
return null;
}
}
exports.ToggleBlock = ToggleBlock;
4 changes: 3 additions & 1 deletion packages/notion-post-publisher/dist/lib/blocks/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.VideoBlock = exports.TableOfContentsBlock = exports.QuoteBlock = exports.ParagraphBlock = exports.NumberedListItemBlock = exports.ImageBlock = exports.Heading3Block = exports.Heading2Block = exports.Heading1Block = exports.EmbedBlock = exports.DividerBlock = exports.CodeBlock = exports.ChildPageBlock = exports.CalloutBlock = exports.BulletedListItemBlock = void 0;
exports.VideoBlock = exports.ToggleBlock = exports.TableOfContentsBlock = exports.QuoteBlock = exports.ParagraphBlock = exports.NumberedListItemBlock = exports.ImageBlock = exports.Heading3Block = exports.Heading2Block = exports.Heading1Block = exports.EmbedBlock = exports.DividerBlock = exports.CodeBlock = exports.ChildPageBlock = exports.CalloutBlock = exports.BulletedListItemBlock = void 0;
var BulletedListItemBlock_1 = require("./BulletedListItemBlock");
Object.defineProperty(exports, "BulletedListItemBlock", { enumerable: true, get: function () { return BulletedListItemBlock_1.BulletedListItemBlock; } });
var CalloutBlock_1 = require("./CalloutBlock");
Expand Down Expand Up @@ -29,5 +29,7 @@ var QuoteBlock_1 = require("./QuoteBlock");
Object.defineProperty(exports, "QuoteBlock", { enumerable: true, get: function () { return QuoteBlock_1.QuoteBlock; } });
var TableOfContentsBlock_1 = require("./TableOfContentsBlock");
Object.defineProperty(exports, "TableOfContentsBlock", { enumerable: true, get: function () { return TableOfContentsBlock_1.TableOfContentsBlock; } });
var ToggleBlock_1 = require("./ToggleBlock");
Object.defineProperty(exports, "ToggleBlock", { enumerable: true, get: function () { return ToggleBlock_1.ToggleBlock; } });
var VideoBlock_1 = require("./VideoBlock");
Object.defineProperty(exports, "VideoBlock", { enumerable: true, get: function () { return VideoBlock_1.VideoBlock; } });
11 changes: 11 additions & 0 deletions packages/notion-post-publisher/dist/utils/render-utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderBlocks = exports.trailingNewlines = exports.renderRichText = void 0;
const chalk_1 = __importDefault(require("chalk"));
const blocks_1 = require("../lib/blocks");
/**
* Given a an array of rich text objects from Notion, return a markdown string.
Expand Down Expand Up @@ -30,6 +34,13 @@ function sanitizeText(text) {
* @returns {string} Text to render to the markdown file.
*/
function renderRichTextItem(richText) {
// A mention appears as a link, but the link is to a Notion page, which is
// likely inaccessible to the public. We log and ignore these for now.
if (richText.type === "mention") {
const msg = `Mention found: ${richText.plain_text} (${richText.href})`;
console.log(chalk_1.default.cyan.bold("[info]"), msg);
return "";
}
if (richText.type !== "text") {
throw new Error(`Rich text type not supported: ${richText.type}`);
}
Expand Down
3 changes: 3 additions & 0 deletions packages/notion-post-publisher/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ module.exports = {
preset: "ts-jest",
testEnvironment: "node",
setupFiles: ["<rootDir>/__mocks__/s3-utils.ts"],
moduleNameMapper: {
"^axios$": "axios/dist/node/axios.cjs",
},
};
3 changes: 1 addition & 2 deletions packages/notion-post-publisher/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
"fast-glob": "^3.2.12",
"js-yaml": "^4.1.0",
"prettier": "^2.8.2",
"slugify": "^1.6.5",
"twitter-api-sdk": "^1.2.1"
"slugify": "^1.6.5"
},
"scripts": {
"build": "tsc",
Expand Down
5 changes: 5 additions & 0 deletions packages/notion-post-publisher/src/lib/Block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
NotionParagraphBlock,
NotionQuoteBlock,
NotionTableOfContentsBlock,
NotionToggleBlock,
NotionVideoBlock,
} from "../types/notion";

Expand All @@ -32,6 +33,7 @@ import {
ParagraphBlock,
QuoteBlock,
TableOfContentsBlock,
ToggleBlock,
VideoBlock,
} from "./blocks";

Expand All @@ -50,6 +52,7 @@ type SupportedNotionBlocks =
| NotionParagraphBlock
| NotionQuoteBlock
| NotionTableOfContentsBlock
| NotionToggleBlock
| NotionVideoBlock;

const BlockMap = {
Expand All @@ -67,6 +70,7 @@ const BlockMap = {
paragraph: ParagraphBlock,
quote: QuoteBlock,
table_of_contents: TableOfContentsBlock,
toggle: ToggleBlock,
video: VideoBlock,
};

Expand All @@ -82,6 +86,7 @@ export type CreatableBlock =
| Heading2Block
| Heading3Block
| ImageBlock
| ToggleBlock
| NumberedListItemBlock
| ParagraphBlock
| QuoteBlock
Expand Down
58 changes: 6 additions & 52 deletions packages/notion-post-publisher/src/lib/blocks/EmbedBlock.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { Client } from "twitter-api-sdk";
import { format as formatDate } from "date-fns";
import prettier from "prettier";

import type { NotionEmbedBlock } from "../../types/notion";
Expand All @@ -15,11 +13,11 @@ export class EmbedBlock {
}
}

async prerender() {
if (this.embedBlock && "prerender" in this.embedBlock) {
await this.embedBlock.prerender();
}
}
// async prerender() {
// if (this.embedBlock && "prerender" in this.embedBlock) {
// await this.embedBlock.prerender();
// }
// }

render() {
if (!this.embedBlock) {
Expand Down Expand Up @@ -53,54 +51,10 @@ class TwitterEmbedBlock {
this.id = id;
}

async prerender() {
const client = new Client(process.env.TWITTER_BEARER_TOKEN!);
const tweet = await client.tweets.findTweetById(this.id, {
"tweet.fields": ["created_at", "text", "author_id"],
});
if (
!tweet.data?.author_id ||
!tweet.data?.created_at ||
!tweet.data?.text
) {
throw new Error(
`Could not find appropriate attributes for tweet: ${this.id}`
);
}
const author = await client.users.findUserById(tweet.data.author_id, {
"user.fields": ["name", "username"],
});
if (!author.data?.name || !author.data?.username) {
throw new Error(
`Could not find appropriate attributes for author: ${tweet.data.author_id}`
);
}
this.tweet = {
created_at: new Date(tweet.data.created_at),
text: tweet.data.text,
author: {
name: author.data.name,
username: author.data.username,
},
};
}

render() {
if (!this.tweet) {
throw new Error(`Tweet not properly prerendered: ${this.id}`);
}

const output = `
<blockquote class="twitter-tweet">
<p lang="en" dir="ltr">
${this.tweet.text}
</p>
&mdash; ${this.tweet.author.name} (@${
this.tweet.author.username
}) <a href="${this.url}">${formatDate(
this.tweet.created_at,
"MMMM d, yyyy"
)}</a>
<a href="https://twitter.com/username/status/${this.id}"></a>
</blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
`;
Expand Down
Loading

0 comments on commit 087a60f

Please sign in to comment.