@openinc/parse-server-opendash 3.19.2 → 3.20.1

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 (61) hide show
  1. package/dist/featuremap.json +1 -0
  2. package/dist/features/config/helper/isFeatureEnabled.d.ts +2 -1
  3. package/dist/features/documentation/config/defaults.d.ts +39 -0
  4. package/dist/features/documentation/config/defaults.js +142 -0
  5. package/dist/features/documentation/config/index.d.ts +1 -0
  6. package/dist/features/documentation/config/index.js +17 -0
  7. package/dist/features/documentation/core/Cleanup.d.ts +30 -0
  8. package/dist/features/documentation/core/Cleanup.js +134 -0
  9. package/dist/features/documentation/core/Converter.d.ts +9 -0
  10. package/dist/features/documentation/core/Converter.js +65 -0
  11. package/dist/features/documentation/core/Importer.d.ts +21 -0
  12. package/dist/features/documentation/core/Importer.js +133 -0
  13. package/dist/features/documentation/core/Organizer.d.ts +11 -0
  14. package/dist/features/documentation/core/Organizer.js +52 -0
  15. package/dist/features/documentation/core/index.d.ts +4 -0
  16. package/dist/features/documentation/core/index.js +20 -0
  17. package/dist/features/documentation/functions/importDocs.d.ts +2 -0
  18. package/dist/features/documentation/functions/importDocs.js +40 -0
  19. package/dist/features/documentation/index.d.ts +8 -0
  20. package/dist/features/documentation/index.js +34 -0
  21. package/dist/features/documentation/services/ConfigApplier.d.ts +11 -0
  22. package/dist/features/documentation/services/ConfigApplier.js +110 -0
  23. package/dist/features/documentation/services/ContentLoader.d.ts +6 -0
  24. package/dist/features/documentation/services/ContentLoader.js +40 -0
  25. package/dist/features/documentation/services/FeatureFilter.d.ts +34 -0
  26. package/dist/features/documentation/services/FeatureFilter.js +154 -0
  27. package/dist/features/documentation/services/GitHubClient.d.ts +43 -0
  28. package/dist/features/documentation/services/GitHubClient.js +140 -0
  29. package/dist/features/documentation/services/MetadataEnricher.d.ts +5 -0
  30. package/dist/features/documentation/services/MetadataEnricher.js +29 -0
  31. package/dist/features/documentation/services/StructureBuilder.d.ts +7 -0
  32. package/dist/features/documentation/services/StructureBuilder.js +43 -0
  33. package/dist/features/documentation/services/TreeNormalizer.d.ts +10 -0
  34. package/dist/features/documentation/services/TreeNormalizer.js +73 -0
  35. package/dist/features/documentation/services/index.d.ts +7 -0
  36. package/dist/features/documentation/services/index.js +23 -0
  37. package/dist/features/documentation/types/GitHubTypes.d.ts +25 -0
  38. package/dist/features/documentation/types/GitHubTypes.js +2 -0
  39. package/dist/features/documentation/types/StructureTypes.d.ts +114 -0
  40. package/dist/features/documentation/types/StructureTypes.js +2 -0
  41. package/dist/features/documentation/types/index.d.ts +2 -0
  42. package/dist/features/documentation/types/index.js +18 -0
  43. package/dist/functions/openinc-documentation-import-docs.d.ts +1 -0
  44. package/dist/functions/openinc-documentation-import-docs.js +23 -0
  45. package/dist/hooks/Documentation_Config.d.ts +1 -0
  46. package/dist/hooks/Documentation_Config.js +17 -0
  47. package/dist/hooks/Tenant.js +3 -0
  48. package/dist/hooks/_Role.js +3 -3
  49. package/dist/index.js +12 -0
  50. package/dist/types/Documentation_Category.d.ts +6 -0
  51. package/dist/types/Documentation_Category.js +12 -0
  52. package/dist/types/Documentation_Config.d.ts +21 -0
  53. package/dist/types/Documentation_Config.js +29 -0
  54. package/dist/types/Documentation_Document.d.ts +6 -0
  55. package/dist/types/Documentation_Document.js +12 -0
  56. package/dist/types/index.d.ts +2 -0
  57. package/dist/types/index.js +5 -3
  58. package/package.json +3 -1
  59. package/schema/Documentation_Category.json +9 -0
  60. package/schema/Documentation_Config.json +50 -0
  61. package/schema/Documentation_Document.json +9 -0
@@ -18,6 +18,7 @@
18
18
  "OD3_Dashboard": "MONITORING",
19
19
  "OD3_Documentation_Category": "DOCUMENTATION",
20
20
  "OD3_Documentation_Document": "DOCUMENTATION",
21
+ "OD3_Documentation_Config": "DOCUMENTATION",
21
22
  "OD3_GTFS_Agency": "GTFS",
22
23
  "OD3_GTFS_Bikes_Allowed": "GTFS",
23
24
  "OD3_GTFS_Calendar": "GTFS",
@@ -1 +1,2 @@
1
- export declare function isFeatureEnabled(feature: string): boolean;
1
+ export type Feature = "CORE" | "MONITORING" | "BDE" | "GTFS" | "KNOWLEDGE" | "MAINTENANCE" | "DOCUMENTATION" | "MIAAS";
2
+ export declare function isFeatureEnabled(feature: Feature): boolean;
@@ -0,0 +1,39 @@
1
+ import { FileConfig, FolderConfig, ImportOptions } from "../types";
2
+ export declare const FOLDER_CONFIG_ALLOWED_KEYS: readonly ["title", "order", "icon", "files", "feature"];
3
+ export type FolderConfigAllowedKey = (typeof FOLDER_CONFIG_ALLOWED_KEYS)[number];
4
+ export declare const FILE_CONFIG_ALLOWED_KEYS: readonly ["order", "icon", "title", "locationPattern", "locations", "feature"];
5
+ export type FileConfigAllowedKey = (typeof FILE_CONFIG_ALLOWED_KEYS)[number];
6
+ /**
7
+ * Default configuration for documentation import
8
+ */
9
+ export declare const DEFAULT_IMPORT_CONFIG: Partial<ImportOptions>;
10
+ export declare const DEFAULT_FILE_CONFIG: Required<Pick<FileConfig, "order" | "icon">>;
11
+ /**
12
+ * Preset configurations for different use cases
13
+ */
14
+ export declare const IMPORT_PRESETS: {
15
+ DOCS_AND_CONFIG: {
16
+ includeExtensions: string[];
17
+ defaultFolderConfig: {
18
+ order: number;
19
+ icon: string;
20
+ };
21
+ };
22
+ MEDIA_ONLY: {
23
+ includeExtensions: string[];
24
+ defaultFolderConfig: {
25
+ template: string;
26
+ tags: string[];
27
+ };
28
+ };
29
+ };
30
+ /**
31
+ * Helper function to merge configuration
32
+ */
33
+ export declare function createImportConfig(overrides?: Partial<ImportOptions>, preset?: keyof typeof IMPORT_PRESETS): ImportOptions;
34
+ /**
35
+ * Sanitize a raw (parsed) folder config object by picking only allowed keys
36
+ * and recursively sanitizing file configs.
37
+ */
38
+ export declare function sanitizeFolderConfig(raw: any): FolderConfig;
39
+ export declare function sanitizeFileConfig(raw: any): FileConfig;
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IMPORT_PRESETS = exports.DEFAULT_FILE_CONFIG = exports.DEFAULT_IMPORT_CONFIG = exports.FILE_CONFIG_ALLOWED_KEYS = exports.FOLDER_CONFIG_ALLOWED_KEYS = void 0;
4
+ exports.createImportConfig = createImportConfig;
5
+ exports.sanitizeFolderConfig = sanitizeFolderConfig;
6
+ exports.sanitizeFileConfig = sanitizeFileConfig;
7
+ // ---------------------------------------------------------------------------
8
+ // Allowed Config Keys (central source of truth)
9
+ // ---------------------------------------------------------------------------
10
+ exports.FOLDER_CONFIG_ALLOWED_KEYS = [
11
+ "title",
12
+ "order",
13
+ "icon",
14
+ "files",
15
+ "feature",
16
+ ];
17
+ exports.FILE_CONFIG_ALLOWED_KEYS = [
18
+ "order",
19
+ "icon",
20
+ "title",
21
+ "locationPattern",
22
+ "locations",
23
+ "feature",
24
+ ];
25
+ /**
26
+ * Default configuration for documentation import
27
+ */
28
+ exports.DEFAULT_IMPORT_CONFIG = {
29
+ organization: "open-inc",
30
+ repository: "documentation",
31
+ branch: process.env.OI_DOCUMENTATION_GITHUB_BRANCH || "main",
32
+ rootPath: "docs", // Start from the docs folder
33
+ fileFilter: {
34
+ // Only include markdown and JSON files by default
35
+ includeExtensions: ["md", "json"],
36
+ // Exclude common non-documentation files
37
+ excludeExtensions: [],
38
+ // Path patterns (examples)
39
+ // includePaths: ["docs/**", "*.md"],
40
+ // excludePaths: ["node_modules/**", ".git/**", "**/.DS_Store"],
41
+ },
42
+ defaultFolderConfig: {
43
+ order: 999,
44
+ },
45
+ };
46
+ exports.DEFAULT_FILE_CONFIG = {
47
+ order: 999,
48
+ icon: "fa:file",
49
+ };
50
+ /**
51
+ * Preset configurations for different use cases
52
+ */
53
+ exports.IMPORT_PRESETS = {
54
+ // Documentation + configuration
55
+ DOCS_AND_CONFIG: {
56
+ includeExtensions: ["md", "json"],
57
+ defaultFolderConfig: {
58
+ order: 999,
59
+ icon: "fa:folder",
60
+ },
61
+ },
62
+ // Media files
63
+ MEDIA_ONLY: {
64
+ includeExtensions: ["png", "jpg", "jpeg", "gif", "svg", "pdf"],
65
+ defaultFolderConfig: {
66
+ template: "media-gallery",
67
+ tags: ["media", "assets"],
68
+ },
69
+ },
70
+ };
71
+ /**
72
+ * Helper function to merge configuration
73
+ */
74
+ function createImportConfig(overrides = {}, preset) {
75
+ const baseConfig = { ...exports.DEFAULT_IMPORT_CONFIG };
76
+ // Apply preset if provided
77
+ if (preset && exports.IMPORT_PRESETS[preset]) {
78
+ baseConfig.fileFilter = {
79
+ ...baseConfig.fileFilter,
80
+ ...exports.IMPORT_PRESETS[preset],
81
+ };
82
+ // Apply preset's default folder config if it exists
83
+ if (exports.IMPORT_PRESETS[preset].defaultFolderConfig) {
84
+ baseConfig.defaultFolderConfig = {
85
+ ...baseConfig.defaultFolderConfig,
86
+ ...exports.IMPORT_PRESETS[preset].defaultFolderConfig,
87
+ };
88
+ }
89
+ }
90
+ // Apply user overrides
91
+ const finalConfig = {
92
+ ...baseConfig,
93
+ ...overrides,
94
+ fileFilter: {
95
+ ...baseConfig.fileFilter,
96
+ ...overrides.fileFilter,
97
+ },
98
+ defaultFolderConfig: {
99
+ ...baseConfig.defaultFolderConfig,
100
+ ...overrides.defaultFolderConfig,
101
+ },
102
+ };
103
+ // Ensure required fields are present
104
+ if (!finalConfig.token) {
105
+ finalConfig.token = process.env.OI_DOCUMENTATION_GITHUB_ACCESS_TOKEN || "";
106
+ }
107
+ return finalConfig;
108
+ }
109
+ /**
110
+ * Sanitize a raw (parsed) folder config object by picking only allowed keys
111
+ * and recursively sanitizing file configs.
112
+ */
113
+ function sanitizeFolderConfig(raw) {
114
+ if (!raw || typeof raw !== "object")
115
+ return {};
116
+ const folder = {};
117
+ for (const key of exports.FOLDER_CONFIG_ALLOWED_KEYS) {
118
+ if (key in raw) {
119
+ // files handled specially below
120
+ if (key !== "files")
121
+ folder[key] = raw[key];
122
+ }
123
+ }
124
+ if (raw.files && typeof raw.files === "object") {
125
+ const files = {};
126
+ for (const [base, cfg] of Object.entries(raw.files)) {
127
+ files[base] = sanitizeFileConfig(cfg);
128
+ }
129
+ folder.files = files;
130
+ }
131
+ return folder;
132
+ }
133
+ function sanitizeFileConfig(raw) {
134
+ if (!raw || typeof raw !== "object")
135
+ return {};
136
+ const fileCfg = {};
137
+ for (const key of exports.FILE_CONFIG_ALLOWED_KEYS) {
138
+ if (key in raw)
139
+ fileCfg[key] = raw[key];
140
+ }
141
+ return fileCfg;
142
+ }
@@ -0,0 +1 @@
1
+ export * from "./defaults";
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./defaults"), exports);
@@ -0,0 +1,30 @@
1
+ import { _User, Tenant } from "../../../types";
2
+ import { DocumentationStructure } from "../types";
3
+ /**
4
+ * Service for cleaning up old documentation that no longer exists in the repository
5
+ */
6
+ export declare class DocumentationCleanup {
7
+ /**
8
+ * Remove old default documentation that is no longer present in the new import
9
+ */
10
+ static cleanupOldDocumentation(newStructure: DocumentationStructure, user: _User | undefined, tenant: Tenant | undefined): Promise<{
11
+ deletedDocuments: number;
12
+ deletedCategories: number;
13
+ }>;
14
+ /**
15
+ * Collect all git paths from the documentation structure
16
+ */
17
+ private static collectGitPaths;
18
+ /**
19
+ * Recursively collect folder paths
20
+ */
21
+ private static collectFolderPaths;
22
+ /**
23
+ * Find all existing default documents for the given user/tenant
24
+ */
25
+ private static findExistingDefaultDocuments;
26
+ /**
27
+ * Find all existing default categories for the given user/tenant
28
+ */
29
+ private static findExistingDefaultCategories;
30
+ }
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DocumentationCleanup = void 0;
4
+ const types_1 = require("../../../types");
5
+ /**
6
+ * Service for cleaning up old documentation that no longer exists in the repository
7
+ */
8
+ class DocumentationCleanup {
9
+ /**
10
+ * Remove old default documentation that is no longer present in the new import
11
+ */
12
+ static async cleanupOldDocumentation(newStructure, user, tenant) {
13
+ console.log(`[DocumentationCleanup] Starting cleanup of old default documentation`);
14
+ // Collect all new git paths from the structure
15
+ const newGitPaths = new Set();
16
+ this.collectGitPaths(newStructure, newGitPaths);
17
+ console.log(`[DocumentationCleanup] Found ${newGitPaths.size} current git paths`);
18
+ // Find all existing default documentation for this user/tenant
19
+ const existingDocuments = await this.findExistingDefaultDocuments(user, tenant);
20
+ const existingCategories = await this.findExistingDefaultCategories(user, tenant);
21
+ console.log(`[DocumentationCleanup] Found ${existingDocuments.length} existing documents and ${existingCategories.length} existing categories`);
22
+ // Identify documents to delete
23
+ const documentsToDelete = existingDocuments.filter((doc) => {
24
+ const gitPath = doc.get("gitPath");
25
+ return gitPath && !newGitPaths.has(gitPath);
26
+ });
27
+ // Identify categories to delete
28
+ const categoriesToDelete = existingCategories.filter((cat) => {
29
+ const gitPath = cat.get("gitPath");
30
+ return gitPath && !newGitPaths.has(gitPath);
31
+ });
32
+ console.log(`[DocumentationCleanup] Identified ${documentsToDelete.length} documents and ${categoriesToDelete.length} categories for deletion`);
33
+ // Delete old documents
34
+ let deletedDocuments = 0;
35
+ for (const doc of documentsToDelete) {
36
+ try {
37
+ console.log(`[DocumentationCleanup] Deleting document: ${doc.get("title")} (gitPath: ${doc.get("gitPath")})`);
38
+ await doc.destroy({ useMasterKey: true });
39
+ deletedDocuments++;
40
+ }
41
+ catch (error) {
42
+ console.error(`[DocumentationCleanup] Failed to delete document ${doc.id}:`, error);
43
+ }
44
+ }
45
+ // Delete old categories (delete in reverse order to handle parent-child relationships)
46
+ let deletedCategories = 0;
47
+ const sortedCategories = categoriesToDelete.sort((a, b) => {
48
+ // Sort by gitPath depth (deeper paths first) to delete children before parents
49
+ const aDepth = (a.get("gitPath") || "").split("/").length;
50
+ const bDepth = (b.get("gitPath") || "").split("/").length;
51
+ return bDepth - aDepth;
52
+ });
53
+ for (const cat of sortedCategories) {
54
+ try {
55
+ console.log(`[DocumentationCleanup] Deleting category: ${cat.get("name")} (gitPath: ${cat.get("gitPath")})`);
56
+ await cat.destroy({ useMasterKey: true });
57
+ deletedCategories++;
58
+ }
59
+ catch (error) {
60
+ console.error(`[DocumentationCleanup] Failed to delete category ${cat.id}:`, error);
61
+ }
62
+ }
63
+ console.log(`[DocumentationCleanup] Cleanup complete: deleted ${deletedDocuments} documents and ${deletedCategories} categories`);
64
+ return { deletedDocuments, deletedCategories };
65
+ }
66
+ /**
67
+ * Collect all git paths from the documentation structure
68
+ */
69
+ static collectGitPaths(structure, gitPaths) {
70
+ // Collect file paths
71
+ for (const file of structure.allFiles) {
72
+ gitPaths.add(file.path);
73
+ }
74
+ // Collect folder paths recursively
75
+ this.collectFolderPaths(structure.root, "", gitPaths);
76
+ }
77
+ /**
78
+ * Recursively collect folder paths
79
+ */
80
+ static collectFolderPaths(folder, currentPath, gitPaths) {
81
+ // Add current folder path (except root)
82
+ if (currentPath) {
83
+ gitPaths.add(currentPath);
84
+ }
85
+ // Recursively process subfolders
86
+ for (const [name, subfolder] of folder.subfolders) {
87
+ const subfolderPath = currentPath ? `${currentPath}/${name}` : name;
88
+ this.collectFolderPaths(subfolder, subfolderPath, gitPaths);
89
+ }
90
+ }
91
+ /**
92
+ * Find all existing default documents for the given user/tenant
93
+ */
94
+ static async findExistingDefaultDocuments(user, tenant) {
95
+ const query = new Parse.Query(types_1.Documentation_Document)
96
+ .equalTo("isDefault", true)
97
+ .exists("gitPath"); // Only documents with gitPath (from repository)
98
+ if (tenant) {
99
+ query.equalTo("tenant", tenant);
100
+ }
101
+ if (user) {
102
+ query.equalTo("user", user);
103
+ }
104
+ try {
105
+ return await query.find({ useMasterKey: true });
106
+ }
107
+ catch (error) {
108
+ console.error(`[DocumentationCleanup] Failed to query existing documents:`, error);
109
+ return [];
110
+ }
111
+ }
112
+ /**
113
+ * Find all existing default categories for the given user/tenant
114
+ */
115
+ static async findExistingDefaultCategories(user, tenant) {
116
+ const query = new Parse.Query(types_1.Documentation_Category)
117
+ .equalTo("isDefault", true)
118
+ .exists("gitPath"); // Only categories with gitPath (from repository)
119
+ if (tenant) {
120
+ query.equalTo("tenant", tenant);
121
+ }
122
+ if (user) {
123
+ query.equalTo("user", user);
124
+ }
125
+ try {
126
+ return await query.find({ useMasterKey: true });
127
+ }
128
+ catch (error) {
129
+ console.error(`[DocumentationCleanup] Failed to query existing categories:`, error);
130
+ return [];
131
+ }
132
+ }
133
+ }
134
+ exports.DocumentationCleanup = DocumentationCleanup;
@@ -0,0 +1,9 @@
1
+ import { _User, Tenant } from "../../../types";
2
+ import { ImportResult } from "../types";
3
+ export declare class DocumentationConverter {
4
+ private readonly results;
5
+ constructor(importResults: ImportResult);
6
+ convert(user?: _User, tenant?: Tenant): Promise<void>;
7
+ private convertFolderToCategory;
8
+ private convertFileToDocumentation;
9
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DocumentationConverter = void 0;
4
+ const types_1 = require("../../../types");
5
+ const USER_ID = process.env.OI_DOCUMENTATION_USER_ID;
6
+ const TENANT_ID = process.env.OI_DOCUMENTATION_TENANT_ID;
7
+ class DocumentationConverter {
8
+ constructor(importResults) {
9
+ this.results = importResults;
10
+ }
11
+ async convert(user, tenant) {
12
+ // Implement your conversion logic here
13
+ if (!this.results.structure)
14
+ return;
15
+ this.convertFolderToCategory(this.results.structure.root, undefined, user, tenant);
16
+ }
17
+ async convertFolderToCategory(folder, parentCategory, user, tenant) {
18
+ const existingCategory = await new Parse.Query(types_1.Documentation_Category)
19
+ .equalTo("gitPath", folder.path)
20
+ .equalTo("isDefault", true)
21
+ .equalTo("user", user)
22
+ .equalTo("tenant", tenant)
23
+ .first({ useMasterKey: true });
24
+ const folderCategory = existingCategory || new types_1.Documentation_Category();
25
+ folderCategory.set("name", folder.config.title || folder.name);
26
+ folderCategory.set("icon", folder.config.icon);
27
+ folderCategory.set("order", folder.config.order || 999);
28
+ folderCategory.set("parent", parentCategory);
29
+ folderCategory.set("isDefault", true);
30
+ folderCategory.set("gitPath", folder.path);
31
+ if (user)
32
+ folderCategory.set("user", user);
33
+ if (tenant || user)
34
+ folderCategory.set("tenant", tenant ?? user?.get("tenant"));
35
+ const savedCategory = await folderCategory.save(null, {
36
+ useMasterKey: true,
37
+ });
38
+ for (const subfolder of folder.subfolders.values())
39
+ await this.convertFolderToCategory(subfolder, savedCategory, user, tenant);
40
+ for (const file of folder.files)
41
+ await this.convertFileToDocumentation(file, savedCategory, user, tenant);
42
+ }
43
+ async convertFileToDocumentation(file, category, user, tenant) {
44
+ const existingDoc = await new Parse.Query(types_1.Documentation_Document)
45
+ .equalTo("gitPath", file.path)
46
+ .equalTo("isDefault", true)
47
+ .first({ useMasterKey: true });
48
+ const doc = existingDoc || new types_1.Documentation_Document();
49
+ doc.set("title", file.config?.title || file.name);
50
+ doc.set("content", file.content || "");
51
+ doc.set("icon", file.config?.icon);
52
+ doc.set("order", file.config?.order || 999);
53
+ doc.set("category", category);
54
+ doc.set("locationPattern", file.config?.locationPattern);
55
+ doc.set("locations", file.config?.locations || []);
56
+ doc.set("isDefault", true);
57
+ doc.set("gitPath", file.path);
58
+ if (user)
59
+ doc.set("user", user);
60
+ if (tenant || user)
61
+ doc.set("tenant", tenant ?? user?.get("tenant"));
62
+ await doc.save(null, { useMasterKey: true });
63
+ }
64
+ }
65
+ exports.DocumentationConverter = DocumentationConverter;
@@ -0,0 +1,21 @@
1
+ import { ImportOptions, ImportResult } from "../types";
2
+ import { _User, Tenant } from "../../../types";
3
+ /**
4
+ * Main Documentation Importer class
5
+ */
6
+ export declare class DocumentationImporter {
7
+ private githubClient;
8
+ constructor(token: string);
9
+ /**
10
+ * Import documentation from a GitHub repository
11
+ */
12
+ importFromRepository(options: ImportOptions, user: _User | undefined, tenant: Tenant | undefined): Promise<ImportResult>;
13
+ /**
14
+ * Validate that a branch exists
15
+ */
16
+ private validateBranch;
17
+ /**
18
+ * Get file content from GitHub
19
+ */
20
+ getFileContent(owner: string, repo: string, path: string, ref?: string): Promise<any>;
21
+ }
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DocumentationImporter = void 0;
4
+ const services_1 = require("../services");
5
+ const types_1 = require("../../../types");
6
+ const Organizer_1 = require("./Organizer");
7
+ const Cleanup_1 = require("./Cleanup");
8
+ /**
9
+ * Main Documentation Importer class
10
+ */
11
+ class DocumentationImporter {
12
+ constructor(token) {
13
+ this.githubClient = new services_1.GitHubClient(token);
14
+ }
15
+ /**
16
+ * Import documentation from a GitHub repository
17
+ */
18
+ async importFromRepository(options, user, tenant) {
19
+ // Validate token
20
+ const gitUser = await this.githubClient.validateToken();
21
+ // Get repository info
22
+ const repo = await this.githubClient.getRepository(options.organization, options.repository);
23
+ // Determine branch to use
24
+ const branch = options.branch || repo.default_branch;
25
+ // Validate branch exists
26
+ await this.validateBranch(options.organization, options.repository, branch);
27
+ // Get branch info (commit SHA)
28
+ const branchInfo = await this.githubClient.getBranch(options.organization, options.repository, branch);
29
+ const latestCommitSha = branchInfo.commit.sha;
30
+ // Attempt to load previously imported commit SHA from Parse
31
+ let previousCommitSha;
32
+ let stateObj;
33
+ try {
34
+ stateObj = await new Parse.Query(types_1.Documentation_Config)
35
+ .equalTo("tenant", tenant)
36
+ .equalTo("user", user)
37
+ .first({
38
+ useMasterKey: true,
39
+ });
40
+ previousCommitSha = stateObj?.get("lastCommitSha");
41
+ }
42
+ catch (err) {
43
+ console.log(`Could not load previous commit SHA: ${err.message}`);
44
+ }
45
+ // Early exit if unchanged
46
+ if (previousCommitSha && previousCommitSha === latestCommitSha) {
47
+ return {
48
+ metadata: {
49
+ totalFiles: 0,
50
+ fileTypes: [],
51
+ // importedAt still reflects the check time
52
+ importedAt: new Date(),
53
+ repository: `${options.organization}/${options.repository}`,
54
+ branch,
55
+ commitSha: latestCommitSha,
56
+ previousCommitSha,
57
+ skipped: true,
58
+ skipReason: "unchanged",
59
+ },
60
+ };
61
+ }
62
+ const treeData = await this.githubClient.getTree(options.organization, options.repository, latestCommitSha);
63
+ // Organize structure with filtering and root path
64
+ const structure = await Organizer_1.DocumentationOrganizer.organizeRepositoryStructure(treeData, options.fileFilter, options.rootPath, this.githubClient, options.organization, options.repository, branch, options.defaultFolderConfig);
65
+ // Clean up old documentation that is no longer in the repository
66
+ // This only runs when commit SHA has changed (not on first import when previousCommitSha is undefined)
67
+ let cleanupResult = { deletedDocuments: 0, deletedCategories: 0 };
68
+ if (previousCommitSha) {
69
+ console.log(`[DocumentationImporter] Repository content changed, cleaning up old documentation...`);
70
+ try {
71
+ cleanupResult = await Cleanup_1.DocumentationCleanup.cleanupOldDocumentation(structure, user, tenant);
72
+ console.log(`[DocumentationImporter] Cleanup completed: ${cleanupResult.deletedDocuments} documents and ${cleanupResult.deletedCategories} categories removed`);
73
+ }
74
+ catch (error) {
75
+ console.error(`[DocumentationImporter] Cleanup failed:`, error);
76
+ // Continue with import even if cleanup fails
77
+ }
78
+ }
79
+ else {
80
+ console.log(`[DocumentationImporter] First import detected, skipping cleanup`);
81
+ }
82
+ // Persist latest commit SHA for future runs
83
+ try {
84
+ if (!stateObj) {
85
+ stateObj = new types_1.Documentation_Config();
86
+ }
87
+ stateObj.set("lastCommitSha", latestCommitSha);
88
+ if (tenant)
89
+ stateObj.set("tenant", tenant);
90
+ if (user)
91
+ stateObj.set("user", user);
92
+ await stateObj.save(null, { useMasterKey: true });
93
+ }
94
+ catch (err) {
95
+ console.log(`Could not persist latest commit SHA: ${err.message}`);
96
+ }
97
+ return {
98
+ structure,
99
+ metadata: {
100
+ totalFiles: structure.allFiles.length,
101
+ fileTypes: Array.from(structure.filesByExtension.keys()),
102
+ importedAt: new Date(),
103
+ repository: `${options.organization}/${options.repository}`,
104
+ branch,
105
+ commitSha: latestCommitSha,
106
+ previousCommitSha,
107
+ cleanup: cleanupResult,
108
+ },
109
+ };
110
+ }
111
+ /**
112
+ * Validate that a branch exists
113
+ */
114
+ async validateBranch(owner, repo, branch) {
115
+ try {
116
+ const branches = await this.githubClient.getBranches(owner, repo);
117
+ const branchNames = branches.map((b) => b.name);
118
+ if (!branchNames.includes(branch)) {
119
+ throw new Error(`Branch '${branch}' not found. Available branches: ${branchNames.join(", ")}`);
120
+ }
121
+ }
122
+ catch (error) {
123
+ console.log(`Could not validate branches: ${error}`);
124
+ }
125
+ }
126
+ /**
127
+ * Get file content from GitHub
128
+ */
129
+ async getFileContent(owner, repo, path, ref) {
130
+ return this.githubClient.getFileContent(owner, repo, path, ref);
131
+ }
132
+ }
133
+ exports.DocumentationImporter = DocumentationImporter;
@@ -0,0 +1,11 @@
1
+ import { GitHubTreeResponse, DocumentationStructure, FileFilterOptions, FolderConfig } from "../types";
2
+ import { GitHubClient } from "../services/GitHubClient";
3
+ /**
4
+ * Documentation Structure Organizer
5
+ */
6
+ export declare class DocumentationOrganizer {
7
+ /**
8
+ * Organize GitHub tree data into a hierarchical structure
9
+ */
10
+ static organizeRepositoryStructure(treeData: GitHubTreeResponse, fileFilter?: FileFilterOptions, rootPath?: string, githubClient?: GitHubClient, owner?: string, repo?: string, branch?: string, defaultFolderConfig?: Partial<FolderConfig>): Promise<DocumentationStructure>;
11
+ }