@kui-shell/core
Version:
An Electron-based shell for cloud-native development
165 lines • 8.01 kB
JavaScript
/*
* Copyright 2017 The Kubernetes Authors
*
* 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.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import Debug from 'debug';
import { webpackPath } from './path';
import { proxy } from '../core/command-tree';
const debug = Debug('core/plugins/resolver');
/** export the prequire function */
const prequire = (route, prescan, registrar, options) => __awaiter(void 0, void 0, void 0, function* () {
try {
if (!Object.prototype.hasOwnProperty.call(registrar, route)) {
// note how we stash a promise in the registrar immediately, to
// avoid race conditions with multiple threads trying to prequire
// the same plugin
// eslint-disable-next-line no-async-promise-executor
registrar[route] = new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
const module = prescan.flat.find(_ => _.route === route);
if (module) {
try {
// NOTE ON @kui-shell relativization: this is important so that
// webpack can be instructed to pull in the plugins into the build
// see the corresponding NOTE in ./assembler.ts and ./preloader.ts
const registrationRef = module.path.charAt(0) === '/'
? yield import(/* webpackIgnore: true */ module.path)
: module.route === 'client'
? yield import('@kui-shell/clien' + webpackPath(module.route).slice(5) + '/mdist/plugin')
: yield import('@kui-shell/plugin-' + webpackPath(module.route) + '/mdist/plugin');
const registration = registrationRef.default || registrationRef;
const combinedOptions = Object.assign({ usage: prescan.usage, docs: prescan.docs }, options);
resolve(registration(proxy(route), combinedOptions));
}
catch (err) {
console.error(`prequire error ${route}`, err);
reject(err);
}
}
else {
reject(new Error(`Internal error: plugin ${route} not found`));
}
}));
}
}
catch (err) {
debug('prequire failure', route);
console.error(err);
}
return registrar[route];
});
/**
* Make a plugin resolver from a given prescan model
*
*/
export const makeResolver = (prescan, registrar) => {
/** memoize resolved plugins */
const isResolved = {};
/** resolve one given plugin */
const resolveOne = (plugin) => __awaiter(void 0, void 0, void 0, function* () {
try {
if (!plugin) {
return;
}
else if (!isResolved[plugin]) {
// eslint-disable-next-line no-async-promise-executor
isResolved[plugin] = new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
try {
const prereqs = prescan.topological[plugin];
if (prereqs) {
yield Promise.all(prereqs.map(route => prequire(route, prescan, registrar)));
}
const loadedPlugin = prequire(plugin, prescan, registrar);
resolve(loadedPlugin);
}
catch (err) {
console.error(`Error resolving plugin ${plugin}`, err);
reject(err);
}
}));
}
// NOTE: even if isResolved[plugin] already has an entry, we may
// need to wait for it to complete, if there is a race between
// two threads trying to load the plugin
return isResolved[plugin];
}
finally {
// debug('resolveOne done', plugin)
}
}); /* resolveOne */
/** a plugin resolver impl */
const resolver = {
isOverridden: (route) => prescan.overrides[route] !== undefined,
isAlpha: (route, plugin) => prescan.overrides[route] === undefined || prescan.overrides[route] === plugin,
resolveOne,
disambiguate: (command) => {
return prescan.disambiguator[command];
},
/** given a partial command, do we have a disambiguation of it? e.g. "gr" => "grid" */
disambiguatePartial: (partial) => {
const matches = [];
if (prescan.disambiguator) {
for (const command in prescan.disambiguator) {
if (command.indexOf(partial) === 0) {
// const { route, plugin } = prescan.disambiguator[command]
matches.push(command);
}
}
}
return matches;
},
/** load any plugins required by the given command */
resolve: (command, { subtree = false, tryCatchalls = true } = {}) => __awaiter(void 0, void 0, void 0, function* () {
// subpath if we are looking for plugins for a subtree, e.g. for cd /auth
let plugin;
let matchLen;
for (const route in prescan.commandToPlugin) {
if (route === command) {
plugin = prescan.commandToPlugin[route];
break;
}
else if (subtree ? route.indexOf(command) === 0 : command.indexOf(`${route}/`) === 0) {
if (!matchLen || route.length > matchLen) {
plugin = prescan.commandToPlugin[route];
matchLen = route.length;
}
}
}
if (plugin) {
yield resolveOne(plugin);
}
else if (prescan.catchalls.length > 0 && tryCatchalls) {
// see if we have catchall
yield Promise.all(prescan.catchalls.map(_ => resolveOne(_.plugin))).catch(err => {
console.error('There seems to be an inconsistency in the prescan model versus the current state of the filesystem: the prescan model refers to a catchall that cannot currently be found', err);
// Note: we hope for the best, and intentionally don't
// rethrow the error. the upstream, in plugin.ts where it
// calls resolver.resolve(), will handle the catastrophe
// (which, at worst, will be a "command not found"), if it
// ensues
});
}
})
}; /* resolver */
return resolver;
};
//# sourceMappingURL=resolver.js.map