@d1vij/jassm 0.1.16 → 0.1.18-beta.1

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/README.md CHANGED
@@ -33,10 +33,10 @@ import react from "@vitejs/plugin-react";
33
33
  import jassm from "@d1vij/jassm/plugin";
34
34
 
35
35
  export default defineConfig({
36
- plugins: [
37
- jassm(), // Put jassm plugin before react's plugin
38
- react(),
39
- ],
36
+ plugins: [
37
+ jassm(), // Put jassm plugin before react's plugin
38
+ react(),
39
+ ],
40
40
  });
41
41
  ```
42
42
 
@@ -56,12 +56,12 @@ echo "# This is a Heading" > sample.mdx
56
56
  import { Registry } from "@d1vij/jassm";
57
57
 
58
58
  export const registry = new Registry({
59
- modules: import.meta.glob("/src/assets/mdx/**/*.mdx"),
60
- source: "/src/assets/mdx",
61
- mountOn: "/root",
62
- records: {
63
- "/sample": "/example.mdx",
64
- },
59
+ modules: import.meta.glob("/src/assets/mdx/**/*.mdx"),
60
+ source: "/src/assets/mdx",
61
+ mountOn: "/root",
62
+ records: {
63
+ "/sample": "/example.mdx",
64
+ },
65
65
  });
66
66
  ```
67
67
 
@@ -75,8 +75,8 @@ import type { StyleClassesMap } from "jassm";
75
75
  import "myStyles.css";
76
76
 
77
77
  export const stylesmap: StyleClassesMap = {
78
- header: "myHeader",
79
- paragraph: "pee",
78
+ header: "myHeader",
79
+ paragraph: "pee",
80
80
  };
81
81
  ```
82
82
 
@@ -88,8 +88,8 @@ import styles from "myStyles.module.css";
88
88
  import type { StyleClassesMap } from "jassm";
89
89
 
90
90
  export const stylesmap: StyleClassesMap = {
91
- header: styles.myHeader,
92
- paragraph: styles.pee,
91
+ header: styles.myHeader,
92
+ paragraph: styles.pee,
93
93
  };
94
94
  ```
95
95
 
@@ -143,17 +143,18 @@ import { stylesmap } from "./stylesmap";
143
143
  import { Suspense } from "react";
144
144
 
145
145
  export default function MyLoader() {
146
- const Component = registry["/root/sample"];
147
-
148
- return (
149
- <div>
150
- <StyleContext styles={stylesmap}>
151
- <Suspense>
152
- <Component components={Elements} />
153
- </Suspense>
154
- </StyleContext>
155
- </div>
156
- );
146
+ const Component = registry["/root/sample"];
147
+
148
+ return (
149
+ <div>
150
+ <StyleContext styles={stylesmap}>
151
+ <Suspense>
152
+ <Component components={Elements} />
153
+ </Suspense>
154
+ </StyleContext>
155
+ </div>
156
+ );
157
157
  }
158
158
  ```
159
+
159
160
  ---
package/dist/index.d.ts CHANGED
@@ -31,118 +31,201 @@ declare function generateElementsFrom<
31
31
  B extends boolean = true
32
32
  >(elements: E, baseElements?: B): { [K in B extends true ? keyof E | (typeof BaseElementTags)[number] : keyof E] : Element2 };
33
33
  /**
34
- * File extension(s) to accept
34
+ * Utility type that ensures a string starts with `/`
35
35
  */
36
- type MDXFile = `${string}.mdx`;
37
36
  type MustStartWithSlash<T extends string> = T extends `/${string}` ? T : never;
37
+ /**
38
+ * Utility type that ensures a string does NOT end with `/`
39
+ */
38
40
  type MustNotEndWithSlash<T extends string> = T extends `${string}/` ? never : T;
39
41
  /**
40
- * Options passed to {@link generateRegistries}
42
+ * Valid path that:
43
+ * - starts with `/`
44
+ * - does not end with `/`
45
+ */
46
+ type PathCheck<T extends string> = MustStartWithSlash<T> & MustNotEndWithSlash<T>;
47
+ /**
48
+ * Type returned by `import.meta.glob`
49
+ */
50
+ type WrappedUnknownPromise = () => Promise<unknown>;
51
+ /**
52
+ * Shape of glob result
53
+ */
54
+ type GlobResult<T> = Record<string, T>;
55
+ /**
56
+ * Removes `.mdx` extension from a path
57
+ */
58
+ type StripExtension<T extends string> = T extends `${infer P}.mdx` ? P : T;
59
+ /**
60
+ * Replace filesystem root with a virtual route prefix
61
+ *
62
+ * Example:
63
+ *
64
+ * `/src/content/foo.mdx`
65
+ * root = `/src/content`
66
+ * virtual = `/blog`
67
+ *
68
+ * Result:
69
+ * `/blog/foo`
70
+ */
71
+ type ReplaceRoot<
72
+ P extends string,
73
+ Root extends string,
74
+ Virtual extends string
75
+ > = P extends `${Root}${infer Rest}` ? `${Virtual}${StripExtension<Rest>}` : never;
76
+ /**
77
+ * Derives the route keys produced by the registry
78
+ *
79
+ * Example:
80
+ *
81
+ * `/src/blog/foo.mdx`
82
+ * → `/blog/foo`
83
+ */
84
+ type RouteKey<
85
+ Modules extends Record<string, unknown>,
86
+ Root extends string,
87
+ Virtual extends string
88
+ > = ReplaceRoot<Extract<keyof Modules, string>, Root, Virtual>;
89
+ /**
90
+ * Options passed to {@link generateRegistry}
41
91
  */
42
92
  type RegistryOptions<
43
- S extends string,
44
- M extends string,
45
- R extends Record<string, string>
93
+ MetaType,
94
+ Modules extends GlobResult<WrappedUnknownPromise>,
95
+ Root extends string,
96
+ Virtual extends string
46
97
  > = {
47
98
  /**
48
- * Module object returned from `import.meta.glob`
49
- * @example import.module.glob("/src/assets/mdx/**\/*.mdx")
99
+ * Module map returned from `import.meta.glob`
100
+ */
101
+ modulesGlob: Modules;
102
+ /**
103
+ * Metadata extracted from each MDX file
104
+ */
105
+ metadataGlob: { [K in keyof Modules] : MetaType };
106
+ /**
107
+ * Filesystem root path
108
+ */
109
+ root: PathCheck<Root>;
110
+ /**
111
+ * Virtual route mount point
112
+ */
113
+ virtual: PathCheck<Virtual>;
114
+ };
115
+ /**
116
+ * Internal function used by {@link Registry}.
117
+ *
118
+ * Builds registry mappings for:
119
+ * - keys
120
+ * - metadata
121
+ * - components
122
+ * - exports
123
+ */
124
+ declare function generateRegistry<
125
+ MetaType,
126
+ Modules extends GlobResult<WrappedUnknownPromise>,
127
+ Root extends string,
128
+ Virtual extends string
129
+ >({ modulesGlob, metadataGlob, root, virtual }: RegistryOptions<MetaType, Modules, Root, Virtual>): {
130
+ /**
131
+ * List of route keys
50
132
  */
51
- modules: Record<string, () => Promise<unknown>>;
133
+ keys: RouteKey<Modules, Root, Virtual>[];
52
134
  /**
53
- * Directory from which to resolve the source paths in {@link RegistryOptions.records}
135
+ * Metadata registry
54
136
  */
55
- source: MustNotEndWithSlash<S> & MustStartWithSlash<S>;
137
+ metadata: Record<RouteKey<Modules, Root, Virtual>, MetaType>;
56
138
  /**
57
- * Virtual base path on which to mount the key of {@link RegistryOptions.records}
139
+ * React lazy component registry
58
140
  */
59
- mountOn: MustNotEndWithSlash<M> & MustStartWithSlash<M>;
141
+ components: Record<RouteKey<Modules, Root, Virtual>, React.LazyExoticComponent<React.ComponentType>>;
60
142
  /**
61
- * Mappings of virtual path to file paths under {@link RegistryOptions.source}
143
+ * Raw module registry
62
144
  */
63
- records: { [K in keyof R] : K extends string ? MustNotEndWithSlash<K> & MustStartWithSlash<K> extends never ? never : R[K] extends MustStartWithSlash<R[K]> & MDXFile ? R[K] : never : never };
145
+ exports: Record<RouteKey<Modules, Root, Virtual>, Promise<Record<string, unknown>>>;
64
146
  };
65
- type RegistryKey<
66
- S extends string,
67
- M extends string,
68
- R extends Record<string, string>
69
- > = keyof RegistryOf<unknown, S, M, R>;
70
- /**
71
- * Constructor for any generic registry with keys in the format of `mount-path/virtual-path` for each virual path passed in {@link RegistryOptions.records}
72
- */
73
- type RegistryOf<
74
- T,
75
- S extends string,
76
- M extends string,
77
- R extends Record<string, string>
78
- > = { [K in keyof RegistryOptions<S, M, R>["records"] as `${RegistryOptions<S, M, R>["mountOn"]}${Extract<K, string>}`] : T };
79
- /**
80
- * Registry of react components
81
- */
82
- type ComponentRegistry<
83
- S extends string,
84
- M extends string,
85
- R extends Record<string, string>
86
- > = RegistryOf<React.LazyExoticComponent<React.ComponentType>, S, M, R>;
87
- /**
88
- * Registry of promise objects equivalent to return type of `import(<path>)`
89
- */
90
- type ExportsRegistry<
91
- S extends string,
92
- M extends string,
93
- R extends Record<string, string>
94
- > = RegistryOf<Promise<Record<string, unknown>>, S, M, R>;
95
- /**
96
- * Function to generate Registry mappings, use {@link Registry} class instead of this.
97
- * @param MDXRegistryOptions
98
- * @returns Tuple of [{@link ComponentRegistry}, {@link ExportsRegistry}]
99
- */
100
- declare function generateRegistries<
101
- S extends string,
102
- M extends string,
103
- R extends Record<string, string>
104
- >({ modules, source, mountOn, records }: RegistryOptions<S, M, R>): [ComponentRegistry<S, M, R>, ExportsRegistry<S, M, R>];
105
- /**
106
- * The returned object has the type of {@link React.ComponentType} + whatever user passes
107
- */
108
- type ExportSingleType<T> = Promise<T & {
109
- default: React.ComponentType;
110
- }>;
111
- type ExportAllType<T> = { [K in keyof T] : ExportSingleType<T[K]> };
147
+ /**
148
+ * Base class for all registry implementations.
149
+ *
150
+ * Provides type-safe access to:
151
+ * - components
152
+ * - module exports
153
+ * - metadata
154
+ */
112
155
  declare abstract class AbstractRegistry<
113
- C extends Record<string, React.LazyExoticComponent<React.ComponentType>>,
114
- E extends Record<string, unknown>
156
+ Keys extends string,
157
+ Components extends Record<Keys, React.LazyExoticComponent<React.ComponentType>>,
158
+ Exports extends Record<Keys, unknown>,
159
+ Metadata extends Record<Keys, unknown>
115
160
  > {
116
- abstract components: C;
117
- abstract exports: E;
118
- getComponent<K extends keyof C>(key: K): C[K];
119
- getComponents(): C;
120
- getExport<
121
- T extends object,
122
- K extends keyof E
123
- >(key: K): ExportSingleType<T>;
124
- getExports<T extends Record<keyof C, object> = Record<keyof C, object>>(): ExportAllType<T>;
161
+ /**
162
+ * List of registry keys
163
+ */
164
+ abstract readonly keys: readonly Keys[];
165
+ /**
166
+ * Lazy component registry
167
+ */
168
+ abstract readonly components: Components;
169
+ /**
170
+ * Raw module export registry
171
+ */
172
+ abstract readonly exports: Exports;
173
+ /**
174
+ * Metadata registry
175
+ */
176
+ abstract readonly metadata: Metadata;
177
+ /**
178
+ * Retrieve a React component by route key
179
+ */
180
+ getComponent<Key extends Keys>(key: Key): Components[Key];
181
+ /**
182
+ * Retrieve raw module exports for a route
183
+ */
184
+ getExport<Key extends Keys>(key: Key): Exports[Key];
185
+ /**
186
+ * Retrieve metadata for a route
187
+ */
188
+ getMetadata<Key extends Keys>(key: Key): Metadata[Key];
125
189
  }
126
190
  /**
127
- * Wrapper class over {@link generateRegistries}. Provides methods to access components and exports from typesafe keys
191
+ * Primary registry implementation.
192
+ *
193
+ * Wraps {@link generateRegistry} and exposes
194
+ * strongly typed access methods.
128
195
  */
129
196
  declare class Registry<
130
- S extends string,
131
- M extends string,
132
- R extends Record<string, string>
133
- > extends AbstractRegistry<ComponentRegistry<S, M, R>, ExportsRegistry<S, M, R>> {
134
- readonly components: ComponentRegistry<S, M, R>;
135
- readonly exports: ExportsRegistry<S, M, R>;
136
- constructor(registryOpts: RegistryOptions<S, M, R>);
197
+ MetaType,
198
+ Modules extends GlobResult<WrappedUnknownPromise>,
199
+ Root extends string,
200
+ Virtual extends string
201
+ > extends AbstractRegistry<RouteKey<Modules, Root, Virtual>, Record<RouteKey<Modules, Root, Virtual>, React.LazyExoticComponent<React.ComponentType>>, Record<RouteKey<Modules, Root, Virtual>, unknown>, Record<RouteKey<Modules, Root, Virtual>, MetaType>> {
202
+ readonly keys: RouteKey<Modules, Root, Virtual>[];
203
+ readonly components: Record<RouteKey<Modules, Root, Virtual>, React.LazyExoticComponent<React.ComponentType>>;
204
+ readonly exports: Record<RouteKey<Modules, Root, Virtual>, unknown>;
205
+ readonly metadata: Record<RouteKey<Modules, Root, Virtual>, MetaType>;
206
+ constructor(opts: RegistryOptions<MetaType, Modules, Root, Virtual>);
137
207
  }
138
- type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
139
208
  /**
140
- * Registry created by coalesing multiple {@link Registry} instances
209
+ * Utility types used for extracting generics
210
+ * from registry instances.
211
+ */
212
+ type RegistryKeys<R> = R extends AbstractRegistry<infer K, any, any, any> ? K : never;
213
+ type RegistryComponents<R> = R extends AbstractRegistry<any, infer C, any, any> ? C : never;
214
+ type RegistryExports<R> = R extends AbstractRegistry<any, any, infer E, any> ? E : never;
215
+ type RegistryMetadata<R> = R extends AbstractRegistry<any, any, any, infer M> ? M : never;
216
+ /**
217
+ * Registry created by merging multiple {@link Registry}
218
+ * instances into a single unified registry.
219
+ *
220
+ * Useful for combining multiple MDX content directories
221
+ * into one route registry.
141
222
  */
142
- declare class CoalescedRegistry<R extends readonly AbstractRegistry<Record<string, React.LazyExoticComponent<React.ComponentType>>, Record<string, unknown>>[]> extends AbstractRegistry<Record<keyof UnionToIntersection<R[number]["components"]>, React.LazyExoticComponent<React.ComponentType>>, Record<keyof UnionToIntersection<R[number]["exports"]>, unknown>> {
143
- readonly components: Record<keyof UnionToIntersection<R[number]["components"]>, React.LazyExoticComponent<React.ComponentType>>;
144
- readonly exports: Record<keyof UnionToIntersection<R[number]["exports"]>, unknown>;
145
- constructor(...registries: R);
223
+ declare class CoalescedRegistry<Registries extends AbstractRegistry<any, any, any, any>[]> extends AbstractRegistry<RegistryKeys<Registries[number]>, RegistryComponents<Registries[number]>, RegistryExports<Registries[number]>, RegistryMetadata<Registries[number]>> {
224
+ readonly keys: RegistryKeys<Registries[number]>[];
225
+ readonly components: RegistryComponents<Registries[number]>;
226
+ readonly exports: RegistryExports<Registries[number]>;
227
+ readonly metadata: RegistryMetadata<Registries[number]>;
228
+ constructor(...registries: Registries);
146
229
  }
147
230
  /**
148
231
  * List of default style classes
@@ -169,4 +252,4 @@ type MDXFromComponentProps = {
169
252
  * Simple way to directly load a component from the Registry
170
253
  */
171
254
  declare function MDXFromComponent({ source: SourceComponent, styles, fallback, elements }: MDXFromComponentProps): JSX;
172
- export { useStyles, generateRegistries, generateElementsFrom, StyleContext, StyleClassesMap, StyleClassesList, StyleClasses, RegistryOptions, RegistryOf, RegistryKey, Registry, MDXFromComponentProps, MDXFromComponent, MDXFile, MDXComponent, HeaderLevels, ExportsRegistry, ExportSingleType, ExportAllType, ElementProps, Element2 as Element, ComponentRegistry, CoalescedRegistry, BaseElements, BaseElementTags };
255
+ export { useStyles, generateRegistry, generateElementsFrom, StyleContext, StyleClassesMap, StyleClassesList, StyleClasses, RegistryOptions, Registry, MDXFromComponentProps, MDXFromComponent, MDXComponent, HeaderLevels, ElementProps, Element2 as Element, CoalescedRegistry, BaseElements, BaseElementTags };
package/dist/index.js CHANGED
@@ -314,10 +314,11 @@ function getTableJsonAsMarkdown(json) {
314
314
  function Table(props) {
315
315
  const styles = useStyles();
316
316
  const ref = useRef2(null);
317
+ const detailsRef = useRef2(null);
317
318
  const [open, setOpen] = useState3(false);
318
319
  const { copy } = useClipboardText2();
319
320
  useEffect2(() => {
320
- const elm = ref.current;
321
+ const elm = detailsRef.current;
321
322
  if (!elm)
322
323
  return;
323
324
  function handleMouseLeave() {
@@ -368,6 +369,7 @@ function Table(props) {
368
369
  children: props.children
369
370
  }),
370
371
  /* @__PURE__ */ jsxs("details", {
372
+ ref: detailsRef,
371
373
  className: cn13(styles.table_action_buttons_details),
372
374
  open,
373
375
  children: [
@@ -503,57 +505,73 @@ function generateElementsFrom(elements, baseElements = true) {
503
505
  }
504
506
  // src/lib/Registry.ts
505
507
  import { lazy } from "react";
506
- function generateRegistries({
507
- modules,
508
- source,
509
- mountOn,
510
- records
508
+ function generateRegistry({
509
+ modulesGlob,
510
+ metadataGlob,
511
+ root,
512
+ virtual
511
513
  }) {
512
- const components = [];
513
- const exports = [];
514
- for (const [virtual, path] of Object.entries(records)) {
515
- const src = `${source}${path}`;
516
- const loader = modules[src];
517
- if (!loader) {
518
- throw new Error(`No such file exsits as ${src}`);
519
- }
520
- components.push([`${mountOn}${virtual}`, lazy(loader)]);
521
- exports.push([`${mountOn}${virtual}`, loader()]);
514
+ const paths = Object.keys(modulesGlob);
515
+ const keys = new Array(paths.length);
516
+ const _components = [];
517
+ const _exports = [];
518
+ const _metadata = [];
519
+ for (const [idx, path] of paths.entries()) {
520
+ const route = path.replace(root, virtual).replace(".mdx", "");
521
+ const loader = modulesGlob[path];
522
+ keys[idx] = route;
523
+ _components.push([route, lazy(loader)]);
524
+ _exports.push([route, loader()]);
525
+ _metadata.push([route, metadataGlob[path]]);
522
526
  }
523
- return [Object.fromEntries(components), Object.fromEntries(exports)];
527
+ return {
528
+ keys,
529
+ components: Object.fromEntries(_components),
530
+ exports: Object.fromEntries(_exports),
531
+ metadata: Object.fromEntries(_metadata)
532
+ };
524
533
  }
525
534
 
526
535
  class AbstractRegistry {
527
536
  getComponent(key) {
528
537
  return this.components[key];
529
538
  }
530
- getComponents() {
531
- return this.components;
532
- }
533
539
  getExport(key) {
534
540
  return this.exports[key];
535
541
  }
536
- getExports() {
537
- return this.exports;
542
+ getMetadata(key) {
543
+ return this.metadata[key];
538
544
  }
539
545
  }
540
546
 
541
547
  class Registry extends AbstractRegistry {
548
+ keys;
542
549
  components;
543
550
  exports;
544
- constructor(registryOpts) {
551
+ metadata;
552
+ constructor(opts) {
545
553
  super();
546
- [this.components, this.exports] = generateRegistries(registryOpts);
554
+ const result = generateRegistry(opts);
555
+ this.keys = result.keys;
556
+ this.components = result.components;
557
+ this.exports = result.exports;
558
+ this.metadata = result.metadata;
547
559
  }
548
560
  }
549
561
 
550
562
  class CoalescedRegistry extends AbstractRegistry {
551
- components;
552
- exports;
563
+ keys = [];
564
+ components = {};
565
+ exports = {};
566
+ metadata = {};
553
567
  constructor(...registries) {
554
568
  super();
555
- this.components = Object.assign({}, ...registries.map((r) => r.getComponents()));
556
- this.exports = Object.assign({}, ...registries.map((r) => r.getExports()));
569
+ for (const registry of registries) {
570
+ this.keys.push(...registry.keys);
571
+ Object.assign(this.components, registry.components);
572
+ Object.assign(this.exports, registry.exports);
573
+ Object.assign(this.metadata, registry.metadata);
574
+ }
557
575
  }
558
576
  }
559
577
  // src/components/Loader.tsx
@@ -576,7 +594,7 @@ function MDXFromComponent({
576
594
  }
577
595
  export {
578
596
  useStyles,
579
- generateRegistries,
597
+ generateRegistry,
580
598
  generateElementsFrom,
581
599
  StyleContext,
582
600
  StyleClassesList,
package/package.json CHANGED
@@ -1,11 +1,17 @@
1
1
  {
2
2
  "name": "@d1vij/jassm",
3
+ "version": "0.1.18-beta.1",
3
4
  "description": "Just another static site maker. Create simple content driven sites using MDX and React along with Typescript safety.",
4
- "version": "0.1.16",
5
- "type": "module",
5
+ "homepage": "https://github.com/d1vij/jassm",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/d1vij/jassm.git"
10
+ },
6
11
  "files": [
7
12
  "dist"
8
13
  ],
14
+ "type": "module",
9
15
  "module": "./dist/index.js",
10
16
  "types": "./dist/index.d.ts",
11
17
  "exports": {
@@ -16,17 +22,11 @@
16
22
  }
17
23
  },
18
24
  "./plugin": {
19
- "import": "./dist/vitePlugin.js",
20
- "types": "./dist/vitePlugin.d.ts"
25
+ "types": "./dist/vitePlugin.d.ts",
26
+ "import": "./dist/vitePlugin.js"
21
27
  },
22
28
  "./package.json": "./package.json"
23
29
  },
24
- "repository": {
25
- "type": "git",
26
- "url": "git+https://github.com/d1vij/jassm.git"
27
- },
28
- "homepage": "https://github.com/d1vij/jassm",
29
- "license": "MIT",
30
30
  "publishConfig": {
31
31
  "access": "public"
32
32
  },
@@ -41,8 +41,11 @@
41
41
  "lint": "biome check --fix --unsafe && tsc -b",
42
42
  "format": "biome format --write"
43
43
  },
44
+ "dependencies": {
45
+ "@d1vij/shit-i-always-use": "^0.1.3"
46
+ },
44
47
  "devDependencies": {
45
- "@biomejs/biome": "^2.4.4",
48
+ "@biomejs/biome": "^2.4.6",
46
49
  "@types/bun": "^1.3.9",
47
50
  "@types/mdx": "^2.0.13",
48
51
  "@types/react": "^19.2.14",
@@ -65,9 +68,6 @@
65
68
  "optional": true
66
69
  }
67
70
  },
68
- "dependencies": {
69
- "@d1vij/shit-i-always-use": "^0.1.3"
70
- },
71
71
  "simple-git-hooks": {
72
72
  "pre-commit": "bun run lint && bun run type-check"
73
73
  }