@lensmap/astro-loader 0.2.1 → 0.3.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/adapter.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type SemanticGraph } from "@lensmap/document";
1
+ import { type SemanticGraph, type VocabularyInput } from "@lensmap/document";
2
2
  export interface ExecutionOptions {
3
3
  /** Exact local files, compared after realpath. Admission is not sandboxing. */
4
4
  mdx?: {
@@ -20,6 +20,6 @@ export interface ParsedMap {
20
20
  authoredFrontmatter: Record<string, unknown>;
21
21
  graph: SemanticGraph;
22
22
  }
23
- export declare function parseMap(source: string, uri: string): ParsedMap;
23
+ export declare function parseMap(source: string, uri: string, vocabulary?: VocabularyInput): ParsedMap;
24
24
  export declare function moduleStem(path: string): string;
25
25
  export declare function writeGenerated(path: string, content: string): boolean;
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  // src/index.ts
2
- import { mkdirSync, readFileSync as readFileSync2 } from "node:fs";
2
+ import { mkdirSync, readFileSync as readFileSync2, realpathSync as realpathSync2 } from "node:fs";
3
3
  import { resolve } from "node:path";
4
4
  import { fileURLToPath as fileURLToPath2 } from "node:url";
5
+ import { readProjectVocabulary } from "@lensmap/document/project";
5
6
  import { glob } from "astro/loaders";
6
7
 
7
8
  // src/adapter.ts
@@ -27,8 +28,13 @@ function canExecute(source, options, installed) {
27
28
  return false;
28
29
  }
29
30
  }
30
- function parseMap(source, uri) {
31
- const snapshot = new DocumentSession(uri, source).snapshot();
31
+ function parseMap(source, uri, vocabulary) {
32
+ const snapshot = new DocumentSession(
33
+ uri,
34
+ source,
35
+ void 0,
36
+ vocabulary
37
+ ).snapshot();
32
38
  if (!snapshot.valid || !snapshot.graph)
33
39
  throw new Error(
34
40
  `Invalid Lensmap ${uri}: ${JSON.stringify(snapshot.diagnostics)}`
@@ -98,10 +104,76 @@ function lensmap(options = {}) {
98
104
  let config;
99
105
  let renderer;
100
106
  let installedMdx = false;
107
+ let vocabulary = {};
108
+ let vocabularyFiles = [];
109
+ let generation = 0;
110
+ const maps = /* @__PURE__ */ new Map();
111
+ async function reloadVocabulary() {
112
+ const current = ++generation;
113
+ const root = realpathSync2(fileURLToPath2(config.root));
114
+ const loaded = await readProjectVocabulary(root);
115
+ if (current !== generation) return false;
116
+ vocabulary = loaded.input;
117
+ vocabularyFiles = loaded.files;
118
+ return true;
119
+ }
120
+ async function publishVocabulary(server) {
121
+ if (!await reloadVocabulary()) return [];
122
+ server.watcher.add(vocabularyFiles);
123
+ for (const [uri, map] of maps) {
124
+ try {
125
+ const { graph } = parseMap(map.source, uri, vocabulary);
126
+ server.ws.send("lensmap:vocabulary", {
127
+ id: map.id,
128
+ stale: false,
129
+ edges: graph.edges.map(
130
+ ({ key, from, to, kind, type, presentation }) => ({
131
+ key,
132
+ from,
133
+ to,
134
+ kind,
135
+ type,
136
+ presentation
137
+ })
138
+ ),
139
+ nodes: graph.nodes.map(({ key, destination }) => ({
140
+ key,
141
+ destination
142
+ }))
143
+ });
144
+ } catch (error) {
145
+ server.config.logger.error(
146
+ error instanceof Error ? error.message : String(error)
147
+ );
148
+ server.ws.send("lensmap:vocabulary", { id: map.id, stale: true });
149
+ }
150
+ }
151
+ for (const uri of maps.keys()) {
152
+ for (const environment of Object.values(server.environments)) {
153
+ for (const module of environment.moduleGraph.getModulesByFile(
154
+ fileURLToPath2(uri)
155
+ ) ?? []) {
156
+ environment.moduleGraph.invalidateModule(module);
157
+ }
158
+ }
159
+ }
160
+ }
101
161
  const mdxModules = /* @__PURE__ */ new Map();
102
162
  return {
103
163
  name: "@lensmap/astro-loader",
104
164
  hooks: {
165
+ "astro:server:setup": ({ server }) => {
166
+ server.watcher.add(vocabularyFiles);
167
+ const changed = (path) => {
168
+ if (vocabularyFiles.includes(path)) void publishVocabulary(server);
169
+ };
170
+ server.watcher.on("add", changed);
171
+ server.watcher.on("unlink", changed);
172
+ server.httpServer?.once("close", () => {
173
+ server.watcher.off("add", changed);
174
+ server.watcher.off("unlink", changed);
175
+ });
176
+ },
105
177
  "astro:config:setup": (setup) => {
106
178
  const version = JSON.parse(
107
179
  readFileSync2(
@@ -124,9 +196,22 @@ function lensmap(options = {}) {
124
196
  {
125
197
  name: "lensmap-source-relative-mdx",
126
198
  enforce: "pre",
127
- resolveId(id) {
199
+ resolveId(id, _importer, resolveOptions) {
200
+ if (resolveOptions.ssr && id === "@lensmap/document")
201
+ return {
202
+ id: fileURLToPath2(
203
+ new URL(import.meta.resolve("@lensmap/document"))
204
+ ),
205
+ external: true
206
+ };
128
207
  if (mdxModules.has(id)) return id;
129
208
  },
209
+ async hotUpdate(context) {
210
+ if (!vocabularyFiles.includes(context.file)) return;
211
+ if (this.environment.name !== "client") return [];
212
+ await publishVocabulary(context.server);
213
+ return [];
214
+ },
130
215
  load(id) {
131
216
  const module = mdxModules.get(id.split("?")[0] ?? id);
132
217
  if (!module) return;
@@ -144,7 +229,8 @@ function lensmap(options = {}) {
144
229
  getEntryInfo({ contents, fileUrl }) {
145
230
  const { authoredFrontmatter: data, graph } = parseMap(
146
231
  contents,
147
- fileUrl.href
232
+ fileUrl.href,
233
+ vocabulary
148
234
  );
149
235
  return {
150
236
  data,
@@ -155,9 +241,12 @@ function lensmap(options = {}) {
155
241
  },
156
242
  async getRenderModule({ contents, fileUrl }) {
157
243
  const path = fileURLToPath2(fileUrl);
244
+ const mapId = moduleStem(path);
245
+ maps.set(fileUrl.href, { source: contents, id: mapId });
158
246
  const { graph, authoredFrontmatter } = parseMap(
159
247
  contents,
160
- fileUrl.href
248
+ fileUrl.href,
249
+ vocabulary
161
250
  );
162
251
  const executable = canExecute(
163
252
  { kind: "local", path },
@@ -216,7 +305,7 @@ ${imports.join("\n")}
216
305
  const graph = ${quote(graph)};
217
306
  const authoredFrontmatter = ${quote(authoredFrontmatter)};
218
307
  ---
219
- <MapContent {...Astro.props} graph={graph} authoredFrontmatter={authoredFrontmatter} executable={${executable}}>
308
+ <MapContent {...Astro.props} graph={graph} mapId={${quote(mapId)}} authoredFrontmatter={authoredFrontmatter} executable={${executable}}>
220
309
  ${slots.join("\n")}
221
310
  </MapContent>
222
311
  `
@@ -228,8 +317,13 @@ ${slots.join("\n")}
228
317
  }
229
318
  });
230
319
  },
231
- "astro:config:done": ({ config: resolved }) => {
320
+ "astro:config:done": async ({ config: resolved }) => {
232
321
  config = resolved;
322
+ await reloadVocabulary();
323
+ if (vocabulary.error)
324
+ throw new Error(
325
+ `Invalid Lensmap project vocabulary: ${vocabulary.error}`
326
+ );
233
327
  installedMdx = resolved.integrations.some(
234
328
  (integration) => integration.name === "@astrojs/mdx"
235
329
  );
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.2.1",
2
+ "version": "0.3.0",
3
3
  "type": "module",
4
4
  "license": "MIT",
5
5
  "files": [
@@ -28,7 +28,7 @@
28
28
  "./components/*": "./dist/components/*"
29
29
  },
30
30
  "dependencies": {
31
- "@lensmap/document": "0.2.1",
31
+ "@lensmap/document": "0.3.0",
32
32
  "rehype-parse": "9.0.1",
33
33
  "rehype-sanitize": "6.0.0",
34
34
  "rehype-stringify": "10.0.1",
@@ -36,15 +36,15 @@
36
36
  "yaml": "2.9.1"
37
37
  },
38
38
  "peerDependencies": {
39
- "astro": "7.4.0",
40
- "@astrojs/mdx": "8.1.0"
39
+ "@astrojs/mdx": "8.1.0",
40
+ "astro": "7.4.0"
41
41
  },
42
42
  "devDependencies": {
43
- "astro": "7.4.0",
44
43
  "@astrojs/mdx": "8.1.0",
44
+ "@types/node": "24.19.2",
45
+ "astro": "7.4.0",
45
46
  "esbuild": "0.28.2",
46
- "typescript": "7.0.2",
47
- "@types/node": "24.19.2"
47
+ "typescript": "7.0.2"
48
48
  },
49
49
  "peerDependenciesMeta": {
50
50
  "@astrojs/mdx": {