remark-mdat 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +10 -0
- package/dist/index.js +4 -0
- package/dist/lib/mdast-utils/mdast-util-mdat-check.d.ts +16 -0
- package/dist/lib/mdast-utils/mdast-util-mdat-clean.d.ts +13 -0
- package/dist/lib/mdast-utils/mdast-util-mdat-expand.d.ts +11 -0
- package/dist/lib/mdast-utils/mdast-util-mdat-split.d.ts +9 -0
- package/dist/lib/mdast-utils/mdast-util-mdat.d.ts +11 -0
- package/dist/lib/mdat/deep-merge-defined.d.ts +2 -0
- package/dist/lib/mdat/log.d.ts +12 -0
- package/dist/lib/mdat/mdat-log.d.ts +20 -0
- package/dist/lib/mdat/parse.d.ts +62 -0
- package/dist/lib/mdat/rules.d.ts +105 -0
- package/dist/lib/remark-mdat.d.ts +29 -0
- package/license.txt +21 -0
- package/package.json +75 -0
- package/readme.md +221 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { type Options as MdatOptions, mdat } from './lib/mdast-utils/mdast-util-mdat';
|
|
2
|
+
export { type Options as MdatCheckOptions, mdatCheck, } from './lib/mdast-utils/mdast-util-mdat-check';
|
|
3
|
+
export { type Options as MdatCleanOptions, mdatClean, } from './lib/mdast-utils/mdast-util-mdat-clean';
|
|
4
|
+
export { type Options as MdatExpandOptions, mdatExpand, } from './lib/mdast-utils/mdast-util-mdat-expand';
|
|
5
|
+
export { mdatSplit } from './lib/mdast-utils/mdast-util-mdat-split';
|
|
6
|
+
export { deepMergeDefined } from './lib/mdat/deep-merge-defined';
|
|
7
|
+
export { default as log } from './lib/mdat/log';
|
|
8
|
+
export { type MdatFileReport, type MdatMessage, getMdatReports, reporterMdat, } from './lib/mdat/mdat-log';
|
|
9
|
+
export { type NormalizedRule, type NormalizedRules, type Rule, type Rules, type SimplifyDeep, getSoleRule, getSoleRuleKey, rulesSchema, } from './lib/mdat/rules';
|
|
10
|
+
export { type Options, default, optionsSchema } from './lib/remark-mdat';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import h from"chalk";var J,L=((J=process==null?void 0:process.versions)==null?void 0:J.node)!==void 0,ae={verbose:!1,log(...e){if(!this.verbose)return;let r=h.gray("[Log]");L?console.warn(r,...e):console.log(r,...e)},logPrefixed(e,...r){this.info(h.blue(`[${e}]`),...r)},info(...e){if(!this.verbose)return;let r=h.green("[Info]");L?console.warn(r,...e):console.info(r,...e)},infoPrefixed(e,...r){this.info(h.blue(`[${e}]`),...r)},warn(...e){console.warn(h.yellow("[Warning]"),...e)},warnPrefixed(e,...r){this.warn(h.blue(`[${e}]`),...r)},error(...e){console.error(h.red("[Error]"),...e)},errorPrefixed(e,...r){this.error(h.blue(`[${e}]`),...r)}},y=ae;import w from"chalk";import D from"node:path";function u(e,r,n,t,o,i){var p,c;let a,s;o===void 0||typeof o=="number"?(a=o??0,s=i??0):(a=((p=o==null?void 0:o.position)==null?void 0:p.start.line)??0,s=((c=o==null?void 0:o.position)==null?void 0:c.start.column)??0);let l={place:{end:{column:s,line:a},start:{column:s,line:a}},source:n},d=e.message(t,l);d.fatal=r==="error"?!0:r==="warn"?!1:void 0}function le(e){return{column:e.column,level:e.fatal?"error":e.fatal===!1?"warn":"info",line:e.line,message:e.reason,source:e.source}}function me(e){return e.map(r=>U(r))}function U(e){var n;let r={destinationPath:e.history.length>0?e.history.at(-1):void 0,errors:[],infos:[],sourcePath:e.history.at(0)??e.path,warnings:[]};(n=r.sourcePath)!=null&&n.startsWith(".")&&(r.sourcePath=D.relative(process.cwd(),D.join(process.cwd(),r.sourcePath)));for(let t of e.messages){let o=le(t);o.level==="error"?r.errors.push(o):o.level==="warn"?r.warnings.push(o):r.infos.push(o)}return r}function de(e){for(let r of e){let n=U(r),{destinationPath:t,errors:o,infos:i,sourcePath:a,warnings:s}=n;y.info(`${w.bold("Comment Expansion Report:")}`),y.info(` From: ${w.blue.bold(a)}`),y.info(` To: ${w.blue.bold(t)}`);for(let l of o)y.error(V(a,l));for(let l of s)y.warn(V(a,l));for(let l of i)y.info(V(a,l));o.length===0&&s.length===0?y.info(`No issues found in ${a}`):y.error(`${o.length} errors, ${s.length} warnings found in ${a}`)}}function V(e,r){let{column:n,level:t,line:o,message:i,source:a}=r,s=a?w.gray(`[${a}] `):"",l=o&&n?`:${o}:${n}`:"",d=pe(i,t);return`${s}${d} ${w.whiteBright(e+l)}`}function pe(e,r){return e.replaceAll(/<!--.+-->/g,n=>r==="info"?w.green(n):r==="warn"?w.yellow(n):w.red(n))}import ue from"json5";import{VFileMessage as P}from"vfile-message";function R(e,r,n){var t;try{let o=ce(e.value,n);return o===void 0?void 0:{...o,node:e,parent:r}}catch(o){throw o instanceof P?(o.line=(t=e.position)==null?void 0:t.start.line,o):o instanceof Error?new P(o.message,e):new P("Unknown error",e)}}function ce(e,r){if(!fe(e))return;let{closingPrefix:n,keywordPrefix:t,metaCommentIdentifier:o}=r,i=e.trim(),a=i.replace(/^\s*<!--+\s*/,"").replace(/\s*-*-->\s*$/,""),[s,...l]=a.split(/(\s+|\(|{)/),d=s.startsWith(o)?"meta":t!==""&&!s.startsWith(t)&&!s.startsWith(`${n}${t}`)?"native":s.startsWith(n)?"close":"open";if(d==="meta")return{content:ye(a,o),html:i,type:d};if(d==="native")return{content:a,html:i,type:d};let p=s.replace(new RegExp(`^${n}`),"").replace(new RegExp(`^${t}`),""),c=ge(l.join(""));if(d==="open"||d==="close"){let f={};try{f=ue.parse(c)}catch(g){if(g instanceof Error)throw new P(`Failed to parse comment options "${c}" for keyword "${p}": ${g.message}`)}return{closingPrefix:n,html:i,keyword:p,keywordPrefix:t,options:f,type:d}}}function fe(e){let r=e.trim();return r.startsWith("<!--")&&r.endsWith("-->")}function ge(e){return e=e.trim(),e=e.startsWith("(")?e.slice(1):e,e=e.endsWith(")")?e.slice(0,-1):e,e=e.trim(),!e.startsWith("{")&&!e.startsWith("[")&&(e="{"+e),!e.endsWith("}")&&!e.endsWith("]")&&(e+="}"),e}function ye(e,r){return e=e.trim(),e=e.startsWith(r)?e.slice(r.length):e,e=e.endsWith(r)?e.slice(0,-r.length):e,e}import{z as m}from"zod";function M(e){let r={};for(let[n,t]of Object.entries(e))if(typeof t=="string")r[n]={applicationOrder:0,content:async()=>t,order:void 0,required:!1};else if(typeof t=="function")r[n]={applicationOrder:0,content:async(o,i)=>t(o,i),order:void 0,required:!1};else if(Array.isArray(t))r[n]={applicationOrder:0,content:Object.values(M(Object.fromEntries(t.entries()))),order:void 0,required:!1};else if(typeof t.content=="string"){let o=t.content;r[n]={applicationOrder:t.applicationOrder??0,content:async()=>o,order:t.order??void 0,required:t.required??!1}}else if(Array.isArray(t.content))r[n]={applicationOrder:t.applicationOrder??0,content:Object.values(M(Object.fromEntries(t.content.entries()))),order:t.order??void 0,required:t.required??!1};else{let o=t.content;r[n]={applicationOrder:t.applicationOrder??0,content:async(i,a)=>o(i,a),order:t.order??void 0,required:t.required??!1}}return he(r),r}function b(e){try{v.parse(e)}catch(r){if(r instanceof Error)throw new TypeError(`Error validating rules: ${r.message}`)}}function he(e){try{we.parse(e)}catch(r){if(r instanceof Error)throw new TypeError(`Error validating rules: ${r.message}`)}}var B=m.any(),G=m.any(),Z=m.lazy(()=>m.object({applicationOrder:m.number(),content:m.union([m.function().args(B.optional(),G.optional()).returns(m.promise(m.string())),m.array(Z)]),order:m.number().optional(),required:m.boolean().default(!1)})),K=m.function().args(B.optional(),G.optional()).returns(m.union([m.string(),m.promise(m.string())])),S=m.lazy(()=>m.union([K,m.array(S),m.string(),m.object({applicationOrder:m.number().optional(),content:m.union([K,m.array(S),m.string()]),order:m.number().optional(),required:m.boolean().optional()})])),v=m.record(S).describe("Mdat Rules"),we=m.record(Z).describe("Mdat Rules");async function C(e,r,n,t=!1){if(Array.isArray(e.content)){let o=[];for(let[i,a]of e.content.entries()){let s=Array.isArray(r)?r.at(i):void 0;try{o.push(await C(a,s??{},n))}catch(l){if(t)throw l}}return o.join(`
|
|
2
|
+
|
|
3
|
+
`)}try{return await e.content(r,n)}catch(o){if(t)throw o}throw new Error("Failed to expand content")}function ke(e){return Me(e)}function Re(e){let r=Object.keys(e);if(r.length!==1)throw new Error(`Expected exactly one rule, found ${r.length}`);return r[0]}function Me(e){let r=Object.values(e);if(r.length===0)throw new Error('Found no entries in a "sole record" record. This should never happen');if(r.length>1)throw new Error('Found multiple entries in "sole record" record. This should never happen');return r[0]}import Q from"chalk";import Ce from"cli-table3";import{CONTINUE as xe,visit as Oe}from"unist-util-visit";async function F(e,r,n){let{closingPrefix:t,keywordPrefix:o,metaCommentIdentifier:i,paranoid:a=!1,rules:s}=n;b(s);let l=M(s),d=[];Oe(e,"html",(p,c,f)=>{if(f===void 0||c===void 0)return xe;let g=R(p,f,{closingPrefix:t,keywordPrefix:o,metaCommentIdentifier:i});if(g!==void 0){let $=g.type==="open"||g.type==="close"?l[g.keyword]:void 0;d.push({...g,rule:$})}}),Te(r,d,l),Ve(r,d),Se(r,d,n),await Pe(r,d,e),a&&$e(r,d,l),ve(r,d),be(r,d,l,n)}async function Pe(e,r,n){for(let t of r)if(t.type==="open"&&t.rule!==void 0)try{(await C(t.rule,t.options,n,!0)).trim()===""&&u(e,t.rule.required?"error":"warn","check",`${t.html} returned an empty string.`,t.node)}catch(o){o instanceof Error&&u(e,t.rule.required?"error":"warn","check",`Could not get content for ${t.html}. ${o.message}`,t.node)}}function be(e,r,n,t){if(t.keywordPrefix==="")return;let o=Object.keys(n);for(let i of r)i.type==="native"&&o.includes(i.content)&&u(e,"warn","check",`Missing prefix: ${i.html}`,i.node)}function ve(e,r){for(let n of r)n.type==="open"&&n.rule===void 0&&u(e,"warn","check",`Missing rule for: ${n.html}`,n.node)}function $e(e,r,n){for(let[t,o]of Object.entries(n))!o.required&&!r.some(i=>i.type==="open"&&i.keyword===t)&&!Y(o,r)&&u(e,"warn","check",`Missing optional: <!-- ${t} -->`)}function Te(e,r,n){for(let[t,o]of Object.entries(n))o.required&&!r.some(i=>i.type==="open"&&i.keyword===t)&&!Y(o,r)&&u(e,"error","check",`Missing required: <!-- ${t} -->`)}function Y(e,r){return r.reduce((n,t)=>{var o;if(Array.isArray((o=t.rule)==null?void 0:o.content))for(let i of t.rule.content)i.content.toString()===e.content.toString()&&(n=!0);return n},!1)}function Ve(e,r){let n=r.filter(s=>{var l;return s.type==="open"&&((l=s.rule)==null?void 0:l.order)!==void 0}),t=[...n].sort((s,l)=>{var c,f;let d=(c=s.rule)==null?void 0:c.order,p=(f=l.rule)==null?void 0:f.order;if(d===void 0||p===void 0)throw new Error("Unexpected undefined rule order");return d-p}),o=X(n),i=X(t),a=new Ce({head:[Q.bold.red("Current Order"),Q.bold.green("Required Order")],style:{compact:!0}});o.join(",")!==i.join(",")&&(a.push(...o.map((s,l)=>[s,i[l]])),u(e,"error","check",`Out of order:
|
|
4
|
+
${a.toString()}`))}function Se(e,r,n){let{addMetaComment:t}=n,o=r.filter(i=>i.type==="meta").length;t&&o!==1&&u(e,"error","check","Missing meta comment"),!t&&o!==0&&u(e,"error","check","Unexpected meta comment"),o>1&&u(e,"error","check","Multiple meta comments")}function X(e){return e.map((r,n)=>{if(r.type==="open"||r.type==="close")return`${n+1}. ${r.html}`;throw new Error("Unexpected comment type")})}import{CONTINUE as k,visit as Fe}from"unist-util-visit";function E(e,r,n){let t;Fe(e,"html",(o,i,a)=>{if(a===void 0||i===void 0)return k;let s=R(o,a,n);if(s===void 0||s.type==="native")return k;if(s.type==="meta")return a.children.splice(i,1),[k,i];if(s.type==="open")return t=s,k;if(s.type==="close"){if(t===void 0)return u(r,"error","clean","Found closing marker without opening marker",o),k;if(t.parent!==s.parent)return u(r,"error","clean","Opening marker doesn't share a parent",o),k;if(t.keyword!==s.keyword)return u(r,"error","clean","Opening marker doesn't share a keyword",o),k;let l=a.children.indexOf(t.node),p=a.children.indexOf(s.node)-l+1;return a.children.splice(l+1,p-1),t=void 0,[k,i-p+1]}})}import{remark as Ee}from"remark";import ze from"remark-gfm";import{CONTINUE as Ne,visit as We}from"unist-util-visit";async function z(e,r,n){let{addMetaComment:t,closingPrefix:o,keywordPrefix:i,metaCommentIdentifier:a,rules:s}=n;b(s);let l=M(s),d=[];We(e,"html",(p,c,f)=>{if(f===void 0||c===void 0)return Ne;let g=R(p,f,{closingPrefix:o,keywordPrefix:i,metaCommentIdentifier:a});g!==void 0&&g.type==="open"&&l[g.keyword]!==void 0&&d.push(g)}),d.sort((p,c)=>l[p.keyword].applicationOrder-l[c.keyword].applicationOrder);for(let p of d){let{closingPrefix:c,html:f,keyword:g,keywordPrefix:$,node:O,options:te,parent:A}=p,oe=l[g],T="";try{T=await C(oe,te,e),T.trim()===""&&u(r,"error","expand",`Got empty content when expanding ${f}`,O)}catch(H){H instanceof Error&&u(r,"error","expand",`Caught error expanding ${f}, Error message: "${H.message}"`,O);continue}let ne=Ee().use(ze).parse(T).children,ie={type:"html",value:`<!-- ${c}${$}${g} -->`},se=A.children.indexOf(O);A.children.splice(se+1,0,...ne,ie),u(r,"info","expand",`Expanded: ${f}`,O)}if(t){let p="Warning: Content in HTML comment blocks generated by mdat",c=new Date().toISOString().slice(0,10),f={type:"html",value:`<!--${a} ${p} on ${c} ${a}-->`};e.children.unshift(f)}}import{fromHtml as Ie}from"hast-util-from-html";import{CONTINUE as N,SKIP as je,visit as re}from"unist-util-visit";function W(e,r){re(e,"html",(n,t,o)=>{if(o===void 0||t===void 0)return N;let i=qe(n);i.length>1&&(u(r,"warn","split","Multiple comments in a single HTML node.",n),o.children.splice(t,1,{children:i,type:"paragraph"}))})}function qe(e){let r=Ie(e.value,{fragment:!0}),n=[];return re(r,t=>{var o,i;return t.type==="root"?N:t.type==="text"?(n.push({position:_(t.position,(o=e.position)==null?void 0:o.start),type:"text",value:ee(e,t)}),N):(n.push({position:_(t.position,(i=e.position)==null?void 0:i.start),type:"html",value:ee(e,t)}),je)}),n}function _(e,r){if(!(e===void 0||r===void 0))return{end:{column:e.end.column-1+r.column,line:e.end.line-1+r.line,offset:e.end.offset!==void 0&&r.offset!==void 0?e.end.offset+r.offset:void 0},start:{column:e.start.column-1+r.column,line:e.start.line-1+r.line,offset:e.start.offset!==void 0&&r.offset!==void 0?e.start.offset+r.offset:void 0}}}function ee(e,r){if(r.position===void 0)throw new Error("Hast ElementContent node has no position!");return e.value.slice(r.position.start.offset,r.position.end.offset)}async function I(e,r,n){let{addMetaComment:t,closingPrefix:o,keywordPrefix:i,metaCommentIdentifier:a,rules:s}=n;W(e,r),E(e,r,{closingPrefix:o,keywordPrefix:i,metaCommentIdentifier:a}),await z(e,r,{addMetaComment:t,closingPrefix:o,keywordPrefix:i,metaCommentIdentifier:a,rules:s}),await F(e,r,{addMetaComment:t,closingPrefix:o,keywordPrefix:i,metaCommentIdentifier:a,paranoid:!1,rules:s})}import{deepmerge as Ae}from"deepmerge-ts";function j(e){return Array.isArray(e)?e.map(r=>r&&typeof r=="object"?j(r):r).filter(r=>r!==void 0):Object.entries(e).map(([r,n])=>[r,n&&typeof n=="object"?j(n):n]).reduce((r,[n,t])=>t===void 0?r:{...r,[n]:t},{})}function q(...e){let r=e.map((n,t)=>t===0?n:j(n));return Ae(...r)}import{z as x}from"zod";var He={addMetaComment:!1,closingPrefix:"/",keywordPrefix:"",metaCommentIdentifier:"+",rules:{mdat:"Powered by the Markdown Autophagic Template system: [mdat](https://github.com/kitschpatrol/mdat)."}},Le=x.object({addMetaComment:x.boolean().optional(),closingPrefix:x.string().optional(),keywordPrefix:x.string().optional(),metaCommentIdentifier:x.string().optional(),rules:v.optional()}).describe("Mdat Options"),Je=function(e){let r=q(He,e);return async function(n,t){await I(n,t,r)}},De=Je;export{q as deepMergeDefined,De as default,me as getMdatReports,ke as getSoleRule,Re as getSoleRuleKey,y as log,I as mdat,F as mdatCheck,E as mdatClean,z as mdatExpand,W as mdatSplit,Le as optionsSchema,de as reporterMdat,v as rulesSchema};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Rules } from '../mdat/rules';
|
|
2
|
+
import type { Root } from 'mdast';
|
|
3
|
+
import type { VFile } from 'vfile';
|
|
4
|
+
export type Options = {
|
|
5
|
+
addMetaComment: boolean;
|
|
6
|
+
closingPrefix: string;
|
|
7
|
+
keywordPrefix: string;
|
|
8
|
+
metaCommentIdentifier: string;
|
|
9
|
+
/** Enable extra checks, too noisy for real life. */
|
|
10
|
+
paranoid: boolean;
|
|
11
|
+
rules: Rules;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Mdast utility function to check mdat source document, and output.
|
|
15
|
+
*/
|
|
16
|
+
export declare function mdatCheck(tree: Root, file: VFile, options: Options): Promise<void>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Root } from 'mdast';
|
|
2
|
+
import { type VFile } from 'vfile';
|
|
3
|
+
export type Options = {
|
|
4
|
+
closingPrefix: string;
|
|
5
|
+
keywordPrefix: string;
|
|
6
|
+
metaCommentIdentifier: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Collapses any expanded mdat comments and removes meta comments,
|
|
10
|
+
* effectively resetting the document to its pre-expansion state. No-op if no
|
|
11
|
+
* mdat comments are found.
|
|
12
|
+
*/
|
|
13
|
+
export declare function mdatClean(tree: Root, file: VFile, options: Options): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Rules } from '../mdat/rules';
|
|
2
|
+
import type { Root } from 'mdast';
|
|
3
|
+
import { type VFile } from 'vfile';
|
|
4
|
+
export type Options = {
|
|
5
|
+
addMetaComment: boolean;
|
|
6
|
+
closingPrefix: string;
|
|
7
|
+
keywordPrefix: string;
|
|
8
|
+
metaCommentIdentifier: string;
|
|
9
|
+
rules: Rules;
|
|
10
|
+
};
|
|
11
|
+
export declare function mdatExpand(tree: Root, file: VFile, options: Options): Promise<void>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Html, type Text } from 'mdast';
|
|
2
|
+
import type { Root } from 'mdast';
|
|
3
|
+
import { type VFile } from 'vfile';
|
|
4
|
+
/**
|
|
5
|
+
* Mdast utility plugin to split any multi-comment nodes and their content into individual MDAST HTML
|
|
6
|
+
* nodes. They're wrapped in a paragraph so as not to introduce new breaks.
|
|
7
|
+
*/
|
|
8
|
+
export declare function mdatSplit(tree: Root, file: VFile): void;
|
|
9
|
+
export declare function splitHtmlIntoMdastNodes(mdastNode: Html): Array<Html | Text>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Rules } from '../mdat/rules';
|
|
2
|
+
import type { Root } from 'mdast';
|
|
3
|
+
import { type VFile } from 'vfile';
|
|
4
|
+
export type Options = {
|
|
5
|
+
addMetaComment: boolean;
|
|
6
|
+
closingPrefix: string;
|
|
7
|
+
keywordPrefix: string;
|
|
8
|
+
metaCommentIdentifier: string;
|
|
9
|
+
rules: Rules;
|
|
10
|
+
};
|
|
11
|
+
export declare function mdat(tree: Root, file: VFile, options: Options): Promise<void>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare const log: {
|
|
2
|
+
verbose: boolean;
|
|
3
|
+
log(...data: unknown[]): void;
|
|
4
|
+
logPrefixed(prefix: string, ...data: unknown[]): void;
|
|
5
|
+
info(...data: unknown[]): void;
|
|
6
|
+
infoPrefixed(prefix: string, ...data: unknown[]): void;
|
|
7
|
+
warn(...data: unknown[]): void;
|
|
8
|
+
warnPrefixed(prefix: string, ...data: unknown[]): void;
|
|
9
|
+
error(...data: unknown[]): void;
|
|
10
|
+
errorPrefixed(prefix: string, ...data: unknown[]): void;
|
|
11
|
+
};
|
|
12
|
+
export default log;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Node } from 'unist';
|
|
2
|
+
import { type VFile } from 'vfile';
|
|
3
|
+
export type MdatMessage = {
|
|
4
|
+
column?: number;
|
|
5
|
+
level: 'error' | 'info' | 'warn';
|
|
6
|
+
line?: number;
|
|
7
|
+
message: string;
|
|
8
|
+
source?: string;
|
|
9
|
+
};
|
|
10
|
+
export type MdatFileReport = {
|
|
11
|
+
destinationPath?: string;
|
|
12
|
+
errors: MdatMessage[];
|
|
13
|
+
infos: MdatMessage[];
|
|
14
|
+
sourcePath: string;
|
|
15
|
+
warnings: MdatMessage[];
|
|
16
|
+
};
|
|
17
|
+
export declare function saveLog(file: VFile, level: 'error' | 'info' | 'warn', source: string, message: string, line?: number, column?: number): void;
|
|
18
|
+
export declare function saveLog(file: VFile, level: 'error' | 'info' | 'warn', source: string, message: string, node?: Node): void;
|
|
19
|
+
export declare function getMdatReports(files: VFile[]): MdatFileReport[];
|
|
20
|
+
export declare function reporterMdat(files: VFile[]): void;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type Html, type Parent } from 'mdast';
|
|
2
|
+
import type { JsonValue } from 'type-fest';
|
|
3
|
+
import { type Simplify } from 'type-fest';
|
|
4
|
+
/**
|
|
5
|
+
* Structured data about a parsed comment.
|
|
6
|
+
* Note that this is a discriminated union based on the `type` field.
|
|
7
|
+
*/
|
|
8
|
+
export type CommentMarker = Simplify<({
|
|
9
|
+
/** Character used to delimit closing tags, e.g. the `/` in `<!-- /keyword -->` */
|
|
10
|
+
closingPrefix: string;
|
|
11
|
+
/** The first complete word in the comment */
|
|
12
|
+
keyword: string;
|
|
13
|
+
/** The unique keyword prefix */
|
|
14
|
+
keywordPrefix: string;
|
|
15
|
+
/** Parsed JSON object of argument string that followed the keyword, empty object if nothing passed */
|
|
16
|
+
options: JsonValue;
|
|
17
|
+
/**
|
|
18
|
+
* `open`: A mdat-style opening comment tag, e.g. `<!-- keyword -->` \
|
|
19
|
+
* `close`: A mdat-style closing comment tag, e.g. `<!-- /keyword -->`
|
|
20
|
+
*/
|
|
21
|
+
type: 'close' | 'open';
|
|
22
|
+
} | {
|
|
23
|
+
/** The original text inside the comment, e.g. `<!-- content -->` */
|
|
24
|
+
content: string;
|
|
25
|
+
/**
|
|
26
|
+
* `meta`: A mdat-style generated meta comment tag \
|
|
27
|
+
* `native`: A normal comment that does not match the the `keywordPrefix` (if specified)
|
|
28
|
+
*/
|
|
29
|
+
type: 'meta' | 'native';
|
|
30
|
+
}) & {
|
|
31
|
+
/** The complete original comment, e.g. `<!-- keyword -->` */
|
|
32
|
+
html: string;
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* Parsed comment with additional information about the Mdast Node and its Parent.
|
|
36
|
+
*/
|
|
37
|
+
export type CommentMarkerNode = Simplify<CommentMarker & {
|
|
38
|
+
/** Original Mdast HTML Node where the comment was found. */
|
|
39
|
+
node: Html;
|
|
40
|
+
/** Parent of original Mdast HTML Node where the comment was found. */
|
|
41
|
+
parent: Parent;
|
|
42
|
+
}>;
|
|
43
|
+
export type CommentMarkerParseOptions = {
|
|
44
|
+
/** Character to identify closing tags, e.g. the `/` in `<!-- /keyword -->` */
|
|
45
|
+
closingPrefix: string;
|
|
46
|
+
/** Prefix to require on all mdat comments, e.g. `mm-` */
|
|
47
|
+
keywordPrefix: string;
|
|
48
|
+
/** Means of identifying mdat generated meta comments, e.g. `+` */
|
|
49
|
+
metaCommentIdentifier: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Parse an Mdast HTML comment node into structured data.
|
|
53
|
+
* @returns A discriminated union of CommentMarkerNode based on comment type, or
|
|
54
|
+
* undefined if the node is not a comment.
|
|
55
|
+
*/
|
|
56
|
+
export declare function parseCommentNode(node: Html, parent: Parent, options: CommentMarkerParseOptions): CommentMarkerNode | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Parse any comment string into structured data.
|
|
59
|
+
* @returns A discriminated union of CommentMarker based on comment type, or
|
|
60
|
+
* undefined if the node is not a comment.
|
|
61
|
+
*/
|
|
62
|
+
export declare function parseComment(text: string, options: CommentMarkerParseOptions): CommentMarker | undefined;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { type Root } from 'mdast';
|
|
2
|
+
import { type JsonValue } from 'type-fest';
|
|
3
|
+
import type { Merge, MergeDeep, SetOptional, Simplify } from 'type-fest';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
export type SimplifyDeep<T> = Simplify<MergeDeep<T, T>>;
|
|
6
|
+
/**
|
|
7
|
+
* Strict normalized rules used internally.
|
|
8
|
+
* Rules normalized to a form with async content functions and other default metadata
|
|
9
|
+
* Simplifies processing elsewhere, while retaining flexibility for rule authors
|
|
10
|
+
*/
|
|
11
|
+
export type NormalizedRule = {
|
|
12
|
+
/**
|
|
13
|
+
* The order in which the rule should be applied during processing
|
|
14
|
+
* Helpful if a rule depends on the presence of content generated by another rule
|
|
15
|
+
* Defaults to 0.
|
|
16
|
+
*/
|
|
17
|
+
applicationOrder: number;
|
|
18
|
+
/**
|
|
19
|
+
* The function that generates the expansion markdown string.
|
|
20
|
+
* For 'compound' rules, this can be an array of rules (without keywords).
|
|
21
|
+
*/
|
|
22
|
+
content: ((options: JsonValue, tree: Root) => Promise<string>) | NormalizedRule[];
|
|
23
|
+
/**
|
|
24
|
+
* The expected order of the keyword in the document relative to other expander comments.
|
|
25
|
+
* Used for validation purposes.
|
|
26
|
+
* Leave undefined to order skip validation.
|
|
27
|
+
* Defaults to undefined, which means order is not enforced.
|
|
28
|
+
*/
|
|
29
|
+
order: number | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Whether the presence of the keyword comment in the document is required.
|
|
32
|
+
* Used for validation purposes.
|
|
33
|
+
* Defaults to false.
|
|
34
|
+
*/
|
|
35
|
+
required: boolean;
|
|
36
|
+
};
|
|
37
|
+
export type Rule =
|
|
38
|
+
/**
|
|
39
|
+
* Function that returns the markdown string to expand at the comment site.
|
|
40
|
+
*/
|
|
41
|
+
((options: JsonValue, tree: Root) => Promise<string> | string)
|
|
42
|
+
/**
|
|
43
|
+
* Compound rules may be defined an array of rules, without keywords.
|
|
44
|
+
* Can be defined at the top level, if no validation metadata is required, or as the 'content' value
|
|
45
|
+
* of a rule object with validation metadata.
|
|
46
|
+
*/
|
|
47
|
+
| Rule[]
|
|
48
|
+
/**
|
|
49
|
+
* The markdown string to expand at the comment site.
|
|
50
|
+
*/
|
|
51
|
+
| SetOptional<Merge<NormalizedRule, {
|
|
52
|
+
/**
|
|
53
|
+
* Gets content to expand into the comment.
|
|
54
|
+
* Can be a simple string for direct replacement, a function that returns a string, or an async function that returns a string.
|
|
55
|
+
*
|
|
56
|
+
* If a function is provided, it will be passed the following arguments:
|
|
57
|
+
*
|
|
58
|
+
* @param options
|
|
59
|
+
* JSON value of options parsed immediately after the comment keyword in the comment, e.g.:
|
|
60
|
+
* `<!-- keyword({something: true}) -->` or
|
|
61
|
+
* `<!-- keyword {something: true}-->`
|
|
62
|
+
* Sets options to {something: true}
|
|
63
|
+
*
|
|
64
|
+
* @param tree
|
|
65
|
+
* Markdown (mdast) abstract syntax tree containing the entire parsed document. Useful for expanders that need the entire document context, such as when generating a table of contents. Do not mutate the AST, instead return a new string.
|
|
66
|
+
*
|
|
67
|
+
* @returns A string with the generated content. The string will be parsed as markdown and inserted into the document at the comment's location.
|
|
68
|
+
*/
|
|
69
|
+
content: ((options: JsonValue, tree: Root) => Promise<string> | string) | Rule[] | string;
|
|
70
|
+
}>, 'applicationOrder' | 'order' | 'required'> | string;
|
|
71
|
+
/**
|
|
72
|
+
* Rules are record objects whose keys match strings inside a Markdown comment, and values explain what should be expanded at the comment site.
|
|
73
|
+
*
|
|
74
|
+
* The record value may be a string, or an object containing additional metadata, possibly with a function to invoke to generate content.
|
|
75
|
+
*
|
|
76
|
+
*
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* Most basic rule:
|
|
80
|
+
* ```ts
|
|
81
|
+
* { basic: 'content' }
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* Rule with dynamic content:
|
|
85
|
+
* ```ts
|
|
86
|
+
* { basic: () => `${new Date().toISOString()}` }
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* Rule with metadata:
|
|
90
|
+
* ```ts
|
|
91
|
+
* { basic-meta: { required: true, content: 'content'} }
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* Rule with dynamic content and metadata:
|
|
95
|
+
* { basic-date: { required: true, content: () => `${new Date().toISOString()}` } }
|
|
96
|
+
*/
|
|
97
|
+
export type Rules = SimplifyDeep<Record<string, Rule>>;
|
|
98
|
+
export type NormalizedRules = SimplifyDeep<Record<string, NormalizedRule>>;
|
|
99
|
+
export declare function normalizeRules(rules: Rules): NormalizedRules;
|
|
100
|
+
export declare function validateRules(rules: Rules): void;
|
|
101
|
+
export declare const rulesSchema: z.ZodRecord<z.ZodString, z.ZodType<any, z.ZodTypeDef, any>>;
|
|
102
|
+
export declare const normalizedRulesSchema: z.ZodRecord<z.ZodString, z.ZodType<any, z.ZodTypeDef, any>>;
|
|
103
|
+
export declare function getRuleContent(rule: NormalizedRule, options: JsonValue, tree: Root, check?: boolean): Promise<string>;
|
|
104
|
+
export declare function getSoleRule<T extends NormalizedRules | Rules>(rules: T): T[keyof T];
|
|
105
|
+
export declare function getSoleRuleKey<T extends NormalizedRules | Rules>(rules: T): keyof T;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type Options as MdatOptions } from './mdast-utils/mdast-util-mdat';
|
|
2
|
+
import type { Root } from 'mdast';
|
|
3
|
+
import type { Plugin } from 'unified';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
export type Options = Partial<MdatOptions>;
|
|
6
|
+
export declare const optionsSchema: z.ZodObject<{
|
|
7
|
+
addMetaComment: z.ZodOptional<z.ZodBoolean>;
|
|
8
|
+
closingPrefix: z.ZodOptional<z.ZodString>;
|
|
9
|
+
keywordPrefix: z.ZodOptional<z.ZodString>;
|
|
10
|
+
metaCommentIdentifier: z.ZodOptional<z.ZodString>;
|
|
11
|
+
rules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<any, z.ZodTypeDef, any>>>;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
addMetaComment?: boolean | undefined;
|
|
14
|
+
closingPrefix?: string | undefined;
|
|
15
|
+
keywordPrefix?: string | undefined;
|
|
16
|
+
metaCommentIdentifier?: string | undefined;
|
|
17
|
+
rules?: Record<string, any> | undefined;
|
|
18
|
+
}, {
|
|
19
|
+
addMetaComment?: boolean | undefined;
|
|
20
|
+
closingPrefix?: string | undefined;
|
|
21
|
+
keywordPrefix?: string | undefined;
|
|
22
|
+
metaCommentIdentifier?: string | undefined;
|
|
23
|
+
rules?: Record<string, any> | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* A remark plugin that expands HTML comments in Markdown files.
|
|
27
|
+
*/
|
|
28
|
+
declare const remarkMdat: Plugin<[Options], Root>;
|
|
29
|
+
export default remarkMdat;
|
package/license.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Eric Mika
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "remark-mdat",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A remark plugin implementing the Markdown Autophagic Template (mdat) system.",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git@github.com:kitschpatrol/mdat.git",
|
|
9
|
+
"directory": "packages/remark-mdat"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/kitschpatrol/mdat/issues",
|
|
13
|
+
"email": "eric@ericmika.com"
|
|
14
|
+
},
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "Eric Mika",
|
|
17
|
+
"email": "eric@ericmika.com",
|
|
18
|
+
"url": "https://ericmika.com"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=16.0.0",
|
|
23
|
+
"pnpm": ">=8.0.0"
|
|
24
|
+
},
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"module": "./dist/index.js",
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"files": [
|
|
29
|
+
"dist/*"
|
|
30
|
+
],
|
|
31
|
+
"keywords": [
|
|
32
|
+
"mdat",
|
|
33
|
+
"markdown",
|
|
34
|
+
"template",
|
|
35
|
+
"comments",
|
|
36
|
+
"unist",
|
|
37
|
+
"mdast",
|
|
38
|
+
"mdast-util",
|
|
39
|
+
"syntax-tree",
|
|
40
|
+
"remark",
|
|
41
|
+
"remark-plugin"
|
|
42
|
+
],
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@types/mdast": "^4.0.3",
|
|
45
|
+
"@types/unist": "^3.0.2",
|
|
46
|
+
"chalk": "^5.3.0",
|
|
47
|
+
"cli-table3": "^0.6.3",
|
|
48
|
+
"deepmerge-ts": "^5.1.0",
|
|
49
|
+
"hast-util-from-html": "^2.0.1",
|
|
50
|
+
"json5": "^2.2.3",
|
|
51
|
+
"remark": "^15.0.1",
|
|
52
|
+
"remark-gfm": "^4.0.0",
|
|
53
|
+
"type-fest": "^4.10.2",
|
|
54
|
+
"unified": "^11.0.4",
|
|
55
|
+
"unist-util-visit": "^5.0.0",
|
|
56
|
+
"vfile": "^6.0.1",
|
|
57
|
+
"vfile-message": "^4.0.2",
|
|
58
|
+
"zod": "^3.22.4"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/node": "^20.11.14",
|
|
62
|
+
"tsup": "^8.0.1",
|
|
63
|
+
"typescript": "^5.3.3",
|
|
64
|
+
"vitest": "^1.2.2"
|
|
65
|
+
},
|
|
66
|
+
"publishConfig": {
|
|
67
|
+
"access": "public"
|
|
68
|
+
},
|
|
69
|
+
"scripts": {
|
|
70
|
+
"build": "tsup && tsc -p tsconfig.build.json",
|
|
71
|
+
"dev": "pnpm run test",
|
|
72
|
+
"mdat": "../mdat-readme/bin/cli.js --config ../../mdat.config.ts",
|
|
73
|
+
"test": "vitest"
|
|
74
|
+
}
|
|
75
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
<!--+ Warning: Content in HTML comment blocks generated by mdat on 2024-02-08 +-->
|
|
2
|
+
|
|
3
|
+
<!-- header -->
|
|
4
|
+
|
|
5
|
+
# remark-mdat
|
|
6
|
+
|
|
7
|
+
[](https://npmjs.com/package/remark-mdat)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
**A remark plugin implementing the Markdown Autophagic Template (mdat) system.**
|
|
11
|
+
|
|
12
|
+
<!-- /header -->
|
|
13
|
+
|
|
14
|
+
> \[!NOTE]\
|
|
15
|
+
> **Please see the [Mdat Monorepo readme](http://github.com/kitschpatrol/mdat) for additional context.**
|
|
16
|
+
|
|
17
|
+
<!-- table-of-contents -->
|
|
18
|
+
|
|
19
|
+
## Table of contents
|
|
20
|
+
|
|
21
|
+
- [Overview](#overview)
|
|
22
|
+
- [Getting started](#getting-started)
|
|
23
|
+
- [Dependencies](#dependencies)
|
|
24
|
+
- [Installation](#installation)
|
|
25
|
+
- [Usage](#usage)
|
|
26
|
+
- [API](#api)
|
|
27
|
+
- [Examples](#examples)
|
|
28
|
+
- [Utilities](#utilities)
|
|
29
|
+
- [The future](#the-future)
|
|
30
|
+
- [Maintainers](#maintainers)
|
|
31
|
+
- [Acknowledgements](#acknowledgements)
|
|
32
|
+
- [Contributing](#contributing)
|
|
33
|
+
- [License](#license)
|
|
34
|
+
|
|
35
|
+
<!-- /table-of-contents -->
|
|
36
|
+
|
|
37
|
+
## Overview
|
|
38
|
+
|
|
39
|
+
This is a [remark](https://remark.js.org) plugin that automates the inline expansion of placeholder HTML comments with dynamic content in Markdown, making it easy to keep readme files and other documentation in sync with an external single source of truth.
|
|
40
|
+
|
|
41
|
+
The plugin can take placeholder comments in a Markdown file like this:
|
|
42
|
+
|
|
43
|
+
```md
|
|
44
|
+
<!-- title -->
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
And replace it with dynamic data. In this case, from `package.json`:
|
|
48
|
+
|
|
49
|
+
```md
|
|
50
|
+
<!-- title -->
|
|
51
|
+
|
|
52
|
+
# remark-mdat
|
|
53
|
+
|
|
54
|
+
<!-- /title -->
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
This plugin powers the higher-level [`mdat`](../mdat) and [`mdat-readme`](../mdat-readme) packages in this monorepo. Either of those is a better place to start if you just want to expand some comments.
|
|
58
|
+
|
|
59
|
+
Please see the [Mdat Monorepo readme](http://github.com/kitschpatrol/mdat) for much more information and context.
|
|
60
|
+
|
|
61
|
+
## Getting started
|
|
62
|
+
|
|
63
|
+
### Dependencies
|
|
64
|
+
|
|
65
|
+
This library is ESM only and requires Node 16 or newer. It's designed to work with Remark 15. `remark-mdat` is implemented in TypeScript and bundles a complete set of type definitions.
|
|
66
|
+
|
|
67
|
+
### Installation
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
npm install remark-mdat
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Usage
|
|
74
|
+
|
|
75
|
+
### API
|
|
76
|
+
|
|
77
|
+
#### Core plugin
|
|
78
|
+
|
|
79
|
+
This package's default export implements the unified [Plugin](https://github.com/unifiedjs/unified#plugin) type.
|
|
80
|
+
|
|
81
|
+
The plugin is integrated into a remark process chain via the `.use()` method:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { remark } from 'remark'
|
|
85
|
+
import remarkMdat from 'remark-mdat'
|
|
86
|
+
|
|
87
|
+
remark().use(remarkMdat)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### Options
|
|
91
|
+
|
|
92
|
+
The plugin accepts an optional options object which exposes some configuration options and, most importantly, determines how comments in the source Markdown file will be expanded via the `rules` field:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
export type Options = {
|
|
96
|
+
addMetaComment?: Boolean // default: false
|
|
97
|
+
closingPrefix?: String // default: '/',
|
|
98
|
+
keywordPrefix?: String // default: '',
|
|
99
|
+
metaCommentIdentifier?: String // default: '+',
|
|
100
|
+
rules?: Rules // default: a single test rule for the 'mdat' keyword
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Examples
|
|
105
|
+
|
|
106
|
+
#### Basic
|
|
107
|
+
|
|
108
|
+
`remark-mdat` includes one test rule by default, `<!-- mdat -->`.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { remark } from 'remark'
|
|
112
|
+
import remarkMdat from 'remark-mdat'
|
|
113
|
+
|
|
114
|
+
const markdownInput = '<!-- mdat -->'
|
|
115
|
+
const markdownOutput = await remark().use(remarkMdat).process(markdown)
|
|
116
|
+
|
|
117
|
+
console.log(markdownOutput.toString())
|
|
118
|
+
|
|
119
|
+
// Logs:
|
|
120
|
+
// <!-- mdat -->
|
|
121
|
+
//
|
|
122
|
+
// Powered by the Markdown Autophagic Template system: [mdat](https://github.com/kitschpatrol/mdat).
|
|
123
|
+
//
|
|
124
|
+
// <!-- /mdat -->
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### With options
|
|
128
|
+
|
|
129
|
+
If you wanted to replace `<!-- time -->` comments in your Markdown file with the current time, you could pass in a rule:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { remark } from 'remark'
|
|
133
|
+
import { type Rules, default as remarkMdat } from 'remark-mdat'
|
|
134
|
+
|
|
135
|
+
// Create the rule
|
|
136
|
+
const rules: Rules = {
|
|
137
|
+
time: () => new Date().toDateString(),
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const markdownInput = '<!-- time -->'
|
|
141
|
+
|
|
142
|
+
// Pass the time rule to remarkMdat
|
|
143
|
+
const markdownOutput = await remark().use(remarkMdat, { rules }).process(markdown)
|
|
144
|
+
|
|
145
|
+
console.log(markdownOutput.toString())
|
|
146
|
+
|
|
147
|
+
// Logs:
|
|
148
|
+
// <!-- time -->
|
|
149
|
+
//
|
|
150
|
+
// Mon Feb 05 2024
|
|
151
|
+
//
|
|
152
|
+
// <!-- /time -->
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
See the [`mdat`](../mdat) package for a higher-level API and CLI that can operate directly on files or strings. It also provides dynamic rule loading and configuration resolution.
|
|
156
|
+
|
|
157
|
+
[`mdat-readme`](../mdat-readme) also provides a higher-still API and CLI, and bundles a collection of rules convenient for use in readme files.
|
|
158
|
+
|
|
159
|
+
## Utilities
|
|
160
|
+
|
|
161
|
+
The plugin bundles a number of [mdast](https://github.com/syntax-tree/mdast) utilities designed to operate directly on syntax trees. These are exported to support customized Unified.js processors and enforce modularity and separation of concerns in mdat's internal implementation, but you do not need to use them directly — all functionality is encapsulated in the single `remarkMdat` plugin export.
|
|
162
|
+
|
|
163
|
+
The remark-mdat plugin chains these utilities together to accommodate the typical use case of end-to-end expansion and validation of mdat comments. For now, the individual utility transformers are not published individually to NPM, and are instead bundled with `remark-mdat`.
|
|
164
|
+
|
|
165
|
+
- [**`mdast-util-mdat`**](./src/lib/mdast-utils/mdast-util-mdat.ts)
|
|
166
|
+
|
|
167
|
+
Composite transformer function performing end-to-end mdat comment expansion and validation on Markdown ASTs by chaining the other utility functions described below.
|
|
168
|
+
|
|
169
|
+
_Exported as `mdat`_
|
|
170
|
+
|
|
171
|
+
Utilities wrapped by `mdast-util-mdat`:
|
|
172
|
+
|
|
173
|
+
- [**`mdast-util-mdat-split`**](./src/lib/mdast-utils/mdast-util-mdat-split.ts)
|
|
174
|
+
|
|
175
|
+
Transformer function that allows inline mdat expansion comments.
|
|
176
|
+
|
|
177
|
+
_Exported as `mdatSplit`_
|
|
178
|
+
|
|
179
|
+
- [**`mdast-util-mdat-clean`**](./src/lib/mdast-utils/mdast-util-mdat-clean.ts)
|
|
180
|
+
|
|
181
|
+
Transformer function that "resets" all mdat comment expansions in a file, collapsing expanded comments back into single-line placeholders.
|
|
182
|
+
|
|
183
|
+
_Exported as `mdatClean`_
|
|
184
|
+
|
|
185
|
+
- [**`mdast-util-mdat-expand`**](./src/lib/mdast-utils/mdast-util-mdat-expand.ts)
|
|
186
|
+
|
|
187
|
+
Transformer function that expands mdat comments (e.g. `<!-- title -->`) in a Markdown file according to the rule set passed in to the `MdatExpandOptions` argument.
|
|
188
|
+
|
|
189
|
+
_Exported as `mdatExpand`_
|
|
190
|
+
|
|
191
|
+
- [**`mdast-util-mdat-check`**](./src/lib/mdast-utils/mdast-util-mdat-check.ts)
|
|
192
|
+
|
|
193
|
+
Transformer function that validates an expanded Markdown document against the requirements defined in the rules passed in to the `MdatCheckOptions` argument.
|
|
194
|
+
|
|
195
|
+
See `reporterMdat` to extract, format, and log results from VFile messages written by `mdatCheck`. This function does not modify the tree, it only appends messages to the VFiles passed through it.
|
|
196
|
+
|
|
197
|
+
_Exported as `mdatCheck`_
|
|
198
|
+
|
|
199
|
+
## The future
|
|
200
|
+
|
|
201
|
+
- Consider making remark a peer dependency? Though perhaps not [strip-markdown/issues/24](https://github.com/remarkjs/strip-markdown/issues/24)...
|
|
202
|
+
|
|
203
|
+
## Maintainers
|
|
204
|
+
|
|
205
|
+
[@kitschpatrol](https://github.com/kitschpatrol)
|
|
206
|
+
|
|
207
|
+
## Acknowledgements
|
|
208
|
+
|
|
209
|
+
Please see the [monorepo readme](../../readme.md#acknowledgments).
|
|
210
|
+
|
|
211
|
+
<!-- footer -->
|
|
212
|
+
|
|
213
|
+
## Contributing
|
|
214
|
+
|
|
215
|
+
[Issues](https://github.com/kitschpatrol/mdat/issues) and pull requests are welcome.
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
[MIT](license.txt) © Eric Mika
|
|
220
|
+
|
|
221
|
+
<!-- /footer -->
|