@slidev/parser 52.17.0 → 52.17.2

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/fs.d.mts CHANGED
@@ -2,10 +2,22 @@ import { a as TimesplitOutput, i as TimesplitInput, n as parseRangeString, o as
2
2
  import { SlidevParserOptions, detectFeatures, extractImagesUsage, getDefaultConfig, parse, parseSlide, parseSync, prettify, prettifySlide, resolveConfig, resolveFonts, stringify, stringifySlide, verifyConfig } from "./core.mjs";
3
3
  import { PreparserExtensionLoader, SlidevData, SlidevMarkdown } from "@slidev/types";
4
4
  //#region src/fs.d.ts
5
+ /**
6
+ * Whether `filePath` resolves inside any of `roots` (no `..` escape).
7
+ * Inlined here (rather than imported from the `slidev` package) because
8
+ * `@slidev/parser` must stay independent of `@slidev/slidev`.
9
+ */
10
+ declare function isPathInsideRoots(filePath: string, roots: string[]): boolean;
5
11
  declare function injectPreparserExtensionLoader(fn: PreparserExtensionLoader): void;
6
12
  interface LoadRootsInfo {
7
13
  roots: string[];
8
14
  userRoot: string;
15
+ /**
16
+ * When provided, `src:` includes resolving outside these roots are
17
+ * rejected (recorded as an error) instead of being loaded. Optional for
18
+ * backward compatibility with other `@slidev/parser` consumers.
19
+ */
20
+ allowedRoots?: string[];
9
21
  }
10
22
  /**
11
23
  * Slidev data without config and themeMeta,
@@ -15,4 +27,4 @@ type LoadedSlidevData = Omit<SlidevData, 'config' | 'themeMeta'>;
15
27
  declare function load(options: LoadRootsInfo, filepath: string, sources?: Record<string, string> | ((path: string) => Promise<string>), mode?: string): Promise<LoadedSlidevData>;
16
28
  declare function save(markdown: SlidevMarkdown): Promise<string>;
17
29
  //#endregion
18
- export { LoadRootsInfo, LoadedSlidevData, SlidevParserOptions, TimesplitInput, TimesplitOutput, detectFeatures, extractImagesUsage, getDefaultConfig, injectPreparserExtensionLoader, load, parse, parseAspectRatio, parseRangeString, parseSlide, parseSync, parseTimeString, parseTimesplits, prettify, prettifySlide, resolveConfig, resolveFonts, save, stringify, stringifySlide, verifyConfig };
30
+ export { LoadRootsInfo, LoadedSlidevData, SlidevParserOptions, TimesplitInput, TimesplitOutput, detectFeatures, extractImagesUsage, getDefaultConfig, injectPreparserExtensionLoader, isPathInsideRoots, load, parse, parseAspectRatio, parseRangeString, parseSlide, parseSync, parseTimeString, parseTimesplits, prettify, prettifySlide, resolveConfig, resolveFonts, save, stringify, stringifySlide, verifyConfig };
package/dist/fs.mjs CHANGED
@@ -4,8 +4,19 @@ import { slash } from "@antfu/utils";
4
4
  import YAML from "yaml";
5
5
  import { existsSync } from "node:fs";
6
6
  import { readFile, writeFile } from "node:fs/promises";
7
- import { dirname, resolve } from "node:path";
7
+ import { dirname, isAbsolute, relative, resolve } from "pathe";
8
8
  //#region src/fs.ts
9
+ /**
10
+ * Whether `filePath` resolves inside any of `roots` (no `..` escape).
11
+ * Inlined here (rather than imported from the `slidev` package) because
12
+ * `@slidev/parser` must stay independent of `@slidev/slidev`.
13
+ */
14
+ function isPathInsideRoots(filePath, roots) {
15
+ return roots.some((root) => {
16
+ const rel = relative(root, filePath);
17
+ return rel === "" || !!rel && !rel.startsWith("..") && !isAbsolute(rel);
18
+ });
19
+ }
9
20
  const RE_FRONTMATTER_START = /^---(?:[^-].*)?$/;
10
21
  const RE_BLANK_LINE = /^\s*$/;
11
22
  const RE_FRONTMATTER_END = /^---$/;
@@ -66,7 +77,22 @@ async function load(options, filepath, sources = {}, mode) {
66
77
  ...frontmatterOverride
67
78
  };
68
79
  delete frontmatterOverride.src;
69
- if (!existsSync(path)) {
80
+ const ancestorPaths = new Set((importChain ?? []).map((s) => s.filepath));
81
+ if (path === slide.filepath || ancestorPaths.has(path)) {
82
+ md.errors ??= [];
83
+ md.errors.push({
84
+ row: slide.start,
85
+ message: `Circular import detected for "${slide.frontmatter.src}" (${path})`
86
+ });
87
+ return;
88
+ }
89
+ if (options.allowedRoots && !isPathInsideRoots(path, options.allowedRoots)) {
90
+ md.errors ??= [];
91
+ md.errors.push({
92
+ row: slide.start,
93
+ message: `Imported markdown escapes the project root: ${path}`
94
+ });
95
+ } else if (!existsSync(path)) {
70
96
  md.errors ??= [];
71
97
  md.errors.push({
72
98
  row: slide.start,
@@ -107,4 +133,4 @@ async function save(markdown) {
107
133
  return fileContent;
108
134
  }
109
135
  //#endregion
110
- export { detectFeatures, extractImagesUsage, getDefaultConfig, injectPreparserExtensionLoader, load, parse, parseAspectRatio, parseRangeString, parseSlide, parseSync, parseTimeString, parseTimesplits, prettify, prettifySlide, resolveConfig, resolveFonts, save, stringify, stringifySlide, verifyConfig };
136
+ export { detectFeatures, extractImagesUsage, getDefaultConfig, injectPreparserExtensionLoader, isPathInsideRoots, load, parse, parseAspectRatio, parseRangeString, parseSlide, parseSync, parseTimeString, parseTimesplits, prettify, prettifySlide, resolveConfig, resolveFonts, save, stringify, stringifySlide, verifyConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slidev/parser",
3
- "version": "52.17.0",
3
+ "version": "52.17.2",
4
4
  "description": "Markdown parser for Slidev",
5
5
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
6
6
  "license": "MIT",
@@ -30,8 +30,9 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@antfu/utils": "^9.3.0",
33
+ "pathe": "^2.0.3",
33
34
  "yaml": "^2.9.0",
34
- "@slidev/types": "52.17.0"
35
+ "@slidev/types": "52.17.2"
35
36
  },
36
37
  "devDependencies": {
37
38
  "tsdown-stale-guard": "^0.1.2"