@se-studio/markdown-renderer 1.0.126 → 1.0.128
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @se-studio/markdown-renderer
|
|
2
2
|
|
|
3
|
+
## 1.0.128
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [ccad4d9]
|
|
8
|
+
- @se-studio/core-data-types@1.0.167
|
|
9
|
+
- @se-studio/contentful-rest-api@1.0.176
|
|
10
|
+
|
|
11
|
+
## 1.0.127
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- **`resolveMarkdownParams`**: Add optional `articleTypeSlugs` for multi-segment article type paths (e.g. `resources/news`). Callers must pass slugs longest-first; development validates sort order. Unmatched configured paths return 404 instead of falling back to a single segment.
|
|
16
|
+
|
|
3
17
|
## 1.0.126
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -83,7 +83,8 @@ When building a markdown API route (e.g. `/api/markdown/[...params]`), use `reso
|
|
|
83
83
|
Options:
|
|
84
84
|
|
|
85
85
|
- **articlesBaseIsPage**: When `true`, a single segment `articles` resolves as a page with slug `"articles"`.
|
|
86
|
-
- **enablePrimaryTagPartOfSlug**: When `true`, article paths
|
|
86
|
+
- **enablePrimaryTagPartOfSlug**: When `true`, article paths include a primary tag segment: `articles/:type/:tag/:slug` (or more segments when `articleTypeSlugs` is set).
|
|
87
|
+
- **articleTypeSlugs**: Article type slugs in Contentful that span multiple URL segments after `articles/`. Pass slugs **longest-first** (e.g. `['resources/news', 'resources/publications']` before single-segment types). The resolver matches the first configured prefix; unmatched paths return 404. In development, unsorted lists throw. Example path: `/api/markdown/articles/resources/news/:tag/:slug/`.
|
|
87
88
|
- **peopleCustomType**: Contentful custom type for person entries (default `'people'`). Use e.g. `'team'` when your app uses a different content type.
|
|
88
89
|
|
|
89
90
|
### Types
|
|
@@ -2,6 +2,8 @@ export interface MarkdownRouteOptions {
|
|
|
2
2
|
/** When true, /articles (single segment) resolves as a page with slug "articles". */
|
|
3
3
|
articlesBaseIsPage: boolean;
|
|
4
4
|
enablePrimaryTagPartOfSlug: boolean;
|
|
5
|
+
/** Article type slugs that span multiple URL segments after `articles/`. Longest first. */
|
|
6
|
+
articleTypeSlugs?: string[];
|
|
5
7
|
/** Contentful custom type for person entries. Default 'people'. */
|
|
6
8
|
peopleCustomType?: string;
|
|
7
9
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveMarkdownParams.d.ts","sourceRoot":"","sources":["../src/resolveMarkdownParams.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,qFAAqF;IACrF,kBAAkB,EAAE,OAAO,CAAC;IAC5B,0BAA0B,EAAE,OAAO,CAAC;IACpC,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,2BAA2B,GACnC;IACE,EAAE,EAAE,IAAI,CAAC;IACT,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,YAAY,GAAG,QAAQ,GAAG,KAAK,CAAC;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"resolveMarkdownParams.d.ts","sourceRoot":"","sources":["../src/resolveMarkdownParams.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,qFAAqF;IACrF,kBAAkB,EAAE,OAAO,CAAC;IAC5B,0BAA0B,EAAE,OAAO,CAAC;IACpC,2FAA2F;IAC3F,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,2BAA2B,GACnC;IACE,EAAE,EAAE,IAAI,CAAC;IACT,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,YAAY,GAAG,QAAQ,GAAG,KAAK,CAAC;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAsE7C,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAAE,EACpB,OAAO,EAAE,oBAAoB,GAC5B,2BAA2B,CAoE7B"}
|
|
@@ -4,6 +4,50 @@ const TAGS_INDEX_NOT_SUPPORTED = 'Tags index page not supported for markdown exp
|
|
|
4
4
|
const ARTICLES_SLUG = 'articles';
|
|
5
5
|
const TAGS_SLUG = 'tags';
|
|
6
6
|
const PEOPLE_SLUG = 'people';
|
|
7
|
+
function articleTypeSegmentCount(slug) {
|
|
8
|
+
return slug.split('/').filter(Boolean).length;
|
|
9
|
+
}
|
|
10
|
+
function isArticleTypeSlugsSortedLongestFirst(slugs) {
|
|
11
|
+
for (let index = 1; index < slugs.length; index++) {
|
|
12
|
+
const previous = slugs[index - 1];
|
|
13
|
+
const current = slugs[index];
|
|
14
|
+
if (!previous || !current) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (articleTypeSegmentCount(previous) < articleTypeSegmentCount(current)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
function assertArticleTypeSlugsSortedInDevelopment(articleTypeSlugs) {
|
|
24
|
+
if (process.env.NODE_ENV !== 'development') {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!isArticleTypeSlugsSortedLongestFirst(articleTypeSlugs)) {
|
|
28
|
+
throw new Error('articleTypeSlugs must be sorted longest-first (e.g. ["resources/news", "resources"])');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function matchArticleTypePrefix(segmentsAfterArticles, articleTypeSlugs) {
|
|
32
|
+
const first = segmentsAfterArticles[0];
|
|
33
|
+
if (!first) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
if (articleTypeSlugs && articleTypeSlugs.length > 0) {
|
|
37
|
+
assertArticleTypeSlugsSortedInDevelopment(articleTypeSlugs);
|
|
38
|
+
for (const candidate of articleTypeSlugs) {
|
|
39
|
+
const parts = candidate.split('/').filter(Boolean);
|
|
40
|
+
if (parts.length === 0) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (parts.every((part, index) => segmentsAfterArticles[index] === part)) {
|
|
44
|
+
return { articleType: candidate, consumed: parts.length };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return { articleType: first, consumed: 1 };
|
|
50
|
+
}
|
|
7
51
|
export function resolveMarkdownParams(slugParams, options) {
|
|
8
52
|
const path = slugParams.join('/');
|
|
9
53
|
const first = slugParams[0];
|
|
@@ -20,25 +64,31 @@ export function resolveMarkdownParams(slugParams, options) {
|
|
|
20
64
|
if (slugParams.length === 1) {
|
|
21
65
|
return { ok: false, status: 404, body: LISTING_NOT_SUPPORTED };
|
|
22
66
|
}
|
|
23
|
-
const
|
|
67
|
+
const segmentsAfterArticles = slugParams.slice(1);
|
|
68
|
+
const match = matchArticleTypePrefix(segmentsAfterArticles, options.articleTypeSlugs);
|
|
69
|
+
if (!match) {
|
|
70
|
+
return { ok: false, status: 404, body: LISTING_NOT_SUPPORTED };
|
|
71
|
+
}
|
|
72
|
+
const { articleType, consumed } = match;
|
|
73
|
+
const afterType = segmentsAfterArticles.slice(consumed);
|
|
24
74
|
if (options.enablePrimaryTagPartOfSlug) {
|
|
25
|
-
if (
|
|
75
|
+
if (afterType.length < 2) {
|
|
26
76
|
return { ok: false, status: 404, body: LISTING_NOT_SUPPORTED };
|
|
27
77
|
}
|
|
28
78
|
return {
|
|
29
79
|
ok: true,
|
|
30
80
|
type: 'article',
|
|
31
|
-
slug:
|
|
81
|
+
slug: afterType.slice(1).join('/'),
|
|
32
82
|
articleType,
|
|
33
83
|
};
|
|
34
84
|
}
|
|
35
|
-
if (
|
|
85
|
+
if (afterType.length < 1) {
|
|
36
86
|
return { ok: true, type: 'articleType', slug: articleType, articleType };
|
|
37
87
|
}
|
|
38
88
|
return {
|
|
39
89
|
ok: true,
|
|
40
90
|
type: 'article',
|
|
41
|
-
slug:
|
|
91
|
+
slug: afterType.join('/'),
|
|
42
92
|
articleType,
|
|
43
93
|
};
|
|
44
94
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveMarkdownParams.js","sourceRoot":"","sources":["../src/resolveMarkdownParams.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resolveMarkdownParams.js","sourceRoot":"","sources":["../src/resolveMarkdownParams.ts"],"names":[],"mappings":"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"}
|
package/docs/llms.md
CHANGED
|
@@ -78,10 +78,18 @@ const links = buildMarkdownLinksFromAppLinks({
|
|
|
78
78
|
import { resolveMarkdownParams } from '@se-studio/markdown-renderer';
|
|
79
79
|
|
|
80
80
|
// In app/api/markdown/[...params]/route.ts:
|
|
81
|
-
export async function GET(
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
export async function GET(_request: Request, { params }: { params: { params: string[] } }) {
|
|
82
|
+
const result = resolveMarkdownParams(params.params, {
|
|
83
|
+
articlesBaseIsPage: false,
|
|
84
|
+
enablePrimaryTagPartOfSlug: true,
|
|
85
|
+
// Required when Contentful article type slugs span multiple segments (longest-first):
|
|
86
|
+
articleTypeSlugs: ['resources/news', 'resources/publications'],
|
|
87
|
+
});
|
|
88
|
+
if (!result.ok) {
|
|
89
|
+
return new Response(result.body, { status: result.status });
|
|
90
|
+
}
|
|
91
|
+
const { type, slug, articleType } = result;
|
|
92
|
+
// Fetch and convert content using type, slug, and articleType
|
|
85
93
|
}
|
|
86
94
|
```
|
|
87
95
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@se-studio/markdown-renderer",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.128",
|
|
4
4
|
"description": "Markdown renderer for Contentful content",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"@contentful/rich-text-types": "^17.2.7",
|
|
31
31
|
"html-entities": "^2.6.0",
|
|
32
32
|
"js-yaml": "^4.1.1",
|
|
33
|
-
"@se-studio/contentful-rest-api": "1.0.
|
|
34
|
-
"@se-studio/core-data-types": "1.0.
|
|
33
|
+
"@se-studio/contentful-rest-api": "1.0.176",
|
|
34
|
+
"@se-studio/core-data-types": "1.0.167"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@biomejs/biome": "^2.4.15",
|