(configData: AppConfigData, extensionPath: string)
| 65 | * @param extensionPath Path to extensions folder |
| 66 | */ |
| 67 | export async function scanExtensions(configData: AppConfigData, extensionPath: string): Promise<IExtension[]> { |
| 68 | const result = new Map<string, IExtension>(); |
| 69 | |
| 70 | // TODO: System extensions (?) |
| 71 | |
| 72 | // User extensions |
| 73 | const userExtPath = path.resolve(extensionPath); |
| 74 | await fs.promises.access(userExtPath, fs.constants.F_OK | fs.constants.R_OK) |
| 75 | .then(() => {/** Folder exists */}) |
| 76 | .catch(() => fs.promises.mkdir(userExtPath)); |
| 77 | await fsPromises.readdir(userExtPath) |
| 78 | .then(filenames => { |
| 79 | // Each folder inside is an Extension |
| 80 | return Promise.all(filenames.map(async filename => { |
| 81 | // Make sure it is a folder or symlink folder |
| 82 | const stats = await fs.promises.stat(path.join(userExtPath, filename)); |
| 83 | if (!stats.isDirectory()) { return; } |
| 84 | // Read Manifest |
| 85 | const manifestPath = path.join(userExtPath, filename, 'package.json'); |
| 86 | return fsPromises.stat(manifestPath) |
| 87 | .then(async (stats) => { |
| 88 | // Manifest file (package.json) exists, continue loading extension |
| 89 | if (stats.isFile()) { |
| 90 | await fsPromises.access(manifestPath); |
| 91 | const ext = await parseExtension(manifestPath, ExtensionType.User); |
| 92 | if (UNSUPPORTED_EXTENSION_IDS.includes(ext.id)) { |
| 93 | log.warn('Extensions', `Ignoring Extension ${ext.id} because of replacement with system extension.`); |
| 94 | return; |
| 95 | } |
| 96 | if (result.get(ext.id) !== undefined) { |
| 97 | // An Extension with the same id has been registered earlier, latest read survives |
| 98 | log.warn('Extensions', `Overriding Extension ${ext.id} with extension at "${path.join(userExtPath, filename)}"`); |
| 99 | } |
| 100 | result.set(ext.id, ext); |
| 101 | } |
| 102 | }) |
| 103 | .catch(err => log.error('Extensions', `Error loading User extension at "${filename}"\n${err}`)); |
| 104 | })); |
| 105 | }); |
| 106 | |
| 107 | // Convert the map to an array and return |
| 108 | const r: IExtension[] = []; |
| 109 | result.forEach((ext) => { |
| 110 | log.debug('Extensions', `Extension Scanned "${ext.manifest.displayName || ext.manifest.name}" (${ext.id})`); |
| 111 | r.push(ext); |
| 112 | }); |
| 113 | return r; |
| 114 | } |
| 115 | |
| 116 | /** |
| 117 | * Returns the extensions ID given its author and name from its manifest |
no test coverage detected