@vxrn/mdx 1.2.53 → 1.2.55

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vxrn/mdx",
3
- "version": "1.2.53",
3
+ "version": "1.2.55",
4
4
  "type": "commonjs",
5
5
  "exports": {
6
6
  "./package.json": "./package.json",
@@ -5,13 +5,16 @@ import matter from 'gray-matter'
5
5
  import readingTime from 'reading-time'
6
6
  import { getHeadings } from './getHeadings'
7
7
  import type { Frontmatter } from './types'
8
+ import { notifyFileRead } from './watchFile'
8
9
 
9
10
  // the front matter and content of all mdx files based on `docsPaths`
10
11
  export const getAllFrontmatter = (fromPath: string): Frontmatter[] => {
11
12
  const paths = glob.sync(`${fromPath}/**/*.mdx`)
12
13
  return paths
13
14
  .map((filePath) => {
14
- const source = fs.readFileSync(path.join(filePath), 'utf8')
15
+ const absolutePath = path.join(filePath)
16
+ notifyFileRead(absolutePath)
17
+ const source = fs.readFileSync(absolutePath, 'utf8')
15
18
  const { data, content } = matter(source)
16
19
  const slug = filePath
17
20
  .replace(`${fromPath.replaceAll('\\', '/')}/`, '')
package/src/getMDX.ts CHANGED
@@ -4,17 +4,33 @@ import rehypeAutolinkHeadings from 'rehype-autolink-headings'
4
4
  import rehypeSlug from 'rehype-slug'
5
5
  import remarkGfm from 'remark-gfm'
6
6
  import { getHeadings } from './getHeadings'
7
+ import { processImageMeta } from './processImageMeta'
7
8
  import { rehypeHighlightCode } from './rehypeHighlightCode'
8
9
  import rehypeMetaAttribute from './rehypeMetaAttribute'
9
- import type { Frontmatter, UnifiedPlugin } from './types'
10
+ import type { Frontmatter, ImageMeta, UnifiedPlugin } from './types'
11
+
12
+ export type GetMDXOptions = {
13
+ extraPlugins?: UnifiedPlugin
14
+ /** Public directory for resolving image paths starting with / (default: ./public) */
15
+ publicDir?: string
16
+ }
17
+
18
+ export async function getMDX(
19
+ source: string,
20
+ extraPluginsOrOptions?: UnifiedPlugin | GetMDXOptions
21
+ ) {
22
+ // Handle both old signature (extraPlugins) and new options object
23
+ const opts: GetMDXOptions =
24
+ Array.isArray(extraPluginsOrOptions)
25
+ ? { extraPlugins: extraPluginsOrOptions }
26
+ : extraPluginsOrOptions ?? {}
10
27
 
11
- export async function getMDX(source: string, extraPlugins?: UnifiedPlugin) {
12
28
  const { frontmatter, code } = await bundleMDX({
13
29
  source,
14
30
  mdxOptions(options) {
15
31
  options.remarkPlugins = [...(options.remarkPlugins ?? []), remarkGfm]
16
32
  const plugins = [
17
- ...(extraPlugins || []),
33
+ ...(opts.extraPlugins || []),
18
34
  ...(options.rehypePlugins ?? []),
19
35
  rehypeMetaAttribute,
20
36
  rehypeHighlightCode,
@@ -26,11 +42,21 @@ export async function getMDX(source: string, extraPlugins?: UnifiedPlugin) {
26
42
  },
27
43
  })
28
44
 
45
+ // Process image metadata if frontmatter.image exists
46
+ let imageMeta: ImageMeta | undefined
47
+ if (frontmatter.image && typeof frontmatter.image === 'string') {
48
+ const meta = await processImageMeta(frontmatter.image, { publicDir: opts.publicDir })
49
+ if (meta) {
50
+ imageMeta = meta
51
+ }
52
+ }
53
+
29
54
  return {
30
55
  frontmatter: {
31
56
  ...frontmatter,
32
57
  headings: getHeadings(source),
33
58
  readingTime: readingTime(code),
59
+ imageMeta,
34
60
  } as Frontmatter,
35
61
  code,
36
62
  }
@@ -3,6 +3,7 @@ import path from 'node:path'
3
3
  import compareVersions from 'compare-versions'
4
4
  import { getMDX } from './getMDX'
5
5
  import type { Frontmatter, UnifiedPlugin } from './types'
6
+ import { notifyFileRead } from './watchFile'
6
7
 
7
8
  export const getMDXBySlug = async (
8
9
  basePath: string,
@@ -18,6 +19,7 @@ export const getMDXBySlug = async (
18
19
  }
19
20
 
20
21
  const filePath = path.join(basePath, `${mdxPath}.mdx`)
22
+ notifyFileRead(filePath)
21
23
  const source = fs.readFileSync(filePath, 'utf8')
22
24
  const bundle = await getMDX(source, extraPlugins)
23
25
  return bundle
package/src/index.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export { getAllFrontmatter } from './getAllFrontmatter'
2
- export { getMDX } from './getMDX'
2
+ export { getMDX, type GetMDXOptions } from './getMDX'
3
3
  export { getAllVersionsFromPath, getMDXBySlug } from './getMDXBySlug'
4
4
  export { createCodeHighlighter } from './highlightCode'
5
5
  export { rehypeHeroTemplate } from './rehypeHeroTemplate'
6
- export type { Frontmatter } from './types'
6
+ export { notifyFileRead } from './watchFile'
7
+ export type { Frontmatter, ImageMeta } from './types'
7
8
  export type { RehypeHeroTemplateOptions } from './rehypeHeroTemplate'
@@ -0,0 +1,55 @@
1
+ import { existsSync } from 'node:fs'
2
+ import { resolve } from 'node:path'
3
+ import type { ImageMeta } from './types'
4
+
5
+ async function getSharp(): Promise<typeof import('sharp') | null> {
6
+ try {
7
+ const sharpModule = await import('sharp')
8
+ return (sharpModule as any).default || sharpModule
9
+ } catch {
10
+ // silent fallback - no warning needed
11
+ return null
12
+ }
13
+ }
14
+
15
+ /**
16
+ * Process an image file and return its metadata.
17
+ * Returns null if sharp is not installed or processing fails.
18
+ */
19
+ export async function processImageMeta(
20
+ imagePath: string,
21
+ opts?: { publicDir?: string }
22
+ ): Promise<ImageMeta | null> {
23
+ const publicDir = opts?.publicDir ?? './public'
24
+
25
+ // Resolve the file path
26
+ let filePath: string
27
+ if (imagePath.startsWith('/')) {
28
+ filePath = resolve(publicDir, imagePath.slice(1))
29
+ } else {
30
+ filePath = resolve(imagePath)
31
+ }
32
+
33
+ if (!existsSync(filePath)) {
34
+ return null
35
+ }
36
+
37
+ const sharp = await getSharp()
38
+ if (!sharp) {
39
+ return null
40
+ }
41
+
42
+ try {
43
+ const image = sharp(filePath)
44
+ const metadata = await image.metadata()
45
+ const { width = 0, height = 0 } = metadata
46
+
47
+ // Generate blur placeholder (10px wide, maintains aspect ratio)
48
+ const blurBuffer = await image.resize(10).blur(1).jpeg({ quality: 40 }).toBuffer()
49
+ const blurDataURL = `data:image/jpeg;base64,${blurBuffer.toString('base64')}`
50
+
51
+ return { width, height, blurDataURL }
52
+ } catch {
53
+ return null
54
+ }
55
+ }
package/src/types.ts CHANGED
@@ -1,3 +1,9 @@
1
+ export type ImageMeta = {
2
+ width: number
3
+ height: number
4
+ blurDataURL: string
5
+ }
6
+
1
7
  export type Frontmatter = {
2
8
  title: string
3
9
  headings?: { title: string; priority: number; id: string }[]
@@ -14,6 +20,8 @@ export type Frontmatter = {
14
20
  poster?: string
15
21
  slug: string
16
22
  image?: string
23
+ /** Image metadata (dimensions and blur placeholder) - populated if image exists and sharp is installed */
24
+ imageMeta?: ImageMeta
17
25
  component?: string
18
26
  package?: string
19
27
  demoName?: string
@@ -0,0 +1,13 @@
1
+ const WATCH_FILE_KEY = '__oneWatchFile'
2
+
3
+ /**
4
+ * Notifies One's HMR system about a file dependency.
5
+ * When One is present, this enables automatic hot reload when the file changes.
6
+ * No-op when One is not present or in production.
7
+ */
8
+ export function notifyFileRead(filePath: string): void {
9
+ const watchFile = globalThis[WATCH_FILE_KEY] as ((path: string) => void) | undefined
10
+ if (watchFile) {
11
+ watchFile(filePath)
12
+ }
13
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"getAllFrontmatter.d.ts","sourceRoot":"","sources":["../src/getAllFrontmatter.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAG1C,eAAO,MAAM,iBAAiB,GAAI,UAAU,MAAM,KAAG,WAAW,EAoB/D,CAAA"}
1
+ {"version":3,"file":"getAllFrontmatter.d.ts","sourceRoot":"","sources":["../src/getAllFrontmatter.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAI1C,eAAO,MAAM,iBAAiB,GAAI,UAAU,MAAM,KAAG,WAAW,EAsB/D,CAAA"}
package/types/getMDX.d.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  import type { Frontmatter, UnifiedPlugin } from './types';
2
- export declare function getMDX(source: string, extraPlugins?: UnifiedPlugin): Promise<{
2
+ export type GetMDXOptions = {
3
+ extraPlugins?: UnifiedPlugin;
4
+ /** Public directory for resolving image paths starting with / (default: ./public) */
5
+ publicDir?: string;
6
+ };
7
+ export declare function getMDX(source: string, extraPluginsOrOptions?: UnifiedPlugin | GetMDXOptions): Promise<{
3
8
  frontmatter: Frontmatter;
4
9
  code: string;
5
10
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"getMDX.d.ts","sourceRoot":"","sources":["../src/getMDX.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAEzD,wBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,aAAa;iBAuBhE,WAAW;;GAGnB"}
1
+ {"version":3,"file":"getMDX.d.ts","sourceRoot":"","sources":["../src/getMDX.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAa,aAAa,EAAE,MAAM,SAAS,CAAA;AAEpE,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,CAAC,EAAE,aAAa,CAAA;IAC5B,qFAAqF;IACrF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,wBAAsB,MAAM,CAC1B,MAAM,EAAE,MAAM,EACd,qBAAqB,CAAC,EAAE,aAAa,GAAG,aAAa;iBAwC9C,WAAW;;GAGnB"}
@@ -1 +1 @@
1
- {"version":3,"file":"getMDXBySlug.d.ts","sourceRoot":"","sources":["../src/getMDXBySlug.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAEzD,eAAO,MAAM,YAAY,GACvB,UAAU,MAAM,EAChB,MAAM,MAAM,EACZ,eAAe,aAAa,KAC3B,OAAO,CAAC;IAAE,WAAW,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAapD,CAAA;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAOjE"}
1
+ {"version":3,"file":"getMDXBySlug.d.ts","sourceRoot":"","sources":["../src/getMDXBySlug.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAGzD,eAAO,MAAM,YAAY,GACvB,UAAU,MAAM,EAChB,MAAM,MAAM,EACZ,eAAe,aAAa,KAC3B,OAAO,CAAC;IAAE,WAAW,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAcpD,CAAA;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAOjE"}
package/types/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  export { getAllFrontmatter } from './getAllFrontmatter';
2
- export { getMDX } from './getMDX';
2
+ export { getMDX, type GetMDXOptions } from './getMDX';
3
3
  export { getAllVersionsFromPath, getMDXBySlug } from './getMDXBySlug';
4
4
  export { createCodeHighlighter } from './highlightCode';
5
5
  export { rehypeHeroTemplate } from './rehypeHeroTemplate';
6
- export type { Frontmatter } from './types';
6
+ export { notifyFileRead } from './watchFile';
7
+ export type { Frontmatter, ImageMeta } from './types';
7
8
  export type { RehypeHeroTemplateOptions } from './rehypeHeroTemplate';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACzD,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAC1C,YAAY,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAA;AACrD,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACrD,YAAY,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,9 @@
1
+ import type { ImageMeta } from './types';
2
+ /**
3
+ * Process an image file and return its metadata.
4
+ * Returns null if sharp is not installed or processing fails.
5
+ */
6
+ export declare function processImageMeta(imagePath: string, opts?: {
7
+ publicDir?: string;
8
+ }): Promise<ImageMeta | null>;
9
+ //# sourceMappingURL=processImageMeta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processImageMeta.d.ts","sourceRoot":"","sources":["../src/processImageMeta.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAYxC;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5B,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAiC3B"}
package/types/types.d.ts CHANGED
@@ -1,3 +1,8 @@
1
+ export type ImageMeta = {
2
+ width: number;
3
+ height: number;
4
+ blurDataURL: string;
5
+ };
1
6
  export type Frontmatter = {
2
7
  title: string;
3
8
  headings?: {
@@ -23,6 +28,8 @@ export type Frontmatter = {
23
28
  poster?: string;
24
29
  slug: string;
25
30
  image?: string;
31
+ /** Image metadata (dimensions and blur placeholder) - populated if image exists and sharp is installed */
32
+ imageMeta?: ImageMeta;
26
33
  component?: string;
27
34
  package?: string;
28
35
  demoName?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,IAAI,CAAC,EAAE,WAAW,GAAG,MAAM,CAAA;IAC3B,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,SAAS,EAAE,MAAM,EAAE,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,IAAI,CAAC,EAAE,WAAW,GAAG,MAAM,CAAA;IAC3B,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,0GAA0G;IAC1G,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,SAAS,EAAE,MAAM,EAAE,CAAA"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Notifies One's HMR system about a file dependency.
3
+ * When One is present, this enables automatic hot reload when the file changes.
4
+ * No-op when One is not present or in production.
5
+ */
6
+ export declare function notifyFileRead(filePath: string): void;
7
+ //# sourceMappingURL=watchFile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watchFile.d.ts","sourceRoot":"","sources":["../src/watchFile.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAKrD"}