diff --git a/.vscode/settings.json b/.vscode/settings.json index 42e2d695..7c21de88 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,7 @@ { - "cSpell.words": [ - "octokit" - ] -} \ No newline at end of file + "cSpell.words": ["octokit"], + "editor.codeActionsOnSave": { + "source.organizeImports": true, + "source.addMissingImports": true + } +} diff --git a/packages/notion-post-publisher/__mocks__/ToggleBlock.mock.ts b/packages/notion-post-publisher/__mocks__/ToggleBlock.mock.ts new file mode 100644 index 00000000..97b9b9fd --- /dev/null +++ b/packages/notion-post-publisher/__mocks__/ToggleBlock.mock.ts @@ -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" }, + }; +} diff --git a/packages/notion-post-publisher/__tests__/lib/Post.spec.ts b/packages/notion-post-publisher/__tests__/lib/Post.spec.ts index b2feb5e5..af7a5633 100644 --- a/packages/notion-post-publisher/__tests__/lib/Post.spec.ts +++ b/packages/notion-post-publisher/__tests__/lib/Post.spec.ts @@ -1,6 +1,6 @@ +import { format as formatDate } from "date-fns"; import fs from "fs"; import path from "path"; -import { Post } from "../../src/lib/Post"; import { mockBulletedListItemBlock, mockNumberedListItemBlock, @@ -8,11 +8,12 @@ import { 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() }; @@ -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); diff --git a/packages/notion-post-publisher/__tests__/lib/blocks/EmbedBlock.spec.ts b/packages/notion-post-publisher/__tests__/lib/blocks/EmbedBlock.spec.ts index 70c42701..5678de9c 100644 --- a/packages/notion-post-publisher/__tests__/lib/blocks/EmbedBlock.spec.ts +++ b/packages/notion-post-publisher/__tests__/lib/blocks/EmbedBlock.spec.ts @@ -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( `
-- `, + + + `, { parser: "html" } ) ); @@ -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}" %}`); }); diff --git a/packages/notion-post-publisher/__tests__/lib/blocks/ToggleBlock.spec.ts b/packages/notion-post-publisher/__tests__/lib/blocks/ToggleBlock.spec.ts new file mode 100644 index 00000000..8711f534 --- /dev/null +++ b/packages/notion-post-publisher/__tests__/lib/blocks/ToggleBlock.spec.ts @@ -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(); + }); +}); diff --git a/packages/notion-post-publisher/dist/lib/Block.js b/packages/notion-post-publisher/dist/lib/Block.js index 6261c6c2..9268e0ca 100644 --- a/packages/notion-post-publisher/dist/lib/Block.js +++ b/packages/notion-post-publisher/dist/lib/Block.js @@ -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 { diff --git a/packages/notion-post-publisher/dist/lib/blocks/EmbedBlock.js b/packages/notion-post-publisher/dist/lib/blocks/EmbedBlock.js index abbf8894..d3ad0831 100644 --- a/packages/notion-post-publisher/dist/lib/blocks/EmbedBlock.js +++ b/packages/notion-post-publisher/dist/lib/blocks/EmbedBlock.js @@ -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 { @@ -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() { diff --git a/packages/notion-post-publisher/dist/lib/blocks/ToggleBlock.js b/packages/notion-post-publisher/dist/lib/blocks/ToggleBlock.js new file mode 100644 index 00000000..c12d03a1 --- /dev/null +++ b/packages/notion-post-publisher/dist/lib/blocks/ToggleBlock.js @@ -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; diff --git a/packages/notion-post-publisher/dist/lib/blocks/index.js b/packages/notion-post-publisher/dist/lib/blocks/index.js index 941e8542..cbfba0cf 100644 --- a/packages/notion-post-publisher/dist/lib/blocks/index.js +++ b/packages/notion-post-publisher/dist/lib/blocks/index.js @@ -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"); @@ -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; } }); diff --git a/packages/notion-post-publisher/dist/utils/render-utils.js b/packages/notion-post-publisher/dist/utils/render-utils.js index c92861cb..0dda56dc 100644 --- a/packages/notion-post-publisher/dist/utils/render-utils.js +++ b/packages/notion-post-publisher/dist/utils/render-utils.js @@ -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. @@ -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}`); } diff --git a/packages/notion-post-publisher/jest.config.js b/packages/notion-post-publisher/jest.config.js index f9e616ef..1f6e666d 100644 --- a/packages/notion-post-publisher/jest.config.js +++ b/packages/notion-post-publisher/jest.config.js @@ -3,4 +3,7 @@ module.exports = { preset: "ts-jest", testEnvironment: "node", setupFiles: ["- 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 -
- — Sean C Davis (@seancdavis29) - July 22, 2022 -
-`; diff --git a/packages/notion-post-publisher/src/lib/blocks/ToggleBlock.ts b/packages/notion-post-publisher/src/lib/blocks/ToggleBlock.ts new file mode 100644 index 00000000..1a9931f7 --- /dev/null +++ b/packages/notion-post-publisher/src/lib/blocks/ToggleBlock.ts @@ -0,0 +1,9 @@ +import type { NotionToggleBlock } from "../../types/notion"; + +export class ToggleBlock { + constructor(_: NotionToggleBlock) {} + + render() { + return null; + } +} diff --git a/packages/notion-post-publisher/src/lib/blocks/index.ts b/packages/notion-post-publisher/src/lib/blocks/index.ts index 0daa1bfa..c62c5bf4 100644 --- a/packages/notion-post-publisher/src/lib/blocks/index.ts +++ b/packages/notion-post-publisher/src/lib/blocks/index.ts @@ -12,4 +12,5 @@ export { NumberedListItemBlock } from "./NumberedListItemBlock"; export { ParagraphBlock } from "./ParagraphBlock"; export { QuoteBlock } from "./QuoteBlock"; export { TableOfContentsBlock } from "./TableOfContentsBlock"; +export { ToggleBlock } from "./ToggleBlock"; export { VideoBlock } from "./VideoBlock"; diff --git a/packages/notion-post-publisher/src/types/notion.ts b/packages/notion-post-publisher/src/types/notion.ts index ed2b4e20..b3eb1fc9 100644 --- a/packages/notion-post-publisher/src/types/notion.ts +++ b/packages/notion-post-publisher/src/types/notion.ts @@ -43,6 +43,8 @@ export type NotionChildPageBlock = Extract- ${this.tweet.text} -
- — ${this.tweet.author.name} (@${ - this.tweet.author.username - }) ${formatDate( - this.tweet.created_at, - "MMMM d, yyyy" - )} +