@@ -2,30 +2,37 @@ import { createRemoteFileNode } from "gatsby-source-filesystem";
22import { visit , EXIT } from "unist-util-visit" ;
33import type { Node as UnistNode , Parent as UnistParent } from "unist" ;
44import type { Image } from "mdast" ;
5- import { RemarkPluginApi , RemarkStructuredContentTransformer , StructuredContentPluginOptions as RemarkStructuredContentPluginOptions , TransformerContext } from "./types.ts" ;
6-
5+ import { RemarkPluginApi , RemarkStructuredContentTransformer , StructuredContentPluginOptions as RemarkStructuredContentPluginOptions , TransformerContext } from "./types" ;
76
87/**
98 * Extract ALL images from the markdown AST and save them to File nodes.
109 */
1110export function createImageExtractorTransformer ( ) : RemarkStructuredContentTransformer < Image > {
1211 return {
13- createSchemaCustomization : ( { actions } ) => {
12+ createSchemaCustomization : ( { reporter , actions, schema } ) => {
1413 const { createTypes } = actions ;
15- const typeDefs = `
14+
15+ reporter . info ( "Creating schema customization for createImageExtractorTransformer" ) ;
16+
17+ const typeDefs = [
18+ `
1619 type MarkdownRemark implements Node {
17- embeddedImages: [File! ] @link(by: "parent.id ", from: "id")
20+ embeddedImages: [File] @link(by: "fields.imageExtractedFromMarkdownRemarkId ", from: "id")
1821 }
19- ` ;
22+ ` ,
23+ ]
24+
2025 createTypes ( typeDefs ) ;
2126 } ,
2227 traverse : ( markdownAST , _utils , context ) => {
2328 getAllImagesFromMarkdownAST ( markdownAST ) . forEach ( ( imageNode ) => {
24- context . scheduleTransformOf ( imageNode ) ;
29+ context . collect ( imageNode ) ;
2530 } ) ;
2631 } ,
27- transform : async ( node , { saveNodeToFile } ) => {
28- await saveNodeToFile ( node , { transformer : true } ) ;
32+ transform : async ( context , { createFileNode } , { markdownNode : markdownRemarkGatsbyNode } ) => {
33+ for ( const node of context . collected ) {
34+ await createFileNode ( node , { imageExtractedFromMarkdownRemarkId : markdownRemarkGatsbyNode . id } ) ;
35+ }
2936 } ,
3037 } ;
3138}
@@ -37,13 +44,17 @@ export type CreateThumbnailImageTransformerOptions = {
3744/**
3845 * Extract a single "thumbnail" image with special rules, then remove it from the AST.
3946 */
40- export function createThumbnailImageTransformer ( { keepImageInMdAST } : CreateThumbnailImageTransformerOptions ) : RemarkStructuredContentTransformer < Image > {
47+ export function createThumbnailImageTransformer ( options ?: CreateThumbnailImageTransformerOptions ) : RemarkStructuredContentTransformer < Image > {
48+ const { keepImageInMdAST } = options || { } ;
49+
50+ const LINK_FIELD_NAME = "thumbnailImage" ;
51+
4152 return {
42- createSchemaCustomization : ( { actions } ) => {
53+ createSchemaCustomization : ( { actions, schema } ) => {
4354 const { createTypes } = actions ;
4455 const typeDefs = `
4556 type MarkdownRemark implements Node {
46- thumbnailImage : File @link(by : "parent.id ", from : "id")
57+ ${ LINK_FIELD_NAME } : File @link(from : "fields. ${ LINK_FIELD_NAME } ", by : "id")
4758 }
4859 ` ;
4960 createTypes ( typeDefs ) ;
@@ -52,16 +63,29 @@ export function createThumbnailImageTransformer({ keepImageInMdAST }: CreateThum
5263 const thumbImgNode = getThumbnailImageOnly ( markdownAST ) ;
5364
5465 if ( thumbImgNode ) {
55- context . scheduleTransformOf ( thumbImgNode ) ;
66+ context . collect ( thumbImgNode ) ;
5667 }
5768 } ,
58- transform : async ( node , { saveNodeToFile, removeNodeFromMdAST } ) => {
59- await saveNodeToFile ( node , { isThumbnail : true } ) ;
69+ transform : async ( context , { createFileNode, removeNodeFromMdAST } , gatsbyApis ) => {
70+ const { markdownNode : markdownRemarkGatsbyNode , actions } = gatsbyApis ;
71+
72+ const [ thumbMdASTNode ] = context . collected ;
73+
74+ if ( ! thumbMdASTNode ) {
75+ // No thumbnail image found
76+ return ;
77+ }
78+
79+ const { createNodeField } = actions ;
80+
81+ const thumbImgGatsbyNode = await createFileNode ( thumbMdASTNode ) ;
82+
83+ createNodeField ( { node : markdownRemarkGatsbyNode , name : LINK_FIELD_NAME , value : thumbImgGatsbyNode . id } ) ;
6084
6185 if ( keepImageInMdAST === true ) {
6286 // do nothing, keep the node in the AST
6387 } else {
64- await removeNodeFromMdAST ( node ) ;
88+ await removeNodeFromMdAST ( thumbMdASTNode ) ;
6589 }
6690 } ,
6791 } ;
@@ -79,17 +103,22 @@ export default async function remarkStructuredContentPlugin(
79103 markdownNode,
80104 getCache,
81105 actions,
106+ reporter,
82107 createNodeId,
83108 ...rest
84109 } = remarkPluginApi ;
85110
111+ reporter . info ( "Starting remark-structured-content plugin for a markdown node with id: " + markdownNode . id ) ;
112+
86113 const { createNode, createNodeField } = actions ;
87114 const { transformers } = pluginOptions ;
88115
89- async function saveNodeToFile (
116+ async function createFileNode (
90117 node : Image ,
91118 extraFields : Record < string , unknown > = { }
92119 ) {
120+ reporter . info ( `Saving remote file node for image: ${ node . url } ` ) ;
121+
93122 const fileNode = await createRemoteFileNode ( {
94123 url : node . url ,
95124 parentNodeId : markdownNode . id ,
@@ -98,8 +127,10 @@ export default async function remarkStructuredContentPlugin(
98127 createNodeId,
99128 } ) ;
100129
130+ reporter . info ( `Created file node with id: ${ fileNode ?. id } for image: ${ node . url } ` ) ;
131+
101132 for ( const [ key , value ] of Object . entries ( extraFields ) ) {
102- await createNodeField ( { node : fileNode , name : key , value } ) ;
133+ createNodeField ( { node : fileNode , name : key , value } ) ;
103134 }
104135
105136 return fileNode ;
@@ -115,20 +146,19 @@ export default async function remarkStructuredContentPlugin(
115146 for ( const transformer of transformers ) {
116147 const context : TransformerContext < any > = {
117148 collected : [ ] ,
118- scheduleTransformOf ( item ) {
149+ collect ( item ) {
119150 this . collected . push ( item ) ;
120151 } ,
152+ meta : { } ,
121153 } ;
122154
123155 transformer . traverse ( markdownAST , { visit } , context ) ;
124156
125- for ( const collectedItem of context . collected ) {
126- await transformer . transform (
127- collectedItem ,
128- { saveNodeToFile, removeNodeFromMdAST } ,
129- remarkPluginApi
130- ) ;
131- }
157+ await transformer . transform (
158+ context ,
159+ { createFileNode, removeNodeFromMdAST } ,
160+ remarkPluginApi ,
161+ ) ;
132162 }
133163
134164 return markdownAST ;
@@ -157,6 +187,8 @@ function getThumbnailImageOnly(markdownAST: UnistNode): Image | null {
157187 markdownAST ,
158188 "image" ,
159189 ( node , index , parent ) => {
190+ thumbnailImage = node as Image ;
191+ return [ EXIT ] ;
160192 if ( ! parent || typeof index !== "number" ) {
161193 return ;
162194 }
@@ -174,10 +206,15 @@ function getThumbnailImageOnly(markdownAST: UnistNode): Image | null {
174206
175207 if ( ! hasTextBefore && ! hasTextAfter ) {
176208 thumbnailImage = node as Image ;
177- return EXIT ;
209+ return [ EXIT ] ;
178210 }
179211 }
180212 ) ;
181213
182214 return thumbnailImage ;
183215}
216+
217+ export { sourceNodes } from "./source-nodes" ;
218+ export { onCreateNode } from "./on-create-node" ;
219+ export { createSchemaCustomization } from "./create-schema-customization" ;
220+ export { pluginOptionsSchema } from "./plugin-options-schema" ;
0 commit comments