Skip to content

Commit

Permalink
Merge pull request #111 from styxlab/fix-types
Browse files Browse the repository at this point in the history
fix types
  • Loading branch information
styxlab authored Jul 21, 2021
2 parents 557e17f + 141459d commit 8a814ab
Show file tree
Hide file tree
Showing 6 changed files with 366 additions and 338 deletions.
11 changes: 9 additions & 2 deletions components/NextImage.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import Image from 'next/image'
import { ComponentPropsWithNode } from 'rehype-react'
import { Node } from 'unist'
import { Dimensions } from '@lib/images'

interface PropertyProps {
src: string
className?: string[]
}

interface ImageNode extends Node {
imageDimensions: Dimensions
properties: PropertyProps
}

export const NextImage = (props: ComponentPropsWithNode) => {
const { node } = props
if (!node) return null
const imageDimensions = node.imageDimensions as Dimensions
const { src, className: classArray } = node.properties as PropertyProps
const imageNode = node as ImageNode
const imageDimensions = imageNode.imageDimensions
const { src, className: classArray } = imageNode.properties
const className = classArray?.join(' ')

return (
Expand Down
10 changes: 8 additions & 2 deletions components/NextLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ interface PropertyProps {
href?: string
}

interface LinkNode extends Node {
children: Node[]
properties: PropertyProps
}

export const NextLink = (props: ComponentPropsWithNode) => {
const { href } = props.node?.properties as PropertyProps
const [child] = props.node?.children as Node[]
const node = props.node as LinkNode
const { href } = node?.properties
const [child] = node?.children

return (
<>
Expand Down
75 changes: 52 additions & 23 deletions lib/ghost-normalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,33 @@ export const normalizePost = async (post: PostOrPage, cmsUrl: UrlWithStringQuery
* Rewrite absolute Ghost CMS links to relative
*/

const withRewriteGhostLinks = (cmsUrl: UrlWithStringQuery, basePath = '/') => (htmlAst: Node) => {
visit(htmlAst, { tagName: `a` }, (node: Node) => {
const href = urlParse((node.properties as HTMLAnchorElement).href)
if (href.protocol === cmsUrl.protocol && href.host === cmsUrl.host) {
;(node.properties as HTMLAnchorElement).href = basePath + href.pathname?.substring(1)
}
})

return htmlAst
interface LinkElement extends Node {
tagName: string
properties?: HTMLAnchorElement
children?: Node[]
}

const withRewriteGhostLinks =
(cmsUrl: UrlWithStringQuery, basePath = '/') =>
(htmlAst: Node) => {
visit(htmlAst, { tagName: `a` }, (node: LinkElement) => {
if (!node.properties) return
const href = urlParse(node.properties.href)
if (href.protocol === cmsUrl.protocol && href.host === cmsUrl.host) {
node.properties.href = basePath + href.pathname?.substring(1)
}
})

return htmlAst
}

/**
* Rewrite relative links to be used with next/link
*/

const rewriteRelativeLinks = (htmlAst: Node) => {
visit(htmlAst, { tagName: `a` }, (node: Node) => {
const href = (node.properties as HTMLAnchorElement).href
visit(htmlAst, { tagName: `a` }, (node: LinkElement) => {
const href = node.properties?.href
if (href && !href.startsWith(`http`)) {
const copyOfNode = cloneDeep(node)
delete copyOfNode.properties
Expand All @@ -88,11 +97,21 @@ interface NodeProperties {
style?: string | string[]
}

interface PropertiesElement extends Node {
tagName: string
properties?: NodeProperties
children?: Node[]
}

interface PropertiesParent extends Parent {
tagName?: string
}

const syntaxHighlightWithPrismJS = (htmlAst: Node) => {
if (!prism.enable) return htmlAst

const getLanguage = (node: Node) => {
const className = (node.properties as NodeProperties).className || []
const getLanguage = (node: PropertiesElement) => {
const className = node.properties?.className || []

for (const classListItem of className) {
if (classListItem.slice(0, 9) === 'language-') {
Expand All @@ -102,15 +121,15 @@ const syntaxHighlightWithPrismJS = (htmlAst: Node) => {
return null
}

visit(htmlAst, 'element', (node: Node, _index: number, parent: Parent | undefined) => {
visit(htmlAst, 'element', (node: PropertiesElement, _index: number, parent: PropertiesParent | undefined) => {
if (!parent || parent.tagName !== 'pre' || node.tagName !== 'code') {
return
}

const lang = getLanguage(node)
if (lang === null) return

let className = (node.properties as NodeProperties).className
let className = node.properties?.className

let result
try {
Expand Down Expand Up @@ -142,31 +161,41 @@ const tableOfContents = (htmlAst: Node) => {
* Always attach aspectRatio for image cards
*/

interface ImageElement extends Node {
tagName: string
properties: HTMLImageElement
imageDimensions: Promise<Dimensions | null> | Dimensions
}

interface ImageParent extends Parent {
properties?: NodeProperties
}

const rewriteInlineImages = async (htmlAst: Node) => {
let nodes: { node: Node; parent: Parent | undefined }[] = []
let nodes: { node: ImageElement; parent: ImageParent | undefined }[] = []

visit(htmlAst, { tagName: `img` }, (node: Node, _index: number, parent: Parent | undefined) => {
visit(htmlAst, { tagName: `img` }, (node: ImageElement, _index: number, parent: ImageParent | undefined) => {
if (nextImages.inline) {
node.tagName = `Image`
}

const { src } = node.properties as HTMLImageElement
const { src } = node.properties
node.imageDimensions = imageDimensions(src)
nodes.push({ node, parent })
})

const dimensions = await Promise.all(nodes.map(({ node }) => node.imageDimensions))

nodes.forEach(({ node, parent }, i) => {
node.imageDimensions = dimensions[i]
if (dimensions[i] === null) return
const { width, height } = dimensions[i] as Dimensions
node.imageDimensions = dimensions[i] as Dimensions
const { width, height } = node.imageDimensions
const aspectRatio = width / height
const flex = `flex: ${aspectRatio} 1 0`
if (parent) {
let parentStyle = (parent.properties as NodeProperties).style || []
if (parent && parent.properties) {
let parentStyle = parent.properties.style || []
if (typeof parentStyle === 'string') parentStyle = [parentStyle]
;(parent.properties as NodeProperties).style = [...parentStyle, flex]
parent.properties.style = [...parentStyle, flex]
}
})

Expand Down
29 changes: 16 additions & 13 deletions lib/toc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,36 @@ interface TOC {
items: TOC[] | []
}

interface TocElement extends Node {
tagName: string
properties?: NodeProperties
children?: TocElement[]
value: string
}

export const generateTableOfContents = (htmlAst: Node) => {
const tags = [`h1`, `h2`, `h3`, `h4`, `h5`, `h6`]

function headings(node: unknown): node is Node {
return tags.includes((node as Node).tagName as string)
function headings(node: unknown): node is TocElement {
return tags.includes((node as TocElement).tagName)
}

// recursive walk to visit all children
const walk = (children: Node[], text = ``, depth = 0) => {
const walk = (children: TocElement[], text = ``, depth = 0) => {
children.forEach((child) => {
if (child.type === `text`) {
text = text + child.value
} else if (child.children && depth < 3) {
depth = depth + 1
text = walk(child.children as Node[], text, depth)
text = walk(child.children, text, depth)
}
})
return text
}

let toc: TOC[] = []
visit(htmlAst, headings, (node: Node) => {
const text = walk(node.children as Node[])
visit(htmlAst, headings, (node: TocElement) => {
const text = walk(node.children || [])
if (text.length > 0) {
const id = (node.properties as NodeProperties).id || `error-missing-id`
const level = (node.tagName as string).substr(1, 1)
Expand All @@ -60,7 +67,7 @@ export const generateTableOfContents = (htmlAst: Node) => {
// determine parents
toc.forEach((node, index) => {
const prev = toc[index > 0 ? index - 1 : 0]
node.parentIndex = node.level > prev.level ? node.parentIndex = index - 1 : prev.parentIndex
node.parentIndex = node.level > prev.level ? (node.parentIndex = index - 1) : prev.parentIndex
node.parentIndex = node.level < prev.level ? findParent(toc, node.parentIndex, node.level) : node.parentIndex
})

Expand All @@ -70,11 +77,7 @@ export const generateTableOfContents = (htmlAst: Node) => {
// make final tree
let tocTree = toc.filter(({ parentIndex }) => parentIndex === -1)

const removeProps = ({ id, heading, items }: TOC): IToC => (
(items.length > 0)
? { id, heading, items: (items as TOC[]).map(item => removeProps(item)) }
: { id, heading }
)
const removeProps = ({ id, heading, items }: TOC): IToC => (items.length > 0 ? { id, heading, items: (items as TOC[]).map((item) => removeProps(item)) } : { id, heading })

return tocTree.map(node => removeProps(node))
return tocTree.map((node) => removeProps(node))
}
42 changes: 21 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,17 @@
"postbuild": "next-sitemap"
},
"dependencies": {
"@tryghost/content-api": "^1.5.9",
"@types/refractor": "^3.0.1",
"@tryghost/content-api": "^1.5.10",
"cheerio": "^1.0.0-rc.10",
"crypto-hash": "^1.3.0",
"dayjs": "^1.10.5",
"dayjs": "^1.10.6",
"disqus-react": "^1.1.1",
"email-validator": "^2.0.4",
"fs": "^0.0.1-security",
"hast-util-to-string": "^1.0.4",
"lodash.throttle": "^4.1.1",
"next": "^11.0.1",
"nodemailer": "^6.6.2",
"nodemailer": "^6.6.3",
"nodemailer-smtp-transport": "^2.7.4",
"probe-image-size": "^7.2.1",
"react": "17.0.2",
Expand All @@ -65,32 +64,33 @@
},
"devDependencies": {
"@next/bundle-analyzer": "^11.0.1",
"@types/cheerio": "^0.22.29",
"@types/lodash": "^4.14.170",
"@types/node": "^15.12.5",
"@types/nodemailer": "^6.4.2",
"@types/nodemailer-smtp-transport": "^2.7.4",
"@types/react": "^17.0.11",
"@types/rss": "^0.0.28",
"@types/sanitize-html": "^2.3.1",
"@types/styled-components": "^5.1.10",
"@types/cheerio": "^0.22.30",
"@types/lodash": "^4.14.171",
"@types/node": "^16.4.0",
"@types/nodemailer": "^6.4.4",
"@types/nodemailer-smtp-transport": "^2.7.5",
"@types/react": "^17.0.14",
"@types/rss": "^0.0.29",
"@types/sanitize-html": "^2.3.2",
"@types/styled-components": "^5.1.11",
"@types/testing-library__react": "^10.2.0",
"@types/tryghost__content-api": "^1.3.6",
"@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.28.1",
"autoprefixer": "^10.2.6",
"@types/tryghost__content-api": "^1.3.7",
"@types/refractor": "^3.0.2",
"@typescript-eslint/eslint-plugin": "^4.28.4",
"@typescript-eslint/parser": "^4.28.4",
"autoprefixer": "^10.3.1",
"critters": "^0.0.10",
"eslint": "^7.29.0",
"eslint": "^7.31.0",
"eslint-config-next": "^11.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.2.0",
"next-sitemap": "^1.6.124",
"postcss": "^8.3.5",
"next-sitemap": "^1.6.140",
"postcss": "^8.3.6",
"postcss-color-mod-function": "^3.0.3",
"postcss-easy-import": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"prettier": "^2.3.2",
"typescript": "^4.3.4"
"typescript": "^4.3.5"
}
}
Loading

1 comment on commit 8a814ab

@vercel
Copy link

@vercel vercel bot commented on 8a814ab Jul 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.