@finos/legend-application
Version:
Legend application core
140 lines • 6.91 kB
JavaScript
/**
* Copyright (c) 2020-present, Goldman Sachs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { LogEvent, uniq, guaranteeNonEmptyString, DocumentationEntry, } from '@finos/legend-shared';
import { APPLICATION_EVENT } from '../__lib__/LegendApplicationEvent.js';
export const collectKeyedDocumentationEntriesFromConfig = (rawEntries) => Object.entries(rawEntries).map((entry) => ({
key: entry[0],
content: DocumentationEntry.create(entry[1], entry[0]),
}));
export const collectDocumentationLinkEntryFromConfig = (rawEntries) => Object.entries(rawEntries).map((entry) => ({
key: guaranteeNonEmptyString(entry[0], "Documentation link 'key' is missing"),
label: guaranteeNonEmptyString(entry[1].label, "Documentation link 'label' is missing"),
url: guaranteeNonEmptyString(entry[1].url, "Documentation link 'url' is missing"),
}));
export const collectContextualDocumentationEntries = (config) => Object.entries(config).map((entry) => ({
context: entry[0],
documentationKey: entry[1],
}));
export class DocumentationService {
url;
links;
docRegistry = new Map();
contextualDocIndex = new Map();
constructor(applicationStore) {
// set the main documenation site url
this.url = applicationStore.config.documentationUrl;
this.links = applicationStore.config.documentationLinkEntries;
/**
* NOTE: the order of documentation entry overidding is (the later override the former):
* 1. Natively specified: specified in the codebase (no overriding allowed within this group of documentation entries):
* since we have extension mechanism, the order of plugins matter,
* we do not allow overriding, i.e. so the first specification for a documentation key wins
* 2. Fetched from documentation registries (no overriding allowed within this group of documentation entries):
* since we have extension mechanism and allow specifying multiple registry URLS,
* we do not allow overriding, i.e. so the first specification for a documentation key wins
* 3. Configured in application config (overiding allowed within this group)
*/
// build doc registry
applicationStore.pluginManager
.getApplicationPlugins()
.flatMap((plugin) => plugin.getExtraKeyedDocumentationEntries?.() ?? [])
.forEach((entry) => {
// NOTE: Entries specified natively will not override each other. This is to prevent entries from extensions
// accidentally overide entries from core.
if (this.hasDocEntry(entry.key)) {
applicationStore.logService.warn(LogEvent.create(APPLICATION_EVENT.DOCUMENTATION_LOAD__SKIP), entry.key);
}
else {
this.docRegistry.set(entry.key, entry.content);
}
});
// entries from config will override entries specified natively
applicationStore.config.keyedDocumentationEntries.forEach((entry) => this.docRegistry.set(entry.key, entry.content));
const contextualDocEntries = applicationStore.pluginManager
.getApplicationPlugins()
.flatMap((plugin) => plugin.getExtraContextualDocumentationEntries?.() ?? []);
// verify that required documentations are available
const missingDocumentationEntries = [];
uniq(applicationStore.pluginManager
.getApplicationPlugins()
.flatMap((plugin) => plugin.getExtraRequiredDocumentationKeys?.() ?? [])
.concat(contextualDocEntries.map((entry) => entry.documentationKey))).forEach((key) => {
if (!this.docRegistry.has(key)) {
missingDocumentationEntries.push(key);
}
});
if (missingDocumentationEntries.length) {
applicationStore.logService.warn(LogEvent.create(APPLICATION_EVENT.DOCUMENTATION_REQUIREMENT_CHECK__FAILURE), `Can't find corresponding documentation entry for keys:\n${missingDocumentationEntries
.map((key) => `- ${key}`)
.join('\n')}`);
}
// Contextual Documentation
contextualDocEntries.forEach((entry) => {
// NOTE: Entries specified natively will not override each other. This is to prevent entries from extensions
// overriding entries from core.
//
// However, it might be useful to allow extending the list of related doc entries.
// This allows extensions to broaden related doc entries for contextual docs
// If we need to support this behavior, we could create a dedicated extension method
if (this.hasContextualDocEntry(entry.context)) {
applicationStore.logService.warn(LogEvent.create(APPLICATION_EVENT.CONTEXTUAL_DOCUMENTATION_LOAD__SKIP), entry.context);
}
else {
const existingDocEntry = this.getDocEntry(entry.documentationKey);
if (existingDocEntry) {
this.contextualDocIndex.set(entry.context, existingDocEntry);
}
}
});
// entries from config will override entries specified natively
applicationStore.config.contextualDocEntries.forEach((entry) => {
const existingDocEntry = this.getDocEntry(entry.documentationKey);
if (existingDocEntry) {
this.contextualDocIndex.set(entry.context, existingDocEntry);
}
});
}
getDocEntry(key) {
return this.docRegistry.get(key);
}
hasDocEntry(key) {
return this.docRegistry.has(key);
}
getContextualDocEntry(key) {
return this.contextualDocIndex.get(key);
}
hasContextualDocEntry(key) {
return this.contextualDocIndex.has(key);
}
getAllDocEntries() {
return Array.from(this.docRegistry.values());
}
publishDocRegistry() {
const result = {};
this.docRegistry.forEach((value, key) => {
result[key] = DocumentationEntry.serialization.toJson(value);
});
return result;
}
publishContextualDocIndex() {
const result = {};
this.contextualDocIndex.forEach((value, key) => {
result[key] = value.key;
});
return result;
}
}
//# sourceMappingURL=DocumentationService.js.map