@xyd-js/uniform 0.1.0-xyd.4 → 0.1.0-xyd.56

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.
@@ -1,3 +1,4 @@
1
+ import { fromMarkdown } from "mdast-util-from-markdown";
1
2
  import {u} from "unist-builder";
2
3
 
3
4
  import {
@@ -41,13 +42,12 @@ export function heading(
41
42
  let uDesc = [
42
43
  u(
43
44
  'heading',
44
- {depth: START_DEPTH_LEVEL},
45
+ {depth: uTitle.depth + 1},
45
46
  [u('text', `!description`),]
46
47
  ),
47
48
  u('paragraph', [u('text', description)])
48
49
  ]
49
50
 
50
-
51
51
  let uRefCategory
52
52
  if (refCategory) {
53
53
  uRefCategory = u(
@@ -79,12 +79,24 @@ export function heading(
79
79
 
80
80
 
81
81
  for (const [key, value] of Object.entries(refContext)) {
82
- uContext.push(u(
83
- 'heading',
84
- {depth: uContext[0].depth + 1},
85
- [u('text', `!${key} ${value}`)]
86
- )
87
- )
82
+ if (typeof value === "object") {
83
+ // TODO: support ```<lang> ??
84
+ if (value.code) {
85
+ uContext.push(
86
+ u('heading', {depth: uContext[0].depth + 1}, [u('text', `!${key}`)])
87
+ );
88
+
89
+ uContext.push(
90
+ u('code', {lang: value.lang}, value.code)
91
+ );
92
+
93
+ continue;
94
+ }
95
+ }
96
+
97
+ uContext.push(
98
+ u('heading', {depth: uContext[0].depth + 1}, [u('text', `!${key} ${value.toString()}`)])
99
+ );
88
100
  }
89
101
  }
90
102
 
@@ -191,6 +203,7 @@ export function definitions(definitions: Definition[]) {
191
203
  name: prop.name,
192
204
  type: prop.type,
193
205
  description: prop.description,
206
+ context: prop.context,
194
207
  properties: prop.properties // TODO: fix ts
195
208
  },
196
209
  md,
@@ -213,13 +226,35 @@ export function properties(
213
226
  const uPropTitle = u('heading', {depth}, [u('text', propTitle)]);
214
227
  const uPropName = u('paragraph', {depth}, [u('text', `!name ${paramName}`)]);
215
228
  const uPropType = u('paragraph', {depth}, [u('text', `!type ${props.type}`)]);
216
- const uPropDesc = u('paragraph', {depth}, [u('text', props.description || '')]);
229
+ const markdownAst = fromMarkdown(props.description || '');
230
+ const uPropDesc = u("paragraph", { depth }, markdownAst.children);
231
+ const uContext = []
232
+
233
+ if (props.context && Object.keys(props.context)) {
234
+ uContext.push(u(
235
+ 'heading',
236
+ {depth: depth + 1},
237
+ [
238
+ u('text', `!context`),
239
+ ]
240
+ ))
241
+
242
+ for (const [key, value] of Object.entries(props.context)) {
243
+ uContext.push(u(
244
+ 'heading',
245
+ {depth: uContext[0].depth + 1},
246
+ [u('text', `!${key} ${value}`)]
247
+ )
248
+ )
249
+ }
250
+ }
217
251
 
218
252
  output.push(
219
253
  uPropTitle,
220
254
  uPropName,
221
255
  uPropType,
222
- uPropDesc
256
+ uPropDesc,
257
+ ...uContext
223
258
  );
224
259
 
225
260
  if (props.properties) {
@@ -0,0 +1,132 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import fs from 'fs';
3
+ import { pluginJsonView } from '../pluginJsonView';
4
+ import type { Reference } from '../../types';
5
+ import uniform from '../../index'
6
+
7
+ describe('pluginJsonView', () => {
8
+ it('should handle properties without examples', () => {
9
+ const plugin = pluginJsonView();
10
+
11
+ const inputs: Reference[] = [
12
+ {
13
+ title: 'Test title',
14
+ description: 'Test description',
15
+ canonical: 'test-canonical',
16
+ examples: {
17
+ groups: []
18
+ },
19
+ "definitions": [
20
+ {
21
+ "title": "Properties",
22
+ "properties": [
23
+ {
24
+ "name": "charset",
25
+ "type": "string",
26
+ "description": "Character encoding for the document\n",
27
+ "examples": [
28
+ "\"UTF-8\""
29
+ ]
30
+ },
31
+ {
32
+ "name": "robots",
33
+ "type": "string",
34
+ "description": "Standard meta tag for controlling search engine crawling and indexing\n",
35
+ "examples": [
36
+ "\"index, follow\"",
37
+ "\"noindex, nofollow\""
38
+ ]
39
+ }
40
+ ]
41
+ }
42
+ ]
43
+ },
44
+ {
45
+ title: 'Test title',
46
+ description: 'Test description',
47
+ canonical: 'test-canonical',
48
+ examples: {
49
+ groups: []
50
+ },
51
+ "definitions": [
52
+ {
53
+ "title": "Properties",
54
+ "properties": [
55
+ {
56
+ "name": "charset",
57
+ "type": "string",
58
+ "description": "Character encoding for the document\n",
59
+ "examples": [
60
+ "UTF-8"
61
+ ]
62
+ },
63
+ {
64
+ "name": "robots",
65
+ "type": "string",
66
+ "description": "Standard meta tag for controlling search engine crawling and indexing\n",
67
+ "examples": [
68
+ "index, follow",
69
+ "noindex, nofollow"
70
+ ]
71
+ }
72
+ ]
73
+ }
74
+ ]
75
+ },
76
+ {
77
+ title: 'Test title',
78
+ description: 'Test description',
79
+ canonical: 'test-canonical',
80
+ examples: {
81
+ groups: []
82
+ },
83
+ "definitions": [
84
+ {
85
+ "title": "Properties",
86
+ "properties": [
87
+ {
88
+ "name": "robots",
89
+ "type": "string",
90
+ "description": "Standard meta tag for controlling search engine crawling and indexing\n",
91
+ "examples": [
92
+ "index, follow",
93
+ "noindex, nofollow"
94
+ ]
95
+ },
96
+ {
97
+ "name": "charset",
98
+ "type": "string",
99
+ "description": "Character encoding for the document\n",
100
+ "examples": [
101
+ "UTF-8"
102
+ ]
103
+ },
104
+ ]
105
+ }
106
+ ]
107
+ }
108
+ ];
109
+
110
+ const outputs: string[] = [
111
+ '{\n' +
112
+ ' "charset": "UTF-8",\n' +
113
+ ' "robots": "index, follow" // or "noindex, nofollow"\n' +
114
+ '}',
115
+
116
+ '{\n' +
117
+ ' "charset": "UTF-8",\n' +
118
+ ' "robots": "index, follow" // or "noindex, nofollow"\n' +
119
+ '}',
120
+
121
+ '{\n' +
122
+ ' "robots": "index, follow", // or "noindex, nofollow"\n' +
123
+ ' "charset": "UTF-8"\n' +
124
+ '}',
125
+ ]
126
+ const result = uniform(inputs, {
127
+ plugins: [plugin]
128
+ });
129
+
130
+ expect(result.out.jsonViews).toStrictEqual(outputs);
131
+ });
132
+ });
@@ -0,0 +1,2 @@
1
+ export { pluginJsonView } from "./pluginJsonView"
2
+ export { pluginNavigation } from "./pluginNavigation"
@@ -0,0 +1,54 @@
1
+ import type { UniformPluginArgs, UniformPlugin } from "../index";
2
+ import { Reference } from "../types";
3
+
4
+ export interface pluginJsonViewOptions {
5
+ }
6
+
7
+ type pluginJsonViewOutput = {
8
+ jsonViews: string;
9
+ }
10
+
11
+ export function pluginJsonView(
12
+ options?: pluginJsonViewOptions
13
+ ): UniformPlugin<pluginJsonViewOutput> {
14
+
15
+ return function pluginJsonViewInner({
16
+ defer,
17
+ }: UniformPluginArgs) {
18
+ const jsonViews: string[] = [];
19
+
20
+ defer(() => ({
21
+ jsonViews
22
+ }))
23
+
24
+ return (ref: Reference) => {
25
+ // Build the output string manually to ensure exact format
26
+ const lines: string[] = [];
27
+ lines.push('{');
28
+
29
+ ref.definitions.forEach(def => {
30
+ def.properties.forEach((prop, index) => {
31
+ // Remove any quotes and trailing characters from the value
32
+ const value = (prop.examples?.[0] || '').replace(/^"|"$|[^a-zA-Z0-9\s\-_.,:/@#=;+()]/g, '');
33
+ const comment = prop.examples && prop.examples.length > 1
34
+ ? ` // or "${(prop.examples as string[])[1].replace(/^"|"$|[^a-zA-Z0-9\s\-_.,:/@#=;+()]/g, '')}"`
35
+ : '';
36
+ const isLast = index === def.properties.length - 1;
37
+ // Add comma after the value but before the comment
38
+ lines.push(` "${prop.name}": "${value}"${isLast ? '' : ','}${comment}`);
39
+ });
40
+ });
41
+
42
+ lines.push('}');
43
+
44
+ jsonViews.push(lines.join('\n'));
45
+ }
46
+ }
47
+ }
48
+
49
+ // example usage:
50
+ // const response = uniform([/* references */], {
51
+ // plugins: [pluginJsonView({
52
+ //
53
+ // })],
54
+ // });
@@ -0,0 +1,135 @@
1
+ import path from 'node:path';
2
+
3
+ import type { Sidebar, Metadata, MetadataMap, Settings, PageURL } from "@xyd-js/core";
4
+
5
+ import type { UniformPluginArgs, UniformPlugin } from "../index";
6
+ import { CodeBlockTab, Example, ExampleGroup, Reference } from "../types";
7
+
8
+ const DEFAULT_VIRTUAL_FOLDER = ".xyd/.cache/.content" // TODO: share this + .xyd/.build/.content for build
9
+
10
+ const DEFAULT_GROUP_NAME = "API Reference" // TODO: configurable
11
+
12
+ type GroupMap = {
13
+ [key: string]: {
14
+ __groups: GroupMap
15
+ pages: Set<string>
16
+ }
17
+ }
18
+
19
+ export interface pluginNavigationOptions {
20
+ urlPrefix: string
21
+ defaultGroup?: string
22
+ }
23
+
24
+ type pluginNavigationOutput = {
25
+ pageFrontMatter: MetadataMap;
26
+ sidebar: Sidebar[];
27
+ }
28
+
29
+ export function pluginNavigation(
30
+ settings: Settings,
31
+ options: pluginNavigationOptions
32
+ ): UniformPlugin<pluginNavigationOutput> {
33
+ if (!options.urlPrefix) {
34
+ throw new Error("urlPrefix is required")
35
+ }
36
+
37
+ return function pluginNavigationInner({
38
+ defer,
39
+ }: UniformPluginArgs) {
40
+ const pageFrontMatter: MetadataMap = {}
41
+ const groupMaps: GroupMap = {}
42
+
43
+ defer(() => ({
44
+ pageFrontMatter,
45
+ sidebar: convertGroupMapsToSidebar(settings, groupMaps) as Sidebar[]
46
+ }))
47
+
48
+ return (ref: Reference) => {
49
+ const dataCtx = ref.context
50
+ const pagePath = path.join(options.urlPrefix, ref.canonical)
51
+
52
+ let group = dataCtx?.group || []
53
+ let title = ref.title
54
+
55
+ if (pageFrontMatter[pagePath]) {
56
+ console.error("(pluginNavigation): pageFrontMatter[pagePath] already exists", pagePath)
57
+ }
58
+
59
+ if (!group) {
60
+ group = [options.defaultGroup || DEFAULT_GROUP_NAME]
61
+ }
62
+
63
+ pageFrontMatter[pagePath] = {
64
+ title,
65
+ }
66
+
67
+ if (typeof group === "string") {
68
+ // TODO: seek nested group (it's not always from 0)
69
+ throw new Error("group as string is not supported yet")
70
+ }
71
+
72
+ group.reduce((groups: GroupMap, groupName: string, i: number) => {
73
+ if (!groups[groupName]) {
74
+ groups[groupName] = {
75
+ __groups: {},
76
+ pages: new Set()
77
+ }
78
+ }
79
+
80
+ if (i === group.length - 1) {
81
+ groups[groupName].pages.add(pagePath)
82
+ }
83
+
84
+ return groups[groupName].__groups
85
+ }, groupMaps)
86
+ }
87
+ }
88
+ }
89
+
90
+ function convertGroupMapsToSidebar(settings: Settings, groupMaps: GroupMap): Sidebar[] {
91
+ const nav: Sidebar[] = []
92
+
93
+ Object.keys(groupMaps).map((groupName) => {
94
+ const current = groupMaps[groupName]
95
+
96
+ const pages: PageURL[] = []
97
+
98
+ current.pages.forEach((page: string) => {
99
+ if (settings?.engine?.uniform?.store) {
100
+ pages.push(page)
101
+ return
102
+ }
103
+ pages.push({
104
+ virtual: path.join(DEFAULT_VIRTUAL_FOLDER, page),
105
+ page: page,
106
+ })
107
+ })
108
+
109
+ if (Object.keys(current.__groups).length) {
110
+ const subNav: Sidebar = {
111
+ group: groupName,
112
+ pages: convertGroupMapsToSidebar(settings, current.__groups)
113
+ }
114
+
115
+ nav.push(subNav)
116
+
117
+ return
118
+ }
119
+
120
+ nav.push({
121
+ group: groupName,
122
+ pages,
123
+ })
124
+ })
125
+
126
+ return nav
127
+ }
128
+
129
+ // TODO: in the future xyd settings must be removed cuz uniform will be part of opendocs
130
+ // example usage:
131
+ // const response = uniform([/* references */], {
132
+ // plugins: [pluginNavigation({}, {
133
+ // urlPrefix: "/docs"
134
+ // })],
135
+ // });