@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.
- package/dist/featuremap.json +1 -0
- package/dist/features/config/helper/isFeatureEnabled.d.ts +2 -1
- package/dist/features/documentation/config/defaults.d.ts +39 -0
- package/dist/features/documentation/config/defaults.js +142 -0
- package/dist/features/documentation/config/index.d.ts +1 -0
- package/dist/features/documentation/config/index.js +17 -0
- package/dist/features/documentation/core/Cleanup.d.ts +30 -0
- package/dist/features/documentation/core/Cleanup.js +134 -0
- package/dist/features/documentation/core/Converter.d.ts +9 -0
- package/dist/features/documentation/core/Converter.js +65 -0
- package/dist/features/documentation/core/Importer.d.ts +21 -0
- package/dist/features/documentation/core/Importer.js +133 -0
- package/dist/features/documentation/core/Organizer.d.ts +11 -0
- package/dist/features/documentation/core/Organizer.js +52 -0
- package/dist/features/documentation/core/index.d.ts +4 -0
- package/dist/features/documentation/core/index.js +20 -0
- package/dist/features/documentation/functions/importDocs.d.ts +2 -0
- package/dist/features/documentation/functions/importDocs.js +40 -0
- package/dist/features/documentation/index.d.ts +8 -0
- package/dist/features/documentation/index.js +34 -0
- package/dist/features/documentation/services/ConfigApplier.d.ts +11 -0
- package/dist/features/documentation/services/ConfigApplier.js +110 -0
- package/dist/features/documentation/services/ContentLoader.d.ts +6 -0
- package/dist/features/documentation/services/ContentLoader.js +40 -0
- package/dist/features/documentation/services/FeatureFilter.d.ts +34 -0
- package/dist/features/documentation/services/FeatureFilter.js +154 -0
- package/dist/features/documentation/services/GitHubClient.d.ts +43 -0
- package/dist/features/documentation/services/GitHubClient.js +140 -0
- package/dist/features/documentation/services/MetadataEnricher.d.ts +5 -0
- package/dist/features/documentation/services/MetadataEnricher.js +29 -0
- package/dist/features/documentation/services/StructureBuilder.d.ts +7 -0
- package/dist/features/documentation/services/StructureBuilder.js +43 -0
- package/dist/features/documentation/services/TreeNormalizer.d.ts +10 -0
- package/dist/features/documentation/services/TreeNormalizer.js +73 -0
- package/dist/features/documentation/services/index.d.ts +7 -0
- package/dist/features/documentation/services/index.js +23 -0
- package/dist/features/documentation/types/GitHubTypes.d.ts +25 -0
- package/dist/features/documentation/types/GitHubTypes.js +2 -0
- package/dist/features/documentation/types/StructureTypes.d.ts +114 -0
- package/dist/features/documentation/types/StructureTypes.js +2 -0
- package/dist/features/documentation/types/index.d.ts +2 -0
- package/dist/features/documentation/types/index.js +18 -0
- package/dist/functions/openinc-documentation-import-docs.d.ts +1 -0
- package/dist/functions/openinc-documentation-import-docs.js +23 -0
- package/dist/hooks/Documentation_Config.d.ts +1 -0
- package/dist/hooks/Documentation_Config.js +17 -0
- package/dist/hooks/Tenant.js +3 -0
- package/dist/hooks/_Role.js +3 -3
- package/dist/index.js +12 -0
- package/dist/types/Documentation_Category.d.ts +6 -0
- package/dist/types/Documentation_Category.js +12 -0
- package/dist/types/Documentation_Config.d.ts +21 -0
- package/dist/types/Documentation_Config.js +29 -0
- package/dist/types/Documentation_Document.d.ts +6 -0
- package/dist/types/Documentation_Document.js +12 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +5 -3
- package/package.json +3 -1
- package/schema/Documentation_Category.json +9 -0
- package/schema/Documentation_Config.json +50 -0
- package/schema/Documentation_Document.json +9 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GitHubClient = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* GitHub API Client for fetching repository data
|
|
6
|
+
*/
|
|
7
|
+
class GitHubClient {
|
|
8
|
+
constructor(token) {
|
|
9
|
+
this.baseUrl = "https://api.github.com";
|
|
10
|
+
this.headers = {
|
|
11
|
+
Authorization: `Bearer ${token}`,
|
|
12
|
+
Accept: "application/vnd.github.v3+json",
|
|
13
|
+
"User-Agent": "OpenInc-Documentation-Importer",
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Validate the GitHub token
|
|
18
|
+
*/
|
|
19
|
+
async validateToken() {
|
|
20
|
+
const response = await fetch(`${this.baseUrl}/user`, {
|
|
21
|
+
headers: this.headers,
|
|
22
|
+
});
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
const error = await response.text();
|
|
25
|
+
throw new Error(`Invalid token: ${response.status} ${response.statusText} - ${error}`);
|
|
26
|
+
}
|
|
27
|
+
return response.json();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get repository information
|
|
31
|
+
*/
|
|
32
|
+
async getRepository(owner, repo) {
|
|
33
|
+
const response = await fetch(`${this.baseUrl}/repos/${owner}/${repo}`, {
|
|
34
|
+
headers: this.headers,
|
|
35
|
+
});
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
const error = await response.text();
|
|
38
|
+
throw new Error(`Failed to access repository: ${response.status} ${response.statusText} - ${error}`);
|
|
39
|
+
}
|
|
40
|
+
return response.json();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get all branches for a repository
|
|
44
|
+
*/
|
|
45
|
+
async getBranches(owner, repo) {
|
|
46
|
+
const response = await fetch(`${this.baseUrl}/repos/${owner}/${repo}/branches`, {
|
|
47
|
+
headers: this.headers,
|
|
48
|
+
});
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
throw new Error(`Failed to fetch branches: ${response.status} ${response.statusText}`);
|
|
51
|
+
}
|
|
52
|
+
return response.json();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get a specific branch
|
|
56
|
+
*/
|
|
57
|
+
async getBranch(owner, repo, branch) {
|
|
58
|
+
const response = await fetch(`${this.baseUrl}/repos/${owner}/${repo}/branches/${branch}`, {
|
|
59
|
+
headers: this.headers,
|
|
60
|
+
});
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
const error = await response.text();
|
|
63
|
+
throw new Error(`Failed to fetch branch '${branch}': ${response.status} ${response.statusText} - ${error}`);
|
|
64
|
+
}
|
|
65
|
+
return response.json();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get repository tree (file structure)
|
|
69
|
+
*/
|
|
70
|
+
async getTree(owner, repo, sha, recursive = true) {
|
|
71
|
+
const url = `${this.baseUrl}/repos/${owner}/${repo}/git/trees/${sha}${recursive ? "?recursive=1" : ""}`;
|
|
72
|
+
const response = await fetch(url, {
|
|
73
|
+
headers: this.headers,
|
|
74
|
+
});
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
throw new Error(`Failed to fetch repository tree: ${response.status} ${response.statusText}`);
|
|
77
|
+
}
|
|
78
|
+
return response.json();
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get file content
|
|
82
|
+
*/
|
|
83
|
+
async getFileContent(owner, repo, path, ref) {
|
|
84
|
+
const url = `${this.baseUrl}/repos/${owner}/${repo}/contents/${path}${ref ? `?ref=${ref}` : ""}`;
|
|
85
|
+
const response = await fetch(url, {
|
|
86
|
+
headers: this.headers,
|
|
87
|
+
});
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
throw new Error(`Failed to fetch file content: ${response.status} ${response.statusText}`);
|
|
90
|
+
}
|
|
91
|
+
return response.json();
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get the last commit information for a specific file
|
|
95
|
+
*/
|
|
96
|
+
async getFileLastCommit(owner, repo, path, ref) {
|
|
97
|
+
const url = `${this.baseUrl}/repos/${owner}/${repo}/commits?path=${encodeURIComponent(path)}&per_page=1${ref ? `&sha=${ref}` : ""}`;
|
|
98
|
+
const response = await fetch(url, {
|
|
99
|
+
headers: this.headers,
|
|
100
|
+
});
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
throw new Error(`Failed to fetch file commit info: ${response.status} ${response.statusText}`);
|
|
103
|
+
}
|
|
104
|
+
const commits = (await response.json());
|
|
105
|
+
return commits.length > 0 ? commits[0] : null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get commit information for multiple files in batch
|
|
109
|
+
*/
|
|
110
|
+
async getMultipleFileCommits(owner, repo, paths, ref) {
|
|
111
|
+
const commitMap = new Map();
|
|
112
|
+
// Process files in batches to avoid rate limiting
|
|
113
|
+
const batchSize = 5;
|
|
114
|
+
for (let i = 0; i < paths.length; i += batchSize) {
|
|
115
|
+
const batch = paths.slice(i, i + batchSize);
|
|
116
|
+
const promises = batch.map(async (path) => {
|
|
117
|
+
try {
|
|
118
|
+
const commit = await this.getFileLastCommit(owner, repo, path, ref);
|
|
119
|
+
return { path, commit };
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.warn(`⚠️ Failed to get commit info for ${path}:`, error);
|
|
123
|
+
return { path, commit: null };
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
const results = await Promise.all(promises);
|
|
127
|
+
results.forEach(({ path, commit }) => {
|
|
128
|
+
if (commit) {
|
|
129
|
+
commitMap.set(path, commit);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
// Small delay to be respectful to GitHub API
|
|
133
|
+
if (i + batchSize < paths.length) {
|
|
134
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return commitMap;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.GitHubClient = GitHubClient;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { DocumentationFile } from "../types";
|
|
2
|
+
import { GitHubClient } from "./GitHubClient";
|
|
3
|
+
export declare class MetadataEnricher {
|
|
4
|
+
static enrichCommits(files: DocumentationFile[], githubClient: GitHubClient, owner: string, repo: string, branch?: string, rootPath?: string): Promise<void>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MetadataEnricher = void 0;
|
|
4
|
+
class MetadataEnricher {
|
|
5
|
+
static async enrichCommits(files, githubClient, owner, repo, branch, rootPath) {
|
|
6
|
+
const normalizedRoot = rootPath?.replace(/^\/+/g, "").replace(/\/+$/g, "");
|
|
7
|
+
const fullPaths = files.map((f) => normalizedRoot ? `${normalizedRoot}/${f.path}` : f.path);
|
|
8
|
+
try {
|
|
9
|
+
const commitMap = await githubClient.getMultipleFileCommits(owner, repo, fullPaths, branch);
|
|
10
|
+
let enriched = 0;
|
|
11
|
+
files.forEach((file, idx) => {
|
|
12
|
+
const commit = commitMap.get(fullPaths[idx]);
|
|
13
|
+
if (commit?.commit) {
|
|
14
|
+
file.lastModified = new Date(commit.commit.author.date);
|
|
15
|
+
file.lastModifiedBy = commit.commit.author.name;
|
|
16
|
+
file.lastCommitSha = commit.sha;
|
|
17
|
+
file.lastCommitMessage = commit.commit.message.split("\n")[0];
|
|
18
|
+
if (!file.fileLastModifiedAt)
|
|
19
|
+
file.fileLastModifiedAt = file.lastModified;
|
|
20
|
+
enriched++;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
console.warn("Failed to fetch commit information:", e);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.MetadataEnricher = MetadataEnricher;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DocumentationFolder, DocumentationFile, FolderConfig } from "../types";
|
|
2
|
+
export declare class StructureBuilder {
|
|
3
|
+
static build(files: DocumentationFile[], rootPath?: string, defaultFolderConfig?: Partial<FolderConfig>): {
|
|
4
|
+
root: DocumentationFolder;
|
|
5
|
+
configFiles: DocumentationFile[];
|
|
6
|
+
};
|
|
7
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StructureBuilder = void 0;
|
|
4
|
+
class StructureBuilder {
|
|
5
|
+
static build(files, rootPath, defaultFolderConfig) {
|
|
6
|
+
const root = {
|
|
7
|
+
name: rootPath || "root",
|
|
8
|
+
path: "",
|
|
9
|
+
files: [],
|
|
10
|
+
subfolders: new Map(),
|
|
11
|
+
config: { ...defaultFolderConfig },
|
|
12
|
+
};
|
|
13
|
+
const configFiles = [];
|
|
14
|
+
for (const file of files) {
|
|
15
|
+
const pathParts = file.path.split("/");
|
|
16
|
+
// folder navigation (all but last segment)
|
|
17
|
+
let current = root;
|
|
18
|
+
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
19
|
+
const folderName = pathParts[i];
|
|
20
|
+
const folderPath = pathParts.slice(0, i + 1).join("/");
|
|
21
|
+
if (!current.subfolders.has(folderName)) {
|
|
22
|
+
current.subfolders.set(folderName, {
|
|
23
|
+
name: folderName,
|
|
24
|
+
path: folderPath,
|
|
25
|
+
files: [],
|
|
26
|
+
subfolders: new Map(),
|
|
27
|
+
config: { ...defaultFolderConfig },
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
current = current.subfolders.get(folderName);
|
|
31
|
+
}
|
|
32
|
+
// classify file
|
|
33
|
+
if (file.originalFilename === "config.json") {
|
|
34
|
+
configFiles.push(file);
|
|
35
|
+
}
|
|
36
|
+
else if (file.extension === "md") {
|
|
37
|
+
current.files.push(file);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { root, configFiles };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.StructureBuilder = StructureBuilder;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { GitHubTreeResponse, DocumentationFile, FileFilterOptions } from "../types";
|
|
2
|
+
/** Handles path normalization, root trimming and initial file object creation + filtering. */
|
|
3
|
+
export declare class TreeNormalizer {
|
|
4
|
+
static normalize(treeData: GitHubTreeResponse, rootPath?: string, fileFilter?: FileFilterOptions): {
|
|
5
|
+
files: DocumentationFile[];
|
|
6
|
+
normalizedRootPath: string;
|
|
7
|
+
};
|
|
8
|
+
private static shouldIncludeFile;
|
|
9
|
+
private static matchesPattern;
|
|
10
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TreeNormalizer = void 0;
|
|
4
|
+
/** Handles path normalization, root trimming and initial file object creation + filtering. */
|
|
5
|
+
class TreeNormalizer {
|
|
6
|
+
static normalize(treeData, rootPath, fileFilter) {
|
|
7
|
+
const normalizedRootPath = rootPath
|
|
8
|
+
? rootPath.replace(/^\/+/g, "").replace(/\/+$/g, "")
|
|
9
|
+
: "";
|
|
10
|
+
const rootPrefix = normalizedRootPath ? normalizedRootPath + "/" : "";
|
|
11
|
+
const files = [];
|
|
12
|
+
for (const item of treeData.tree) {
|
|
13
|
+
if (item.type !== "blob")
|
|
14
|
+
continue;
|
|
15
|
+
if (normalizedRootPath && !item.path.startsWith(rootPrefix))
|
|
16
|
+
continue;
|
|
17
|
+
let relativePath = item.path;
|
|
18
|
+
if (normalizedRootPath)
|
|
19
|
+
relativePath = item.path.substring(rootPrefix.length);
|
|
20
|
+
if (!relativePath)
|
|
21
|
+
continue;
|
|
22
|
+
const pathParts = relativePath.split("/");
|
|
23
|
+
const fileName = pathParts[pathParts.length - 1];
|
|
24
|
+
const extension = fileName.includes(".")
|
|
25
|
+
? (fileName.split(".").pop() || "").toLowerCase()
|
|
26
|
+
: "";
|
|
27
|
+
const baseName = extension
|
|
28
|
+
? fileName.slice(0, fileName.lastIndexOf("."))
|
|
29
|
+
: fileName;
|
|
30
|
+
const file = {
|
|
31
|
+
name: baseName,
|
|
32
|
+
originalFilename: fileName,
|
|
33
|
+
path: relativePath,
|
|
34
|
+
sha: item.sha,
|
|
35
|
+
size: item.size,
|
|
36
|
+
extension,
|
|
37
|
+
url: item.url,
|
|
38
|
+
};
|
|
39
|
+
if (fileFilter && !this.shouldIncludeFile(file, fileFilter))
|
|
40
|
+
continue;
|
|
41
|
+
files.push(file);
|
|
42
|
+
}
|
|
43
|
+
return { files, normalizedRootPath };
|
|
44
|
+
}
|
|
45
|
+
static shouldIncludeFile(file, filter) {
|
|
46
|
+
if (filter.excludeExtensions?.includes(file.extension))
|
|
47
|
+
return false;
|
|
48
|
+
if (filter.includeExtensions?.length &&
|
|
49
|
+
!filter.includeExtensions.includes(file.extension))
|
|
50
|
+
return false;
|
|
51
|
+
if (filter.excludePaths?.length) {
|
|
52
|
+
for (const p of filter.excludePaths)
|
|
53
|
+
if (this.matchesPattern(file.path, p))
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (filter.includePaths?.length) {
|
|
57
|
+
let inc = false;
|
|
58
|
+
for (const p of filter.includePaths)
|
|
59
|
+
if (this.matchesPattern(file.path, p)) {
|
|
60
|
+
inc = true;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
if (!inc)
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
static matchesPattern(path, pattern) {
|
|
69
|
+
const regexPattern = pattern.replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
70
|
+
return new RegExp(`^${regexPattern}$`, "i").test(path);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.TreeNormalizer = TreeNormalizer;
|
|
@@ -0,0 +1,23 @@
|
|
|
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("./GitHubClient"), exports);
|
|
18
|
+
__exportStar(require("./FeatureFilter"), exports);
|
|
19
|
+
__exportStar(require("./ConfigApplier"), exports);
|
|
20
|
+
__exportStar(require("./ContentLoader"), exports);
|
|
21
|
+
__exportStar(require("./MetadataEnricher"), exports);
|
|
22
|
+
__exportStar(require("./StructureBuilder"), exports);
|
|
23
|
+
__exportStar(require("./TreeNormalizer"), exports);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type GitHubTreeItem = {
|
|
2
|
+
path: string;
|
|
3
|
+
mode: string;
|
|
4
|
+
type: "blob" | "tree";
|
|
5
|
+
sha: string;
|
|
6
|
+
size?: number;
|
|
7
|
+
url: string;
|
|
8
|
+
};
|
|
9
|
+
export type GitHubTreeResponse = {
|
|
10
|
+
sha: string;
|
|
11
|
+
url: string;
|
|
12
|
+
tree: GitHubTreeItem[];
|
|
13
|
+
truncated: boolean;
|
|
14
|
+
};
|
|
15
|
+
export type GitHubBranch = {
|
|
16
|
+
name: string;
|
|
17
|
+
commit: {
|
|
18
|
+
sha: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export type GitHubRepository = {
|
|
22
|
+
name: string;
|
|
23
|
+
private: boolean;
|
|
24
|
+
default_branch: string;
|
|
25
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Feature } from "../../config/helper/isFeatureEnabled";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for an individual file within a documentation folder.
|
|
4
|
+
*/
|
|
5
|
+
export type FileConfig = {
|
|
6
|
+
/** Sort order for this file (lower first). Defaults to 999 if not provided. */
|
|
7
|
+
order?: number;
|
|
8
|
+
/** Icon identifier (e.g., fa:file). Defaults to fa:file */
|
|
9
|
+
icon?: string;
|
|
10
|
+
/** Optional display title overriding file name */
|
|
11
|
+
title?: string;
|
|
12
|
+
/** Location Pattern */
|
|
13
|
+
locationPattern?: string;
|
|
14
|
+
/** locations */
|
|
15
|
+
locations?: string[];
|
|
16
|
+
/** Optional feature flag controlling visibility */
|
|
17
|
+
feature?: Feature;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Configuration for a documentation folder (from config.json)
|
|
21
|
+
*/
|
|
22
|
+
export type FolderConfig = {
|
|
23
|
+
/** Display title for the folder (overrides folder name) */
|
|
24
|
+
title?: string;
|
|
25
|
+
/** Sort order for this folder (lower numbers first) */
|
|
26
|
+
order?: number;
|
|
27
|
+
/** Icon identifier for display */
|
|
28
|
+
icon?: string;
|
|
29
|
+
/** Per-file configuration map (key = file name without extension) */
|
|
30
|
+
files?: Record<string, FileConfig>;
|
|
31
|
+
/** Optional feature flag controlling the entire folder */
|
|
32
|
+
feature?: Feature;
|
|
33
|
+
};
|
|
34
|
+
export type DocumentationFile = {
|
|
35
|
+
/** Base name without extension */
|
|
36
|
+
name: string;
|
|
37
|
+
/** Original filename including extension */
|
|
38
|
+
originalFilename?: string;
|
|
39
|
+
path: string;
|
|
40
|
+
sha: string;
|
|
41
|
+
size?: number;
|
|
42
|
+
extension: string;
|
|
43
|
+
url: string;
|
|
44
|
+
lastModified?: Date;
|
|
45
|
+
lastModifiedBy?: string;
|
|
46
|
+
lastCommitSha?: string;
|
|
47
|
+
lastCommitMessage?: string;
|
|
48
|
+
/** Raw textual content of the file (decoded UTF-8 for text-based files) */
|
|
49
|
+
content?: string;
|
|
50
|
+
/** Timestamp from source control representing when the source was last modified (alias of lastModified for persistence clarity) */
|
|
51
|
+
fileLastModifiedAt?: Date;
|
|
52
|
+
/** File-specific configuration (inherited from parent folder config.files entry) */
|
|
53
|
+
config?: FileConfig;
|
|
54
|
+
};
|
|
55
|
+
export type DocumentationFolder = {
|
|
56
|
+
name: string;
|
|
57
|
+
path: string;
|
|
58
|
+
files: DocumentationFile[];
|
|
59
|
+
subfolders: Map<string, DocumentationFolder>;
|
|
60
|
+
/** Configuration from config.json file or default config (always present) */
|
|
61
|
+
config: FolderConfig;
|
|
62
|
+
};
|
|
63
|
+
export type DocumentationStructure = {
|
|
64
|
+
root: DocumentationFolder;
|
|
65
|
+
allFiles: DocumentationFile[];
|
|
66
|
+
filesByExtension: Map<string, DocumentationFile[]>;
|
|
67
|
+
};
|
|
68
|
+
export type ImportOptions = {
|
|
69
|
+
branch?: string;
|
|
70
|
+
repository: string;
|
|
71
|
+
organization: string;
|
|
72
|
+
token: string;
|
|
73
|
+
fileFilter?: FileFilterOptions;
|
|
74
|
+
/** Root path within the repository to start from (e.g., "docs" to start from docs folder) */
|
|
75
|
+
rootPath?: string;
|
|
76
|
+
/** Default folder configuration to apply to folders without config.json */
|
|
77
|
+
defaultFolderConfig?: Partial<FolderConfig>;
|
|
78
|
+
/** If provided, skip calling getBranch() and use this commit SHA directly (e.g., provided by external scheduler) */
|
|
79
|
+
preResolvedCommitSha?: string;
|
|
80
|
+
};
|
|
81
|
+
export type FileFilterOptions = {
|
|
82
|
+
/** Array of file extensions to include (without dots). If not provided, all files are included. */
|
|
83
|
+
includeExtensions?: string[];
|
|
84
|
+
/** Array of file extensions to exclude (without dots). Takes precedence over includeExtensions. */
|
|
85
|
+
excludeExtensions?: string[];
|
|
86
|
+
/** Path patterns to include (supports wildcards) */
|
|
87
|
+
includePaths?: string[];
|
|
88
|
+
/** Path patterns to exclude (supports wildcards) */
|
|
89
|
+
excludePaths?: string[];
|
|
90
|
+
};
|
|
91
|
+
export type ImportResult = {
|
|
92
|
+
/** Documentation structure for this import. Undefined when skipped (no new commit). */
|
|
93
|
+
structure?: DocumentationStructure;
|
|
94
|
+
metadata: {
|
|
95
|
+
totalFiles: number;
|
|
96
|
+
fileTypes: string[];
|
|
97
|
+
importedAt: Date;
|
|
98
|
+
repository: string;
|
|
99
|
+
branch: string;
|
|
100
|
+
/** Latest commit SHA observed for the branch at import time */
|
|
101
|
+
commitSha: string;
|
|
102
|
+
/** Previously imported commit SHA (if any) */
|
|
103
|
+
previousCommitSha?: string;
|
|
104
|
+
/** Indicates the import was skipped because the commit SHA is unchanged */
|
|
105
|
+
skipped?: boolean;
|
|
106
|
+
/** Reason for skipping (e.g., 'unchanged') */
|
|
107
|
+
skipReason?: string;
|
|
108
|
+
/** Cleanup information when old documentation was removed */
|
|
109
|
+
cleanup?: {
|
|
110
|
+
deletedDocuments: number;
|
|
111
|
+
deletedCategories: number;
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
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("./GitHubTypes"), exports);
|
|
18
|
+
__exportStar(require("./StructureTypes"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function init(name: string): Promise<void>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.init = init;
|
|
4
|
+
const config_1 = require("../features/config");
|
|
5
|
+
const importDocs_1 = require("../features/documentation/functions/importDocs");
|
|
6
|
+
async function init(name) {
|
|
7
|
+
Parse.Cloud.define(name, async function (request) {
|
|
8
|
+
if (!request.master)
|
|
9
|
+
return { success: false, error: "Master key is required" };
|
|
10
|
+
try {
|
|
11
|
+
if ((0, config_1.isFeatureEnabled)("DOCUMENTATION")) {
|
|
12
|
+
await (0, importDocs_1.importDocs)();
|
|
13
|
+
return { status: "ok" };
|
|
14
|
+
}
|
|
15
|
+
console.log("Feature DOCUMENTATION is disabled");
|
|
16
|
+
return { status: "feature_disabled" };
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
console.error("Error in importDocs:", e);
|
|
20
|
+
return { status: "error", error: e };
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function init(): Promise<void>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.init = init;
|
|
4
|
+
const __1 = require("..");
|
|
5
|
+
const types_1 = require("../types");
|
|
6
|
+
async function init() {
|
|
7
|
+
(0, __1.beforeSaveHook)(types_1.Documentation_Config, async (request) => {
|
|
8
|
+
const { object, original, user } = request;
|
|
9
|
+
await (0, __1.defaultHandler)(request);
|
|
10
|
+
await (0, __1.defaultAclHandler)(request);
|
|
11
|
+
// TODO
|
|
12
|
+
});
|
|
13
|
+
(0, __1.afterSaveHook)(types_1.Documentation_Config, async (request) => {
|
|
14
|
+
const { object, original, user } = request;
|
|
15
|
+
// TODO
|
|
16
|
+
});
|
|
17
|
+
}
|
package/dist/hooks/Tenant.js
CHANGED
|
@@ -54,6 +54,7 @@ async function init() {
|
|
|
54
54
|
await (0, __1.ensureRole)(`od-tenant-admin-${object.id}`, {
|
|
55
55
|
label: `${object.get("label")} (Admin)`,
|
|
56
56
|
});
|
|
57
|
+
console.log("--------> Ensured tenant admin role");
|
|
57
58
|
await (0, __1.ensureRole)(`od-tenant-user-${object.id}`, {
|
|
58
59
|
label: object.get("label"),
|
|
59
60
|
acl: new Parse.ACL({
|
|
@@ -62,7 +63,9 @@ async function init() {
|
|
|
62
63
|
},
|
|
63
64
|
}),
|
|
64
65
|
});
|
|
66
|
+
console.log("--------> Ensured tenant user role");
|
|
65
67
|
if (!original) {
|
|
68
|
+
console.log("--------> Trigger beforeSave after creation");
|
|
66
69
|
// trigger beforeSave after creation
|
|
67
70
|
await object.save(null, {
|
|
68
71
|
useMasterKey: true,
|
package/dist/hooks/_Role.js
CHANGED
|
@@ -9,9 +9,9 @@ async function init() {
|
|
|
9
9
|
if (request.user && request.user.get("tenant")) {
|
|
10
10
|
tenantId = request.user.get("tenant").id;
|
|
11
11
|
}
|
|
12
|
-
if (!role.get("name") && role.isNew()) {
|
|
13
|
-
|
|
14
|
-
}
|
|
12
|
+
//if (!role.get("name") && role.isNew()) {
|
|
13
|
+
// role.set("name", crypto.randomUUID());
|
|
14
|
+
//}
|
|
15
15
|
//Set ACL to od-tenant-admin-{id_of_tenant}
|
|
16
16
|
if (role.isNew()) {
|
|
17
17
|
role.setACL(new Parse.ACL({
|
package/dist/index.js
CHANGED
|
@@ -42,6 +42,7 @@ const Core_Email_1 = require("./hooks/Core_Email");
|
|
|
42
42
|
const openservice_1 = require("./features/openservice");
|
|
43
43
|
const _init_1 = require("./functions/_init");
|
|
44
44
|
const _init_2 = require("./hooks/_init");
|
|
45
|
+
const importDocs_1 = require("./features/documentation/functions/importDocs");
|
|
45
46
|
dayjs_1.default.extend(objectSupport_1.default);
|
|
46
47
|
dayjs_1.default.extend(weekday_1.default);
|
|
47
48
|
dayjs_1.default.extend(dayOfYear_1.default);
|
|
@@ -96,6 +97,8 @@ async function init() {
|
|
|
96
97
|
await (0, settings_1.initUserSettings)();
|
|
97
98
|
if ((0, config_1.isFeatureEnabled)("MAINTENANCE"))
|
|
98
99
|
await (0, openservice_1.init)();
|
|
100
|
+
if ((0, config_1.isFeatureEnabled)("DOCUMENTATION"))
|
|
101
|
+
await (0, importDocs_1.importDocs)();
|
|
99
102
|
}
|
|
100
103
|
async function initTranslations() {
|
|
101
104
|
// try {
|
|
@@ -272,6 +275,7 @@ async function getConfigBoolean(key) {
|
|
|
272
275
|
* @returns A Promise that resolves when the role is successfully created or updated.
|
|
273
276
|
*/
|
|
274
277
|
async function ensureRole(name, options) {
|
|
278
|
+
console.log("--------> Inside ensureRole");
|
|
275
279
|
const label = options?.label || undefined;
|
|
276
280
|
const acl = options?.acl || new Parse.ACL();
|
|
277
281
|
const childRoles = options?.childRoles || undefined;
|
|
@@ -282,19 +286,25 @@ async function ensureRole(name, options) {
|
|
|
282
286
|
.equalTo("name", name)
|
|
283
287
|
.first({ useMasterKey: true });
|
|
284
288
|
if (!role) {
|
|
289
|
+
console.log("--------> Creating role");
|
|
285
290
|
role = new Parse.Role(name, acl);
|
|
286
291
|
role.set("label", label);
|
|
287
292
|
await role.save(null, {
|
|
288
293
|
useMasterKey: true,
|
|
289
294
|
});
|
|
290
295
|
}
|
|
296
|
+
else {
|
|
297
|
+
console.log("--------> Role already exists");
|
|
298
|
+
}
|
|
291
299
|
let changed = false;
|
|
292
300
|
if (role.get("label") !== label) {
|
|
293
301
|
role.set("label", label);
|
|
302
|
+
console.log("--------> Updated role label");
|
|
294
303
|
changed = true;
|
|
295
304
|
}
|
|
296
305
|
if (!(0, fast_equals_1.deepEqual)(acl.toJSON(), role.getACL()?.toJSON())) {
|
|
297
306
|
role.setACL(acl);
|
|
307
|
+
console.log("--------> Updated role ACL");
|
|
298
308
|
changed = true;
|
|
299
309
|
}
|
|
300
310
|
if (Array.isArray(childRoles) && childRoles.length > 0) {
|
|
@@ -311,10 +321,12 @@ async function ensureRole(name, options) {
|
|
|
311
321
|
.equalTo("name", childRoleName)
|
|
312
322
|
.find({ useMasterKey: true });
|
|
313
323
|
relation.add(childRole);
|
|
324
|
+
console.log("--------> Added child role", childRoleName);
|
|
314
325
|
changed = true;
|
|
315
326
|
}
|
|
316
327
|
}
|
|
317
328
|
if (changed) {
|
|
329
|
+
console.log("--------> Saving role");
|
|
318
330
|
await role.save(null, { useMasterKey: true });
|
|
319
331
|
}
|
|
320
332
|
}
|