@xyd-js/content 0.1.0-xyd.13 → 0.1.0-xyd.16

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.
Files changed (89) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/ISSUES.md +1 -0
  3. package/TODO.md +2 -0
  4. package/dist/index.d.ts +24 -5
  5. package/dist/index.js +1411 -21776
  6. package/dist/index.js.map +1 -1
  7. package/dist/md.d.ts +62 -7
  8. package/dist/md.js +18071 -15085
  9. package/dist/md.js.map +1 -1
  10. package/dist/{mdToc-CYxzibVZ.d.ts → mdToc-NBBxMJ4l.d.ts} +1 -0
  11. package/dist/vite.d.ts +81 -2
  12. package/dist/vite.js +9716 -10090
  13. package/dist/vite.js.map +1 -1
  14. package/example.txt +0 -0
  15. package/package.json +24 -6
  16. package/packages/md/index.ts +17 -8
  17. package/packages/md/plugins/component-directives/index.ts +3 -0
  18. package/packages/md/plugins/component-directives/mdComponentDirective.ts +524 -0
  19. package/packages/md/plugins/component-directives/types.ts +1 -0
  20. package/packages/md/plugins/component-directives/utils.ts +27 -0
  21. package/packages/md/plugins/composer/__fixtures__/1.single-example/input.md +7 -0
  22. package/packages/md/plugins/composer/__fixtures__/1.single-example/output.json +63 -0
  23. package/packages/md/plugins/composer/__fixtures__/2.single-example-with-name/input.md +7 -0
  24. package/packages/md/plugins/composer/__fixtures__/2.single-example-with-name/output.json +63 -0
  25. package/packages/md/plugins/composer/__fixtures__/3.multiple-examples/input.md +15 -0
  26. package/packages/md/plugins/composer/__fixtures__/3.multiple-examples/output.json +122 -0
  27. package/packages/md/plugins/composer/__fixtures__/4.example-groups/input.md +23 -0
  28. package/packages/md/plugins/composer/__fixtures__/4.example-groups/output.json +184 -0
  29. package/packages/md/plugins/composer/__tests__/mdComposer.test.ts +41 -0
  30. package/packages/md/plugins/composer/__tests__/testHelpers.ts +48 -0
  31. package/packages/md/plugins/composer/index.ts +1 -0
  32. package/packages/md/plugins/composer/mdComposer.ts +146 -0
  33. package/packages/md/plugins/developer-writing/index.ts +3 -0
  34. package/packages/md/plugins/developer-writing/mdCodeRehype.ts +78 -0
  35. package/packages/md/plugins/functions/__fixtures__/external.ts +4 -0
  36. package/packages/md/plugins/functions/__fixtures__/test.js +11 -0
  37. package/packages/md/plugins/functions/__fixtures__/test.py +9 -0
  38. package/packages/md/plugins/functions/__fixtures__/test.ts +18 -0
  39. package/packages/md/plugins/functions/__tests__/mdFunctionImportCode.test.ts +295 -0
  40. package/packages/md/plugins/functions/__tests__/parseFunctionCall.test.ts +47 -0
  41. package/packages/md/plugins/functions/__tests__/testHelpers.ts +71 -0
  42. package/packages/md/plugins/functions/index.ts +11 -0
  43. package/packages/md/plugins/functions/mdFunctionChangelog.ts +124 -0
  44. package/packages/md/plugins/functions/mdFunctionImportCode.ts +83 -0
  45. package/packages/md/plugins/functions/mdFunctionUniform.ts +79 -0
  46. package/packages/md/plugins/functions/types.ts +6 -0
  47. package/packages/md/plugins/functions/uniformProcessor.ts +349 -0
  48. package/packages/md/plugins/functions/utils.ts +423 -0
  49. package/packages/md/plugins/index.ts +56 -11
  50. package/packages/md/plugins/mdCode.ts +52 -4
  51. package/packages/md/plugins/mdHeadingId.ts +47 -0
  52. package/packages/md/plugins/mdPage.ts +3 -0
  53. package/packages/md/plugins/mdThemeSettings.ts +4 -0
  54. package/packages/md/plugins/mdToc.ts +108 -17
  55. package/packages/md/plugins/meta/index.ts +1 -0
  56. package/packages/md/plugins/meta/mdMeta.ts +189 -0
  57. package/packages/md/plugins/output-variables/__fixtures__/1.simple/input.md +22 -0
  58. package/packages/md/plugins/output-variables/__fixtures__/1.simple/output.json +191 -0
  59. package/packages/md/plugins/output-variables/__fixtures__/2.multiple-vars/input.md +21 -0
  60. package/packages/md/plugins/output-variables/__fixtures__/2.multiple-vars/output.json +127 -0
  61. package/packages/md/plugins/output-variables/__tests__/index.test.ts +28 -0
  62. package/packages/md/plugins/output-variables/__tests__/testHelpers.ts +36 -0
  63. package/packages/md/plugins/output-variables/index.ts +1 -0
  64. package/packages/md/plugins/output-variables/lib/const.ts +4 -0
  65. package/packages/md/plugins/output-variables/lib/factoryAttributes.ts +350 -0
  66. package/packages/md/plugins/output-variables/lib/factoryLabel.ts +135 -0
  67. package/packages/md/plugins/output-variables/lib/factoryName.ts +59 -0
  68. package/packages/md/plugins/output-variables/lib/index.ts +21 -0
  69. package/packages/md/plugins/output-variables/lib/outputVarsContainer.ts +328 -0
  70. package/packages/md/plugins/output-variables/lib/util.ts +494 -0
  71. package/packages/md/plugins/output-variables/remarkOutputVars.ts +22 -0
  72. package/packages/md/plugins/rehypeHeading.ts +50 -0
  73. package/packages/md/plugins/types.ts +15 -0
  74. package/packages/md/plugins/utils/componentLike.ts +72 -0
  75. package/packages/md/plugins/utils/index.ts +2 -0
  76. package/packages/md/plugins/utils/mdParameters.test.ts +114 -0
  77. package/packages/md/plugins/utils/mdParameters.ts +249 -0
  78. package/packages/md/plugins/utils/mdastTypes.ts +42 -0
  79. package/packages/md/search/index.ts +251 -0
  80. package/packages/md/search/types.ts +36 -0
  81. package/packages/vite/index.ts +8 -2
  82. package/src/fs.ts +51 -36
  83. package/src/index.ts +4 -4
  84. package/src/navigation.ts +50 -38
  85. package/src/types.ts +8 -0
  86. package/tsconfig.json +31 -8
  87. package/vitest.config.ts +17 -0
  88. package/packages/md/plugins/mdCodeGroup.ts +0 -40
  89. package/packages/md/plugins/mdComponentDirective.ts +0 -141
@@ -0,0 +1,11 @@
1
+ export {
2
+ mdFunctionImportCode
3
+ } from "./mdFunctionImportCode"
4
+
5
+ export {
6
+ mdFunctionUniform
7
+ } from "./mdFunctionUniform"
8
+
9
+ export {
10
+ mdFunctionChangelog
11
+ } from "./mdFunctionChangelog"
@@ -0,0 +1,124 @@
1
+ import { visit } from 'unist-util-visit';
2
+ import { VFile } from 'vfile';
3
+ import { unified } from 'unified';
4
+ import remarkParse from 'remark-parse';
5
+ import remarkMdx from 'remark-mdx';
6
+
7
+ import { FunctionName } from './types';
8
+ import { FunctionOptions, parseFunctionCall, downloadContent } from './utils';
9
+
10
+ interface ChangelogEntry {
11
+ version: string;
12
+ date?: string;
13
+ content: string;
14
+ }
15
+
16
+ export function mdFunctionChangelog() {
17
+ return function (options: FunctionOptions = {}) {
18
+ return async function transformer(tree: any, file: VFile) {
19
+ const promises: Promise<void>[] = [];
20
+
21
+ visit(tree, 'paragraph', (node: any) => {
22
+ const result = parseFunctionCall(node, FunctionName.Changelog);
23
+ if (!result) return;
24
+
25
+ const importPath = result[0];
26
+
27
+ const promise = (async () => {
28
+ try {
29
+ const content = await downloadContent(importPath, file, options.resolveFrom);
30
+ const entries = parseChangelog(content);
31
+
32
+ // Replace the node with the generated content
33
+ node.type = 'mdxJsxFlowElement';
34
+ node.attributes = [];
35
+ node.children = entries.map(entry => {
36
+ // Parse the markdown content
37
+ const parsedContent = unified()
38
+ .use(remarkParse)
39
+ .use(remarkMdx)
40
+ .parse(entry.content);
41
+
42
+ return {
43
+ type: 'mdxJsxFlowElement',
44
+ name: 'Update',
45
+ attributes: [
46
+ {
47
+ type: 'mdxJsxAttribute',
48
+ name: 'version',
49
+ value: entry.version
50
+ },
51
+ {
52
+ type: 'mdxJsxAttribute',
53
+ name: 'date',
54
+ value: entry.date || ''
55
+ }
56
+ ],
57
+ children: parsedContent.children
58
+ };
59
+ });
60
+ } catch (error) {
61
+ console.error(`Error processing changelog: ${importPath}`, error);
62
+ }
63
+ })();
64
+
65
+ promises.push(promise);
66
+ });
67
+
68
+ await Promise.all(promises);
69
+ };
70
+ };
71
+ }
72
+
73
+ function parseChangelog(content: string): ChangelogEntry[] {
74
+ const entries: ChangelogEntry[] = [];
75
+ const lines = content.split('\n');
76
+ let currentEntry: ChangelogEntry | null = null;
77
+ let currentContent: string[] = [];
78
+
79
+ for (let i = 0; i < lines.length; i++) {
80
+ const line = lines[i];
81
+
82
+ // Match different version header formats:
83
+ // 1. ## [X.Y.Z] - any date format
84
+ // 2. ## [X.Y.Z]
85
+ // 3. ## X.Y.Z
86
+ const versionMatch = line.match(/^##\s+(?:\[?([\d.]+)\]?(?:\s*-\s*([^\n]+))?)/);
87
+ if (versionMatch) {
88
+ // Save previous entry if exists
89
+ if (currentEntry) {
90
+ currentEntry.content = currentContent.join('\n').trim();
91
+ entries.push(currentEntry);
92
+ }
93
+
94
+ // Start new entry
95
+ currentEntry = {
96
+ version: versionMatch[1],
97
+ date: versionMatch[2]?.trim() || '',
98
+ content: ''
99
+ };
100
+ currentContent = [];
101
+ continue;
102
+ }
103
+
104
+ // Skip the main title (# xyd-js)
105
+ if (line.startsWith('# ')) {
106
+ continue;
107
+ }
108
+
109
+ // Add content to current entry
110
+ if (currentEntry) {
111
+ currentContent.push(line);
112
+ }
113
+ }
114
+
115
+ // Add last entry
116
+ if (currentEntry) {
117
+ currentEntry.content = currentContent.join('\n').trim();
118
+ entries.push(currentEntry);
119
+ }
120
+
121
+ return entries;
122
+ }
123
+
124
+
@@ -0,0 +1,83 @@
1
+ import { visit } from 'unist-util-visit';
2
+ import { VFile } from 'vfile';
3
+
4
+ import { Settings } from '@xyd-js/core';
5
+
6
+ import { FunctionName } from "./types";
7
+ import {
8
+ FunctionOptions,
9
+ parseFunctionCall,
10
+ parseImportPath,
11
+ processContent,
12
+ detectLanguage,
13
+ readLocalFile,
14
+ fetchFileContent,
15
+ resolvePathAlias
16
+ } from './utils';
17
+
18
+ export function mdFunctionImportCode(settings?: Settings) {
19
+ return function (options: FunctionOptions = {}) {
20
+ return async function transformer(tree: any, file: VFile) {
21
+ // Collect promises for async operations
22
+ const promises: Promise<void>[] = [];
23
+
24
+ console.time('plugin:mdFunctionImportCode');
25
+
26
+ visit(tree, 'paragraph', (node: any) => {
27
+ // Try to parse the function call
28
+ const result = parseFunctionCall(node, FunctionName.ImportCode);
29
+ if (!result) return;
30
+
31
+ const importPath = result[0];
32
+
33
+ // Parse the import path to extract file path, regions, and line ranges
34
+ const { filePath, regions, lineRanges } = parseImportPath(
35
+ resolvePathAlias(importPath, settings, process.cwd()) || importPath
36
+ );
37
+
38
+ // Determine if this is a local or external file
39
+ const isExternal = filePath.startsWith('http://') || filePath.startsWith('https://');
40
+
41
+ // Create a promise for this node
42
+ const promise = (async () => {
43
+ try {
44
+ // Get the file content
45
+ let content: string;
46
+
47
+ if (isExternal) {
48
+ // Fetch external content
49
+ content = await fetchFileContent(filePath);
50
+ } else {
51
+ const baseDir = options.resolveFrom || (file.dirname || process.cwd());
52
+ content = readLocalFile(filePath, baseDir);
53
+ }
54
+
55
+ // Process the content based on regions and line ranges
56
+ let processedContent = processContent(content, regions, lineRanges);
57
+
58
+ // Detect language from file extension
59
+ const language = detectLanguage(filePath);
60
+
61
+ // Replace the paragraph with a code block
62
+ node.type = 'code';
63
+ node.lang = language;
64
+ node.value = processedContent;
65
+ node.children = undefined;
66
+
67
+ } catch (error) {
68
+ console.error(`Error importing file: ${filePath}`, error);
69
+ // Keep the node as is if there's an error
70
+ }
71
+ })();
72
+
73
+ // Add the promise to our collection
74
+ promises.push(promise);
75
+ });
76
+
77
+ // Wait for all promises to resolve
78
+ await Promise.all(promises);
79
+ console.timeEnd('plugin:mdFunctionImportCode');
80
+ };
81
+ }
82
+ }
83
+
@@ -0,0 +1,79 @@
1
+ import { visit } from 'unist-util-visit';
2
+ import { VFile } from 'vfile';
3
+
4
+ import { Settings } from '@xyd-js/core'
5
+ import uniform, { pluginJsonView, Reference, TypeDocReferenceContext } from "@xyd-js/uniform"
6
+
7
+ import { FunctionName } from "./types";
8
+ import {
9
+ FunctionOptions,
10
+ parseFunctionCall,
11
+ } from './utils';
12
+
13
+ // Import the processUniformFunctionCall function
14
+ import { processUniformFunctionCall } from './uniformProcessor';
15
+ import { uniformToMiniUniform } from '@xyd-js/sources/ts';
16
+
17
+ export function mdFunctionUniform(settings?: Settings) {
18
+ return function (options: FunctionOptions = {}) {
19
+ return async function transformer(tree: any, file: VFile) {
20
+ // Collect promises for async operations
21
+ const promises: Promise<void>[] = [];
22
+
23
+ console.time('plugin:mdFunctionUniform');
24
+
25
+ visit(tree, 'paragraph', (node: any) => {
26
+ // Try to parse the function call
27
+ const result = parseFunctionCall(node, FunctionName.Uniform);
28
+ if (!result) return;
29
+
30
+ const importPath = result[0];
31
+ const importArgs = result[1];
32
+
33
+ // Create a promise for this node
34
+ const promise = (async () => {
35
+ try {
36
+ // Process the uniform function call
37
+ let references = await processUniformFunctionCall(
38
+ importPath,
39
+ file,
40
+ options.resolveFrom,
41
+ settings,
42
+ );
43
+
44
+ if (importArgs?.mini && references) { // TODO: move to `processUniformFunctionCall`
45
+ references = uniformToMiniUniform(importArgs.mini, references as Reference<TypeDocReferenceContext>[]);
46
+ }
47
+
48
+ if (references) {
49
+ node.type = 'code';
50
+ node.lang = 'json';
51
+ const jsonViewRefs = uniform(references, {
52
+ plugins: [
53
+ pluginJsonView()
54
+ ]
55
+ })
56
+
57
+ // TODO: support multiple json views
58
+ node.value = jsonViewRefs.out.jsonViews[0]
59
+ node.children = undefined;
60
+ }
61
+ } catch (error) {
62
+ console.error(`Error processing uniform function call: ${importPath}`, error);
63
+ // Keep the node as is if there's an error
64
+ }
65
+ })();
66
+
67
+ // Add the promise to our collection
68
+ promises.push(promise);
69
+ });
70
+
71
+ // Wait for all promises to resolve
72
+ await Promise.all(promises);
73
+ console.timeEnd('plugin:mdFunctionUniform');
74
+ };
75
+ }
76
+
77
+ }
78
+
79
+
@@ -0,0 +1,6 @@
1
+ export enum FunctionName {
2
+ ImportCode = '@importCode',
3
+ Import = '@import',
4
+ Uniform = '@uniform',
5
+ Changelog = '@changelog',
6
+ }
@@ -0,0 +1,349 @@
1
+ import * as path from 'node:path';
2
+ import * as fs from 'node:fs';
3
+ import * as os from 'node:os';
4
+ import { VFile } from 'vfile';
5
+
6
+ import { Metadata, Settings } from '@xyd-js/core';
7
+ import { sourcesToUniform, sourcesToUniformV2, type TypeDocReferenceContext } from '@xyd-js/sources/ts';
8
+ import { reactDocgenToUniform, uniformToReactUniform } from '@xyd-js/sources/react';
9
+ import { gqlSchemaToReferences } from "@xyd-js/gql"
10
+ import {oapSchemaToReferences, deferencedOpenAPI, uniformPluginXDocsSidebar} from "@xyd-js/openapi"
11
+
12
+ import { downloadContent, LineRange, parseImportPath, Region, resolvePathAlias } from './utils';
13
+ import uniform, { Reference, ReferenceContext } from '@xyd-js/uniform';
14
+ // TODO: rewrite to async
15
+
16
+ /**
17
+ * Process a uniform function call and return the references
18
+ *
19
+ * @param settings The settings object
20
+ * @param value The value containing the uniform function call
21
+ * @param file The VFile object
22
+ * @param resolveFrom Optional base directory to resolve relative paths from
23
+ * @returns A promise that resolves to the references or null if processing failed
24
+ */
25
+ export async function processUniformFunctionCall(
26
+ value: string,
27
+ file: VFile,
28
+ resolveFrom?: string,
29
+ settings?: Settings,
30
+ ): Promise<Reference[] | null> {
31
+ // Parse the import path to extract file path
32
+ const { filePath, regions, lineRanges } = parseImportPath(value);
33
+
34
+ // Resolve path aliases and get the base directory
35
+ let resolvedFilePath = resolvePathAlias(filePath, settings, process.cwd());
36
+
37
+ if (resolvedFilePath.startsWith("~/")) {
38
+ resolvedFilePath = path.join(process.cwd(), resolvedFilePath.slice(2));
39
+ }
40
+
41
+ // Process the uniform file
42
+ const references = await processUniformFile(resolvedFilePath, regions, lineRanges, file, resolveFrom);
43
+
44
+ if (!references) {
45
+ return null
46
+ }
47
+
48
+ const plugins = globalThis.__xydUserUniformVitePlugins || []
49
+ const matter = file.data?.matter as Metadata
50
+ if (matter?.openapi) {
51
+ plugins.push(uniformPluginXDocsSidebar)
52
+ }
53
+
54
+ const uniformRefs = uniform(references, {
55
+ plugins: [
56
+ ...plugins,
57
+ ]
58
+ })
59
+
60
+ return uniformRefs.references
61
+ }
62
+
63
+ async function processUniformFile(
64
+ filePath: string,
65
+ regions: Region[],
66
+ lineRanges: LineRange[],
67
+ file: VFile,
68
+ resolveFrom?: string
69
+ ): Promise<any[] | null> {
70
+ try {
71
+ if (!isSupportedProgrammingSource(filePath)) {
72
+ // TODO: openapi + graphql
73
+ throw new Error(`Unsupported file type: ${filePath}`);
74
+ }
75
+
76
+ let ext = extension(filePath);
77
+
78
+ const matter = file.data?.matter as Metadata
79
+ if (matter?.openapi) {
80
+ ext = "openapi"
81
+ }
82
+
83
+ if (isLocalPath(filePath)) {
84
+ const baseDir = resolveFrom || (file.dirname || process.cwd());
85
+ const resolvedFilePath = path.resolve(baseDir, filePath);
86
+
87
+ switch (ext) {
88
+ case 'ts':
89
+ case 'tsx': {
90
+ const packageDir = findClosestPackageJsonDir(
91
+ baseDir,
92
+ filePath,
93
+ );
94
+
95
+ if (packageDir) {
96
+ // Extract the relative file path from the package directory
97
+ const relativeFilePath = path.relative(packageDir, resolvedFilePath);
98
+
99
+ try {
100
+ let references: Reference[] = []
101
+
102
+ switch (ext) {
103
+ case 'ts': {
104
+ const typedocRefs = await sourcesToUniformV2(
105
+ packageDir,
106
+ [relativeFilePath]
107
+ )
108
+
109
+ if (!typedocRefs || !typedocRefs.references) {
110
+ console.error("Failed to process uniform file", filePath)
111
+ break
112
+ }
113
+
114
+ references = typedocRefs.references.filter(ref => {
115
+ const ctx = ref?.context as TypeDocReferenceContext
116
+
117
+ const pathMatch = ctx?.fileFullPath === relativeFilePath
118
+
119
+
120
+ if (regions.length > 0) {
121
+ const regionMatch = regions.some(region => {
122
+ return region.name === ctx?.symbolName // TODO: BETTER REGION API FOR TYPEDOC
123
+ })
124
+
125
+ return pathMatch && regionMatch
126
+ }
127
+
128
+ return pathMatch
129
+ })
130
+
131
+ break
132
+ }
133
+
134
+ case 'tsx': {
135
+ const resp = await sourcesToUniformV2(
136
+ packageDir,
137
+ [relativeFilePath]
138
+ )
139
+
140
+ if (!resp || !resp.references || !resp.projectJson) {
141
+ console.error("Failed to process uniform file", filePath)
142
+ return null
143
+ }
144
+ const typedocRefs = resp.references as Reference<TypeDocReferenceContext>[]
145
+
146
+ references = uniformToReactUniform(typedocRefs, resp.projectJson)
147
+
148
+ break
149
+ }
150
+ }
151
+
152
+ return references
153
+ } finally {
154
+ // Clean up the temporary directory when done
155
+ // cleanupTempFolder(tempDir);
156
+ }
157
+ } else {
158
+ console.error("package.json not found", filePath)
159
+ }
160
+ }
161
+
162
+ case 'graphql': {
163
+ const references = await gqlSchemaToReferences(resolvedFilePath, {
164
+ regions: regions.map(region => region.name),
165
+ });
166
+
167
+ return references;
168
+ }
169
+
170
+ case 'openapi': {
171
+ const schema = await deferencedOpenAPI(resolvedFilePath);
172
+ const references = oapSchemaToReferences(schema, {
173
+ regions: regions.map(region => region.name)
174
+ });
175
+
176
+ return references;
177
+ }
178
+
179
+ default: {
180
+ throw new Error(`Unsupported file extension: ${ext}`);
181
+ }
182
+ }
183
+
184
+ }
185
+
186
+ throw new Error("current implementation does not support remote files")
187
+
188
+ // For remote files, download the content
189
+ const content = await downloadContent(
190
+ filePath,
191
+ file,
192
+ resolveFrom,
193
+ );
194
+
195
+ // Fallback to creating temporary folder structure if no package.json found
196
+ const tempDir = await createTempFolderStructure(content);
197
+
198
+ try {
199
+ // Get the path to the package directory
200
+ const tempPackageDir = path.join(tempDir, 'packages', 'package');
201
+
202
+ // Process the content using sourcesToUniform
203
+ const references = await sourcesToUniformV2(
204
+ tempDir,
205
+ [tempPackageDir]
206
+ );
207
+
208
+ return references || null;
209
+ } finally {
210
+ // Clean up the temporary directory when done
211
+ cleanupTempFolder(tempDir);
212
+ }
213
+
214
+ } catch (error) {
215
+ console.error(`Error processing uniform file: ${filePath}`, error);
216
+ return null;
217
+ }
218
+ }
219
+
220
+
221
+ /**
222
+ * Creates a temporary folder structure with package.json, tsconfig.json, and src/index.ts
223
+ * @param content The content to be placed in src/index.ts
224
+ * @returns The path to the temporary directory
225
+ */
226
+ async function createTempFolderStructure(content: string): Promise<string> {
227
+ // Create a temporary directory
228
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'xyd-uniform-'));
229
+
230
+ // Create the package directory
231
+ const packageDir = path.join(tempDir, 'packages', 'package');
232
+ fs.mkdirSync(packageDir, { recursive: true });
233
+
234
+ // Create the src directory
235
+ const srcDir = path.join(packageDir, 'src');
236
+ fs.mkdirSync(srcDir, { recursive: true });
237
+
238
+ // Create package.json
239
+ const packageJson = {
240
+ "name": "@xyd-sources-examples/package-a",
241
+ "main": "dist/index.js"
242
+ };
243
+ fs.writeFileSync(
244
+ path.join(packageDir, 'package.json'),
245
+ JSON.stringify(packageJson, null, 2)
246
+ );
247
+
248
+ // Create tsconfig.json
249
+ const tsconfigJson = {
250
+ "compilerOptions": {
251
+ "outDir": "./dist"
252
+ }
253
+ };
254
+ fs.writeFileSync(
255
+ path.join(packageDir, 'tsconfig.json'),
256
+ JSON.stringify(tsconfigJson, null, 2)
257
+ );
258
+
259
+ // Create src/index.ts with the provided content
260
+ fs.writeFileSync(path.join(srcDir, 'index.ts'), content);
261
+
262
+ return tempDir;
263
+ }
264
+
265
+ /**
266
+ * Cleans up the temporary folder structure
267
+ * @param tempDir The path to the temporary directory
268
+ */
269
+ function cleanupTempFolder(tempDir: string): void {
270
+ try {
271
+ // Recursively delete the temporary directory
272
+ fs.rmSync(tempDir, { recursive: true, force: true });
273
+ } catch (error) {
274
+ console.error(`Error cleaning up temporary directory: ${tempDir}`, error);
275
+ }
276
+ }
277
+
278
+ const supportedProgrammingExtensions: Record<string, boolean> = {
279
+ 'ts': true,
280
+ 'tsx': true,
281
+ 'graphql': true,
282
+ 'yaml': true,
283
+ 'yml': true,
284
+ 'json': true,
285
+
286
+ // TODO
287
+ // 'py': true,
288
+ // 'go': true,
289
+ // TODO: AND OTHER PROGRAMMING LANGUAGES IN THE FUTEURE
290
+ }
291
+
292
+ /**
293
+ * Check if a file is a programming source file based on its extension
294
+ * @param filePath The path to the file
295
+ * @returns True if the file is a programming source file
296
+ */
297
+ function isSupportedProgrammingSource(filePath: string) {
298
+ const ext = extension(filePath);
299
+
300
+ if (supportedProgrammingExtensions[ext]) {
301
+ return true;
302
+ }
303
+
304
+ return false;
305
+ }
306
+
307
+ function extension(filePath: string) {
308
+ return path.extname(filePath).toLowerCase().replace('.', '');
309
+ }
310
+
311
+ /**
312
+ * Find the closest package.json directory for a given file path
313
+ * @param baseDir The base directory to start searching from (used as cwd for resolving relative paths)
314
+ * @param filePath The path to the file (can be relative)
315
+ * @returns The path to the directory containing package.json, or null if not found
316
+ */
317
+ function findClosestPackageJsonDir(
318
+ baseDir: string,
319
+ filePath: string
320
+ ): string | null {
321
+ // Resolve the filePath relative to baseDir
322
+ const resolvedFilePath = path.resolve(baseDir, filePath);
323
+ let currentDir = path.dirname(resolvedFilePath);
324
+ const root = path.parse(currentDir).root;
325
+
326
+ while (currentDir !== root) {
327
+ try {
328
+ const files = fs.readdirSync(currentDir);
329
+ if (files.includes('package.json')) {
330
+ return currentDir;
331
+ }
332
+ } catch (error) {
333
+ // If we can't read the directory, move up
334
+ console.warn(`Cannot read directory ${currentDir}:`, error);
335
+ }
336
+ currentDir = path.dirname(currentDir);
337
+ }
338
+
339
+ return null;
340
+ }
341
+
342
+ /**
343
+ * Check if a path is a local file path (not a URL)
344
+ * @param filePath The path to check
345
+ * @returns True if the path is local
346
+ */
347
+ function isLocalPath(filePath: string): boolean {
348
+ return !filePath.startsWith('http://') && !filePath.startsWith('https://');
349
+ }