Support plugins that contain a scope in their name (#1427)
Summary: Pull Request resolved: https://github.com/facebook/flipper/pull/1427 Reviewed By: mweststrate Differential Revision: D22868784 fbshipit-source-id: c332e5b05e3fccb74cf5fdcdecf15b8f2e8c5006
This commit is contained in:
committed by
Facebook GitHub Bot
parent
14e6b1078d
commit
7e84c8e880
@@ -8,7 +8,7 @@
|
||||
"description": "The name of the package. Must start with \"flipper-plugin-\" prefix.",
|
||||
"type": "string",
|
||||
"maxLength": 214,
|
||||
"pattern": "^flipper-plugin-[a-z0-9-._~]*$",
|
||||
"pattern": "^(?:@[a-z0-9-*~][a-z0-9-*._~]*/)?flipper-plugin-[a-z0-9-._~]*$",
|
||||
"errorMessage": "should start with \"flipper-plugin-\", e.g. \"flipper-plugin-example\""
|
||||
},
|
||||
"id": {
|
||||
|
||||
@@ -48,6 +48,15 @@ test('valid package json', async () => {
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
|
||||
test('valid scoped package json', async () => {
|
||||
const testPackageJson = Object.assign({}, validPackageJson);
|
||||
testPackageJson.name = '@test/flipper-plugin-package';
|
||||
const json = JSON.stringify(testPackageJson);
|
||||
fs.readFile = jest.fn().mockResolvedValue(new Buffer(json));
|
||||
const result = await runLint('dir');
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
|
||||
test('$schema field is required', async () => {
|
||||
const testPackageJson = Object.assign({}, validPackageJson);
|
||||
delete testPackageJson.$schema;
|
||||
|
||||
@@ -45,11 +45,21 @@ function getPluginPendingInstallationDir(
|
||||
}
|
||||
|
||||
function getPluginPendingInstallationsDir(name: string): string {
|
||||
return path.join(pluginPendingInstallationDir, name);
|
||||
return path.join(
|
||||
pluginPendingInstallationDir,
|
||||
replaceInvalidPathSegmentCharacters(name),
|
||||
);
|
||||
}
|
||||
|
||||
function getPluginInstallationDir(name: string): string {
|
||||
return path.join(pluginInstallationDir, name);
|
||||
return path.join(
|
||||
pluginInstallationDir,
|
||||
replaceInvalidPathSegmentCharacters(name),
|
||||
);
|
||||
}
|
||||
|
||||
function replaceInvalidPathSegmentCharacters(name: string) {
|
||||
return name.replace('/', '__');
|
||||
}
|
||||
|
||||
async function installPluginFromTempDir(
|
||||
@@ -145,7 +155,10 @@ export async function installPluginFromNpm(name: string) {
|
||||
const plugManNoDep = providePluginManagerNoDependencies();
|
||||
plugManNoDep.options.pluginsPath = tmpDir;
|
||||
await plugManNoDep.install(name);
|
||||
const pluginTempDir = path.join(tmpDir, name);
|
||||
const pluginTempDir = path.join(
|
||||
tmpDir,
|
||||
replaceInvalidPathSegmentCharacters(name),
|
||||
);
|
||||
await installPluginFromTempDir(pluginTempDir);
|
||||
} finally {
|
||||
await fs.remove(tmpDir);
|
||||
@@ -178,14 +191,15 @@ export async function getInstalledPlugins(): Promise<PluginMap> {
|
||||
const dirs = await fs.readdir(pluginInstallationDir);
|
||||
const plugins = await Promise.all<[string, PluginDetails]>(
|
||||
dirs.map(
|
||||
(name) =>
|
||||
(dirName) =>
|
||||
new Promise(async (resolve, reject) => {
|
||||
const pluginDir = path.join(pluginInstallationDir, name);
|
||||
const pluginDir = path.join(pluginInstallationDir, dirName);
|
||||
if (!(await fs.lstat(pluginDir)).isDirectory()) {
|
||||
return resolve(undefined);
|
||||
}
|
||||
try {
|
||||
resolve([name, await getPluginDetails(pluginDir)]);
|
||||
const details = await getPluginDetails(pluginDir);
|
||||
resolve([details.name, details]);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
@@ -203,24 +217,25 @@ export async function getPendingInstallationPlugins(): Promise<PluginMap> {
|
||||
const dirs = await fs.readdir(pluginPendingInstallationDir);
|
||||
const plugins = await Promise.all<[string, PluginDetails]>(
|
||||
dirs.map(
|
||||
(name) =>
|
||||
(dirName) =>
|
||||
new Promise(async (resolve, reject) => {
|
||||
const versions = (
|
||||
await fs.readdir(path.join(pluginPendingInstallationDir, name))
|
||||
await fs.readdir(path.join(pluginPendingInstallationDir, dirName))
|
||||
).sort((v1, v2) => semver.compare(v2, v1, true));
|
||||
if (versions.length === 0) {
|
||||
return resolve(undefined);
|
||||
}
|
||||
const pluginDir = path.join(
|
||||
pluginPendingInstallationDir,
|
||||
name,
|
||||
dirName,
|
||||
versions[0],
|
||||
);
|
||||
if (!(await fs.lstat(pluginDir)).isDirectory()) {
|
||||
return resolve(undefined);
|
||||
}
|
||||
try {
|
||||
resolve([name, await getPluginDetails(pluginDir)]);
|
||||
const details = await getPluginDetails(pluginDir);
|
||||
resolve([details.name, details]);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
@@ -244,7 +259,7 @@ export async function getPendingAndInstalledPlugins(): Promise<PluginMap> {
|
||||
}
|
||||
|
||||
export async function removePlugin(name: string): Promise<void> {
|
||||
await fs.remove(path.join(pluginInstallationDir, name));
|
||||
await fs.remove(getPluginInstallationDir(name));
|
||||
}
|
||||
|
||||
export async function finishPendingPluginInstallations() {
|
||||
|
||||
Reference in New Issue
Block a user