Skip to content

Commit aa8dbfb

Browse files
committed
feat(cli-plugin-scaffold-extensions): add link-extensions command
1 parent 8c7f12e commit aa8dbfb

File tree

11 files changed

+338
-171
lines changed

11 files changed

+338
-171
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const defaultConfig = require("../../.eslintrc");
2+
3+
module.exports = {
4+
...defaultConfig,
5+
rules: {
6+
...defaultConfig.rules,
7+
"import/dynamic-import-chunkname": 0
8+
}
9+
};

packages/cli-plugin-scaffold-extensions/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"@webiny/error": "0.0.0",
2525
"case": "^1.6.3",
2626
"execa": "^5.0.0",
27+
"glob": "^7.1.2",
2728
"load-json-file": "^6.2.0",
2829
"ncp": "^2.0.0",
2930
"replace-in-path": "^1.1.0",
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import fs from "fs";
2+
import path from "path";
3+
import { formatCode } from "@webiny/cli-plugin-scaffold/utils";
4+
import { ExtensionWorkspace } from "./getExtensionsFromFilesystem";
5+
6+
export const generateAdminExtensions = async (extensions: ExtensionWorkspace[]) => {
7+
const extensionsFilePath = path.join("apps", "admin", "src", "Extensions.tsx");
8+
9+
const code: string[][] = [];
10+
11+
extensions.forEach(extension => {
12+
const name = path.basename(extension.path);
13+
const ucFirstName = name.charAt(0).toUpperCase() + name.slice(1);
14+
const componentName = ucFirstName + "Extension";
15+
const importStatement = `import { Extension as ${componentName}} from "${extension.packageJson.name}";`;
16+
code.push([importStatement, `<${componentName}/>`]);
17+
});
18+
19+
const extensionsFile = [
20+
`// This file is automatically updated via scaffolding utilities.`,
21+
`import React from "react";`,
22+
...code.map(ext => ext[0]),
23+
"",
24+
`export const Extensions = () => { return (<>${code.map(ext => ext[1]).join("\n")}</>); };`
25+
];
26+
27+
fs.writeFileSync(extensionsFilePath, extensionsFile.join("\n"));
28+
29+
await formatCode(extensionsFilePath, {});
30+
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import fs from "fs";
2+
import path from "path";
3+
import { formatCode } from "@webiny/cli-plugin-scaffold/utils";
4+
import { ExtensionWorkspace } from "./getExtensionsFromFilesystem";
5+
6+
export const generateApiExtensions = async (extensions: ExtensionWorkspace[]) => {
7+
const extensionsFilePath = path.join("apps", "api", "graphql", "src", "extensions.ts");
8+
const code: string[][] = [];
9+
10+
extensions.forEach(extension => {
11+
const name = path.basename(extension.path);
12+
const extensionFactory = name + "ExtensionFactory";
13+
const importStatement = `import { createExtension as ${extensionFactory}} from "${extension.packageJson.name}";`;
14+
code.push([importStatement, `${extensionFactory}()`]);
15+
});
16+
17+
const extensionsFile = [
18+
"// This file is automatically updated via scaffolding utilities.",
19+
...code.map(ext => ext[0]),
20+
"export const extensions = () => {",
21+
"return [",
22+
code.map(ext => ext[1]).join(","),
23+
"];};"
24+
];
25+
26+
fs.writeFileSync(extensionsFilePath, extensionsFile.join("\n"));
27+
28+
await formatCode(extensionsFilePath, {});
29+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import loadJson from "load-json-file";
2+
import glob from "glob";
3+
import path from "path";
4+
import { PackageJson } from "@webiny/cli-plugin-scaffold/types";
5+
6+
export type ExtensionType = "api" | "admin" | undefined;
7+
8+
export type ExtensionWorkspace = {
9+
path: string;
10+
type: ExtensionType;
11+
packageJson: PackageJson;
12+
};
13+
14+
export const getExtensionsFromFilesystem = (): ExtensionWorkspace[] => {
15+
const workspaces = glob.sync(`extensions/**/package.json`);
16+
return workspaces
17+
.map(pkg => ({
18+
path: path.dirname(pkg),
19+
packageJson: loadJson.sync<PackageJson>(pkg)
20+
}))
21+
.map(workspace => {
22+
const typeKeyword = (workspace.packageJson.keywords || []).find(kw => {
23+
return kw.startsWith("webiny-extension-type:");
24+
});
25+
26+
const type = (typeKeyword ? typeKeyword.split(":")[1] : undefined) as ExtensionType;
27+
28+
return {
29+
...workspace,
30+
type
31+
};
32+
});
33+
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { getExtensionsFromFilesystem } from "./getExtensionsFromFilesystem";
2+
import { generateApiExtensions } from "./generateApiExtensions";
3+
import { generateAdminExtensions } from "./generateAdminExtensions";
4+
import { registerWorkspaces } from "./registerWorkspaces";
5+
6+
export const linkAllExtensions = async () => {
7+
const allExtensions = getExtensionsFromFilesystem();
8+
const apiExtensions = allExtensions.filter(extension => extension.type === "api");
9+
const adminExtensions = allExtensions.filter(extension => extension.type === "admin");
10+
11+
await Promise.all([
12+
generateApiExtensions(apiExtensions),
13+
generateAdminExtensions(adminExtensions),
14+
registerWorkspaces(allExtensions)
15+
]);
16+
};
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import execa from "execa";
2+
import loadJson from "load-json-file";
3+
import writeJson from "write-json-file";
4+
import type { ExtensionWorkspace } from "./getExtensionsFromFilesystem";
5+
import { PackageJson } from "@webiny/cli-plugin-scaffold/types";
6+
import { formatCode } from "@webiny/cli-plugin-scaffold/utils";
7+
8+
export const registerWorkspaces = async (extensions: ExtensionWorkspace[]) => {
9+
const packageJsonPath = "package.json";
10+
const rootPkgJson = await loadJson<PackageJson>(packageJsonPath);
11+
12+
extensions.forEach(extension => {
13+
const workspacePath = extension.path.replace(`${process.cwd()}/`, "");
14+
15+
if (!rootPkgJson.workspaces.packages.includes(workspacePath)) {
16+
rootPkgJson.workspaces.packages.push(workspacePath);
17+
}
18+
});
19+
20+
await writeJson(packageJsonPath, rootPkgJson);
21+
await formatCode(packageJsonPath, {});
22+
23+
await execa("yarn");
24+
};

0 commit comments

Comments
 (0)