@webiny/project 0.0.0-unstable.6f45466a1d → 0.0.0-unstable.dbdf5d6258
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/Wcp.d.ts +17 -0
- package/components/Wcp.js +41 -0
- package/components/Wcp.js.map +1 -0
- package/defineExtension/createExtensionReactComponent.js +2 -6
- package/defineExtension/createExtensionReactComponent.js.map +1 -1
- package/defineExtension/index.d.ts +0 -1
- package/defineExtension/index.js +0 -1
- package/defineExtension/index.js.map +1 -1
- package/defineExtension/zodTypes/zodSrcPath.d.ts +1 -0
- package/defineExtension/zodTypes/zodSrcPath.js +7 -14
- package/defineExtension/zodTypes/zodSrcPath.js.map +1 -1
- package/exports/extensions.d.ts +1 -0
- package/exports/extensions.js +1 -0
- package/exports/extensions.js.map +1 -1
- package/extensions/AdminBuildParam.d.ts +11 -0
- package/extensions/AdminBuildParam.js +184 -0
- package/extensions/AdminBuildParam.js.map +1 -0
- package/extensions/AdminExtension.d.ts +11 -0
- package/extensions/AdminExtension.js +99 -0
- package/extensions/AdminExtension.js.map +1 -0
- package/extensions/ApiBuildParam.d.ts +11 -0
- package/extensions/ApiBuildParam.js +119 -0
- package/extensions/ApiBuildParam.js.map +1 -0
- package/extensions/ApiExtension.d.ts +11 -0
- package/{defineExtension/defineApiExtension.js → extensions/ApiExtension.js} +14 -22
- package/extensions/ApiExtension.js.map +1 -0
- package/extensions/FeatureFlags.d.ts +85 -0
- package/extensions/FeatureFlags.js +42 -0
- package/extensions/FeatureFlags.js.map +1 -0
- package/extensions/index.d.ts +102 -0
- package/extensions/index.js +12 -2
- package/extensions/index.js.map +1 -1
- package/index.d.ts +3 -0
- package/index.js +3 -0
- package/index.js.map +1 -1
- package/package.json +18 -18
- package/services/GetProjectConfigService/WcpProjectLicenseContext.d.ts +13 -0
- package/services/GetProjectConfigService/WcpProjectLicenseContext.js +41 -0
- package/services/GetProjectConfigService/WcpProjectLicenseContext.js.map +1 -0
- package/services/GetProjectConfigService/renderConfigWorker.js +3 -2
- package/services/GetProjectConfigService/renderConfigWorker.js.map +1 -1
- package/services/InitProjectSdkService/registerDecorators.js +2 -2
- package/services/InitProjectSdkService/registerDecorators.js.map +1 -1
- package/services/InitProjectSdkService/registerHooks.js +2 -2
- package/services/InitProjectSdkService/registerHooks.js.map +1 -1
- package/services/InitProjectSdkService/registerImplementations.js +2 -2
- package/services/InitProjectSdkService/registerImplementations.js.map +1 -1
- package/services/InitProjectSdkService/registerPulumiExtensions.js +2 -2
- package/services/InitProjectSdkService/registerPulumiExtensions.js.map +1 -1
- package/services/InstallExtensionService/InstallExtensionService.d.ts +1 -1
- package/services/InstallExtensionService/InstallExtensionService.js +24 -10
- package/services/InstallExtensionService/InstallExtensionService.js.map +1 -1
- package/services/InstallExtensionService/mergePackageJson.js +4 -4
- package/services/InstallExtensionService/mergePackageJson.js.map +1 -1
- package/services/InstallExtensionService/updateWebinyConfig.js +46 -1
- package/services/InstallExtensionService/updateWebinyConfig.js.map +1 -1
- package/services/ListAppLambdaFunctionsService/ListAppLambdaFunctionsService.js +1 -1
- package/services/ListAppLambdaFunctionsService/ListAppLambdaFunctionsService.js.map +1 -1
- package/utils/ExtensionSrcResolver.d.ts +33 -0
- package/utils/ExtensionSrcResolver.js +119 -0
- package/utils/ExtensionSrcResolver.js.map +1 -0
- package/utils/index.d.ts +1 -1
- package/utils/index.js +1 -1
- package/utils/index.js.map +1 -1
- package/defineExtension/defineApiExtension.d.ts +0 -17
- package/defineExtension/defineApiExtension.js.map +0 -1
- package/utils/ImplPathResolver.d.ts +0 -10
- package/utils/ImplPathResolver.js +0 -27
- package/utils/ImplPathResolver.js.map +0 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface ChildrenProps {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
}
|
|
5
|
+
declare function CanUseMultiTenancy({ children }: ChildrenProps): React.JSX.Element | null;
|
|
6
|
+
declare function CanUseTeams({ children }: ChildrenProps): React.JSX.Element | null;
|
|
7
|
+
declare function CanUsePrivateFiles({ children }: ChildrenProps): React.JSX.Element | null;
|
|
8
|
+
declare function CanUseFileManagerThreatDetection({ children }: ChildrenProps): React.JSX.Element | null;
|
|
9
|
+
declare function CanUseWorkflows({ children }: ChildrenProps): React.JSX.Element | null;
|
|
10
|
+
export declare const Wcp: {
|
|
11
|
+
CanUseMultiTenancy: typeof CanUseMultiTenancy;
|
|
12
|
+
CanUseTeams: typeof CanUseTeams;
|
|
13
|
+
CanUsePrivateFiles: typeof CanUsePrivateFiles;
|
|
14
|
+
CanUseFileManagerThreatDetection: typeof CanUseFileManagerThreatDetection;
|
|
15
|
+
CanUseWorkflows: typeof CanUseWorkflows;
|
|
16
|
+
};
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useWcpProjectLicense } from "../services/GetProjectConfigService/WcpProjectLicenseContext.js";
|
|
3
|
+
function CanUseMultiTenancy({
|
|
4
|
+
children
|
|
5
|
+
}) {
|
|
6
|
+
const wcp = useWcpProjectLicense();
|
|
7
|
+
return wcp.canUseMultiTenancy() ? /*#__PURE__*/React.createElement(React.Fragment, null, children) : null;
|
|
8
|
+
}
|
|
9
|
+
function CanUseTeams({
|
|
10
|
+
children
|
|
11
|
+
}) {
|
|
12
|
+
const wcp = useWcpProjectLicense();
|
|
13
|
+
return wcp.canUseTeams() ? /*#__PURE__*/React.createElement(React.Fragment, null, children) : null;
|
|
14
|
+
}
|
|
15
|
+
function CanUsePrivateFiles({
|
|
16
|
+
children
|
|
17
|
+
}) {
|
|
18
|
+
const wcp = useWcpProjectLicense();
|
|
19
|
+
return wcp.canUsePrivateFiles() ? /*#__PURE__*/React.createElement(React.Fragment, null, children) : null;
|
|
20
|
+
}
|
|
21
|
+
function CanUseFileManagerThreatDetection({
|
|
22
|
+
children
|
|
23
|
+
}) {
|
|
24
|
+
const wcp = useWcpProjectLicense();
|
|
25
|
+
return wcp.canUseFileManagerThreatDetection() ? /*#__PURE__*/React.createElement(React.Fragment, null, children) : null;
|
|
26
|
+
}
|
|
27
|
+
function CanUseWorkflows({
|
|
28
|
+
children
|
|
29
|
+
}) {
|
|
30
|
+
const wcp = useWcpProjectLicense();
|
|
31
|
+
return wcp.canUseWorkflows() ? /*#__PURE__*/React.createElement(React.Fragment, null, children) : null;
|
|
32
|
+
}
|
|
33
|
+
export const Wcp = {
|
|
34
|
+
CanUseMultiTenancy,
|
|
35
|
+
CanUseTeams,
|
|
36
|
+
CanUsePrivateFiles,
|
|
37
|
+
CanUseFileManagerThreatDetection,
|
|
38
|
+
CanUseWorkflows
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=Wcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["React","useWcpProjectLicense","CanUseMultiTenancy","children","wcp","canUseMultiTenancy","createElement","Fragment","CanUseTeams","canUseTeams","CanUsePrivateFiles","canUsePrivateFiles","CanUseFileManagerThreatDetection","canUseFileManagerThreatDetection","CanUseWorkflows","canUseWorkflows","Wcp"],"sources":["Wcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { useWcpProjectLicense } from \"~/services/GetProjectConfigService/WcpProjectLicenseContext.js\";\n\ninterface ChildrenProps {\n children: React.ReactNode;\n}\n\nfunction CanUseMultiTenancy({ children }: ChildrenProps) {\n const wcp = useWcpProjectLicense();\n\n return wcp.canUseMultiTenancy() ? <>{children}</> : null;\n}\n\nfunction CanUseTeams({ children }: ChildrenProps) {\n const wcp = useWcpProjectLicense();\n\n return wcp.canUseTeams() ? <>{children}</> : null;\n}\n\nfunction CanUsePrivateFiles({ children }: ChildrenProps) {\n const wcp = useWcpProjectLicense();\n\n return wcp.canUsePrivateFiles() ? <>{children}</> : null;\n}\n\nfunction CanUseFileManagerThreatDetection({ children }: ChildrenProps) {\n const wcp = useWcpProjectLicense();\n\n return wcp.canUseFileManagerThreatDetection() ? <>{children}</> : null;\n}\n\nfunction CanUseWorkflows({ children }: ChildrenProps) {\n const wcp = useWcpProjectLicense();\n\n return wcp.canUseWorkflows() ? <>{children}</> : null;\n}\n\nexport const Wcp = {\n CanUseMultiTenancy,\n CanUseTeams,\n CanUsePrivateFiles,\n CanUseFileManagerThreatDetection,\n CanUseWorkflows\n};\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,oBAAoB;AAM7B,SAASC,kBAAkBA,CAAC;EAAEC;AAAwB,CAAC,EAAE;EACrD,MAAMC,GAAG,GAAGH,oBAAoB,CAAC,CAAC;EAElC,OAAOG,GAAG,CAACC,kBAAkB,CAAC,CAAC,gBAAGL,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AAC5D;AAEA,SAASK,WAAWA,CAAC;EAAEL;AAAwB,CAAC,EAAE;EAC9C,MAAMC,GAAG,GAAGH,oBAAoB,CAAC,CAAC;EAElC,OAAOG,GAAG,CAACK,WAAW,CAAC,CAAC,gBAAGT,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AACrD;AAEA,SAASO,kBAAkBA,CAAC;EAAEP;AAAwB,CAAC,EAAE;EACrD,MAAMC,GAAG,GAAGH,oBAAoB,CAAC,CAAC;EAElC,OAAOG,GAAG,CAACO,kBAAkB,CAAC,CAAC,gBAAGX,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AAC5D;AAEA,SAASS,gCAAgCA,CAAC;EAAET;AAAwB,CAAC,EAAE;EACnE,MAAMC,GAAG,GAAGH,oBAAoB,CAAC,CAAC;EAElC,OAAOG,GAAG,CAACS,gCAAgC,CAAC,CAAC,gBAAGb,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AAC1E;AAEA,SAASW,eAAeA,CAAC;EAAEX;AAAwB,CAAC,EAAE;EAClD,MAAMC,GAAG,GAAGH,oBAAoB,CAAC,CAAC;EAElC,OAAOG,GAAG,CAACW,eAAe,CAAC,CAAC,gBAAGf,KAAA,CAAAM,aAAA,CAAAN,KAAA,CAAAO,QAAA,QAAGJ,QAAW,CAAC,GAAG,IAAI;AACzD;AAEA,OAAO,MAAMa,GAAG,GAAG;EACfd,kBAAkB;EAClBM,WAAW;EACXE,kBAAkB;EAClBE,gCAAgC;EAChCE;AACJ,CAAC","ignoreList":[]}
|
|
@@ -13,10 +13,6 @@ const KeyValues = props => {
|
|
|
13
13
|
};
|
|
14
14
|
export function createExtensionReactComponent(extensionParams) {
|
|
15
15
|
const ExtensionReactComponent = props => {
|
|
16
|
-
// If custom render function is provided, use it.
|
|
17
|
-
if (extensionParams.render) {
|
|
18
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, extensionParams.render(props));
|
|
19
|
-
}
|
|
20
16
|
const {
|
|
21
17
|
name,
|
|
22
18
|
remove,
|
|
@@ -39,14 +35,14 @@ export function createExtensionReactComponent(extensionParams) {
|
|
|
39
35
|
|
|
40
36
|
// @ts-expect-error move KeyValues back inside the Property component to avoid this error
|
|
41
37
|
const KeyValuesComponent = parentProps => /*#__PURE__*/React.createElement(KeyValues, Object.assign({}, parentProps, keyValues));
|
|
42
|
-
return /*#__PURE__*/React.createElement(Property, {
|
|
38
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Property, {
|
|
43
39
|
id: propertyId,
|
|
44
40
|
name: propertyName,
|
|
45
41
|
array: extensionParams.multiple,
|
|
46
42
|
remove: remove,
|
|
47
43
|
before: placeBefore,
|
|
48
44
|
after: placeAfter
|
|
49
|
-
}, /*#__PURE__*/React.createElement(KeyValuesComponent, null));
|
|
45
|
+
}, /*#__PURE__*/React.createElement(KeyValuesComponent, null)), extensionParams.render && extensionParams.render(props));
|
|
50
46
|
};
|
|
51
47
|
ExtensionReactComponent.displayName = `ExtensionReactComponent(${extensionParams.type})`;
|
|
52
48
|
return ExtensionReactComponent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","useMemo","Property","useIdGenerator","KeyValues","props","getId","Object","entries","map","key","value","createElement","name","id","createExtensionReactComponent","extensionParams","ExtensionReactComponent","
|
|
1
|
+
{"version":3,"names":["React","useMemo","Property","useIdGenerator","KeyValues","props","getId","Object","entries","map","key","value","createElement","name","id","createExtensionReactComponent","extensionParams","ExtensionReactComponent","remove","before","after","keyValues","type","propertyId","multiple","undefined","propertyName","placeAfter","placeBefore","KeyValuesComponent","parentProps","assign","Fragment","array","render","displayName"],"sources":["createExtensionReactComponent.tsx"],"sourcesContent":["import React, { useMemo } from \"react\";\nimport { Property, useIdGenerator } from \"@webiny/react-properties\";\nimport { type DefineExtensionParams } from \"./types.js\";\nimport { type z } from \"zod\";\n\nconst KeyValues = (props: Record<string, any>) => {\n const getId = useIdGenerator(\"\");\n return Object.entries(props).map(([key, value]) => {\n return <Property key={key} name={key} id={getId(key)} value={value} />;\n });\n};\n\ntype ExtensionReactComponentProps<TParamsSchema extends z.ZodTypeAny> = z.infer<TParamsSchema> & {\n remove?: boolean;\n before?: string;\n after?: string;\n name?: string;\n};\n\nexport function createExtensionReactComponent<TParamsSchema extends z.ZodTypeAny>(\n extensionParams: DefineExtensionParams<TParamsSchema>\n) {\n const ExtensionReactComponent: React.FC<\n ExtensionReactComponentProps<TParamsSchema>\n > = props => {\n const { name, remove, before, after, ...keyValues } = props;\n\n const getId = useIdGenerator(extensionParams.type);\n\n // By passing undefined, we're letting RP generate a unique ID for us.\n const propertyId = useMemo(() => {\n if (extensionParams.multiple) {\n return name ? getId(name) : undefined;\n }\n\n return getId(extensionParams.type);\n }, [name, extensionParams.multiple, getId]);\n\n const propertyName = name || extensionParams.type;\n\n const placeAfter = after !== undefined ? getId(after) : undefined;\n const placeBefore = before !== undefined ? getId(before) : undefined;\n\n // @ts-expect-error move KeyValues back inside the Property component to avoid this error\n const KeyValuesComponent = parentProps => <KeyValues {...parentProps} {...keyValues} />;\n\n return (\n <>\n <Property\n id={propertyId}\n name={propertyName}\n array={extensionParams.multiple}\n remove={remove}\n before={placeBefore}\n after={placeAfter}\n >\n <KeyValuesComponent />\n </Property>\n {extensionParams.render && extensionParams.render(props)}\n </>\n );\n };\n\n ExtensionReactComponent.displayName = `ExtensionReactComponent(${extensionParams.type})`;\n return ExtensionReactComponent;\n}\n"],"mappings":"AAAA,OAAOA,KAAK,IAAIC,OAAO,QAAQ,OAAO;AACtC,SAASC,QAAQ,EAAEC,cAAc,QAAQ,0BAA0B;AAInE,MAAMC,SAAS,GAAIC,KAA0B,IAAK;EAC9C,MAAMC,KAAK,GAAGH,cAAc,CAAC,EAAE,CAAC;EAChC,OAAOI,MAAM,CAACC,OAAO,CAACH,KAAK,CAAC,CAACI,GAAG,CAAC,CAAC,CAACC,GAAG,EAAEC,KAAK,CAAC,KAAK;IAC/C,oBAAOX,KAAA,CAAAY,aAAA,CAACV,QAAQ;MAACQ,GAAG,EAAEA,GAAI;MAACG,IAAI,EAAEH,GAAI;MAACI,EAAE,EAAER,KAAK,CAACI,GAAG,CAAE;MAACC,KAAK,EAAEA;IAAM,CAAE,CAAC;EAC1E,CAAC,CAAC;AACN,CAAC;AASD,OAAO,SAASI,6BAA6BA,CACzCC,eAAqD,EACvD;EACE,MAAMC,uBAEL,GAAGZ,KAAK,IAAI;IACT,MAAM;MAAEQ,IAAI;MAAEK,MAAM;MAAEC,MAAM;MAAEC,KAAK;MAAE,GAAGC;IAAU,CAAC,GAAGhB,KAAK;IAE3D,MAAMC,KAAK,GAAGH,cAAc,CAACa,eAAe,CAACM,IAAI,CAAC;;IAElD;IACA,MAAMC,UAAU,GAAGtB,OAAO,CAAC,MAAM;MAC7B,IAAIe,eAAe,CAACQ,QAAQ,EAAE;QAC1B,OAAOX,IAAI,GAAGP,KAAK,CAACO,IAAI,CAAC,GAAGY,SAAS;MACzC;MAEA,OAAOnB,KAAK,CAACU,eAAe,CAACM,IAAI,CAAC;IACtC,CAAC,EAAE,CAACT,IAAI,EAAEG,eAAe,CAACQ,QAAQ,EAAElB,KAAK,CAAC,CAAC;IAE3C,MAAMoB,YAAY,GAAGb,IAAI,IAAIG,eAAe,CAACM,IAAI;IAEjD,MAAMK,UAAU,GAAGP,KAAK,KAAKK,SAAS,GAAGnB,KAAK,CAACc,KAAK,CAAC,GAAGK,SAAS;IACjE,MAAMG,WAAW,GAAGT,MAAM,KAAKM,SAAS,GAAGnB,KAAK,CAACa,MAAM,CAAC,GAAGM,SAAS;;IAEpE;IACA,MAAMI,kBAAkB,GAAGC,WAAW,iBAAI9B,KAAA,CAAAY,aAAA,CAACR,SAAS,EAAAG,MAAA,CAAAwB,MAAA,KAAKD,WAAW,EAAMT,SAAS,CAAG,CAAC;IAEvF,oBACIrB,KAAA,CAAAY,aAAA,CAAAZ,KAAA,CAAAgC,QAAA,qBACIhC,KAAA,CAAAY,aAAA,CAACV,QAAQ;MACLY,EAAE,EAAES,UAAW;MACfV,IAAI,EAAEa,YAAa;MACnBO,KAAK,EAAEjB,eAAe,CAACQ,QAAS;MAChCN,MAAM,EAAEA,MAAO;MACfC,MAAM,EAAES,WAAY;MACpBR,KAAK,EAAEO;IAAW,gBAElB3B,KAAA,CAAAY,aAAA,CAACiB,kBAAkB,MAAE,CACf,CAAC,EACVb,eAAe,CAACkB,MAAM,IAAIlB,eAAe,CAACkB,MAAM,CAAC7B,KAAK,CACzD,CAAC;EAEX,CAAC;EAEDY,uBAAuB,CAACkB,WAAW,GAAG,2BAA2BnB,eAAe,CAACM,IAAI,GAAG;EACxF,OAAOL,uBAAuB;AAClC","ignoreList":[]}
|
package/defineExtension/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["index.ts"],"sourcesContent":["export * from \"./defineExtension.js\";\nexport * from \"./
|
|
1
|
+
{"version":3,"names":[],"sources":["index.ts"],"sourcesContent":["export * from \"./defineExtension.js\";\nexport * from \"./models/index.js\";\nexport * from \"./zodTypes/zodSrcPath.js\";\n"],"mappings":"AAAA;AACA;AACA","ignoreList":[]}
|
|
@@ -4,6 +4,7 @@ import { type IProjectModel } from "../../abstractions/models/index.js";
|
|
|
4
4
|
/**
|
|
5
5
|
* TypeScript type for source paths.
|
|
6
6
|
* - `/extensions/${string}` - resolves from project root
|
|
7
|
+
* - `@/${string}` or other tsconfig aliases - resolves using tsconfig.json paths
|
|
7
8
|
* - string (absolute path) - treated as absolute path
|
|
8
9
|
*/
|
|
9
10
|
export type SrcPath = `/extensions/${string}` | string;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Metadata } from "@webiny/di";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import fs from "fs";
|
|
5
4
|
import { ProjectError } from "../../ProjectError.js";
|
|
6
|
-
import {
|
|
5
|
+
import { ExtensionSrcResolver } from "../../utils/index.js";
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* TypeScript type for source paths.
|
|
10
9
|
* - `/extensions/${string}` - resolves from project root
|
|
10
|
+
* - `@/${string}` or other tsconfig aliases - resolves using tsconfig.json paths
|
|
11
11
|
* - string (absolute path) - treated as absolute path
|
|
12
12
|
*/
|
|
13
13
|
|
|
@@ -21,18 +21,10 @@ export const zodSrcPath = options => {
|
|
|
21
21
|
return str.replace(/^Symbol\(/, "").replace(/\)$/, "");
|
|
22
22
|
};
|
|
23
23
|
const tokenName = abstraction ? getTokenName(abstraction.token) : undefined;
|
|
24
|
-
const description = abstraction ? `Path to a file exporting ${tokenName}. Use "/extensions/..." to resolve from project root, or provide an absolute path.` : `Path: "/extensions/..." resolves from project root, or provide an absolute path.`;
|
|
24
|
+
const description = abstraction ? `Path to a file exporting ${tokenName}. Use "/extensions/..." to resolve from project root, "@/..." for tsconfig path aliases, or provide an absolute path.` : `Path: "/extensions/..." resolves from project root, "@/..." resolves using tsconfig path aliases, or provide an absolute path.`;
|
|
25
25
|
return z.string().describe(description).transform(val => val).superRefine(async (src, ctx) => {
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
if (src.startsWith("/extensions/")) {
|
|
29
|
-
// Resolve from project root.
|
|
30
|
-
absoluteSrcPath = project.paths.rootFolder.join(src).toString();
|
|
31
|
-
} else {
|
|
32
|
-
// Treat as absolute path.
|
|
33
|
-
absoluteSrcPath = src;
|
|
34
|
-
}
|
|
35
|
-
if (!fs.existsSync(absoluteSrcPath)) {
|
|
26
|
+
// Check if file exists using ExtensionSrcResolver.
|
|
27
|
+
if (!ExtensionSrcResolver.existsSync(src, project)) {
|
|
36
28
|
ctx.addIssue({
|
|
37
29
|
code: z.ZodIssueCode.custom,
|
|
38
30
|
message: ProjectError.formatMessage(`File not found: %s. Please check the path and try again.`, src)
|
|
@@ -42,8 +34,9 @@ export const zodSrcPath = options => {
|
|
|
42
34
|
|
|
43
35
|
// If abstraction validation is required
|
|
44
36
|
if (abstraction) {
|
|
37
|
+
const absoluteSrcPath = ExtensionSrcResolver.resolvePath(src, project);
|
|
45
38
|
const exportName = path.basename(absoluteSrcPath).replace(path.extname(absoluteSrcPath), "");
|
|
46
|
-
const exportedImplementation = await
|
|
39
|
+
const exportedImplementation = await ExtensionSrcResolver.importFromPath(src, project);
|
|
47
40
|
if (!exportedImplementation) {
|
|
48
41
|
ctx.addIssue({
|
|
49
42
|
code: z.ZodIssueCode.custom,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Metadata","z","path","
|
|
1
|
+
{"version":3,"names":["Metadata","z","path","ProjectError","ExtensionSrcResolver","zodSrcPath","options","project","abstraction","getTokenName","token","str","toString","replace","tokenName","undefined","description","string","describe","transform","val","superRefine","src","ctx","existsSync","addIssue","code","ZodIssueCode","custom","message","formatMessage","absoluteSrcPath","resolvePath","exportName","basename","extname","exportedImplementation","importFromPath","metadata","metadataName","getAbstraction","defName","isCorrectAbstraction"],"sources":["zodSrcPath.ts"],"sourcesContent":["import { type Abstraction, Metadata } from \"@webiny/di\";\nimport { z } from \"zod\";\nimport path from \"path\";\nimport { type IProjectModel } from \"~/abstractions/models/index.js\";\nimport { ProjectError } from \"~/ProjectError.js\";\nimport { ExtensionSrcResolver } from \"~/utils/index.js\";\n\n/**\n * TypeScript type for source paths.\n * - `/extensions/${string}` - resolves from project root\n * - `@/${string}` or other tsconfig aliases - resolves using tsconfig.json paths\n * - string (absolute path) - treated as absolute path\n */\nexport type SrcPath = `/extensions/${string}` | string;\n\ntype ZodSrcPathOptions = {\n project: IProjectModel;\n abstraction?: Abstraction<any>;\n};\n\nexport const zodSrcPath = (options: ZodSrcPathOptions) => {\n const { project, abstraction } = options;\n\n const getTokenName = (token: symbol) => {\n const str = token.toString();\n return str.replace(/^Symbol\\(/, \"\").replace(/\\)$/, \"\");\n };\n\n const tokenName = abstraction ? getTokenName(abstraction.token) : undefined;\n const description = abstraction\n ? `Path to a file exporting ${tokenName}. Use \"/extensions/...\" to resolve from project root, \"@/...\" for tsconfig path aliases, or provide an absolute path.`\n : `Path: \"/extensions/...\" resolves from project root, \"@/...\" resolves using tsconfig path aliases, or provide an absolute path.`;\n\n return z\n .string()\n .describe(description)\n .transform((val): SrcPath => val as SrcPath)\n .superRefine(async (src, ctx) => {\n // Check if file exists using ExtensionSrcResolver.\n if (!ExtensionSrcResolver.existsSync(src, project)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: ProjectError.formatMessage(\n `File not found: %s. Please check the path and try again.`,\n src\n )\n });\n return;\n }\n\n // If abstraction validation is required\n if (abstraction) {\n const absoluteSrcPath = ExtensionSrcResolver.resolvePath(src, project);\n const exportName = path\n .basename(absoluteSrcPath)\n .replace(path.extname(absoluteSrcPath), \"\");\n\n const exportedImplementation = await ExtensionSrcResolver.importFromPath(\n src,\n project\n );\n\n if (!exportedImplementation) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: ProjectError.formatMessage(\n `The file %s must export a class named %s or as a default export.`,\n src,\n exportName\n )\n });\n return;\n }\n\n const metadata = new Metadata(exportedImplementation);\n const metadataName = metadata.getAbstraction().toString();\n const defName = abstraction.toString();\n const isCorrectAbstraction = metadataName === defName;\n\n if (!isCorrectAbstraction) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: ProjectError.formatMessage(\n `The class %s in %s must implement the %s interface.`,\n exportName,\n src,\n tokenName || \"\"\n )\n });\n }\n }\n });\n};\n"],"mappings":"AAAA,SAA2BA,QAAQ,QAAQ,YAAY;AACvD,SAASC,CAAC,QAAQ,KAAK;AACvB,OAAOC,IAAI,MAAM,MAAM;AAEvB,SAASC,YAAY;AACrB,SAASC,oBAAoB;;AAE7B;AACA;AACA;AACA;AACA;AACA;;AAQA,OAAO,MAAMC,UAAU,GAAIC,OAA0B,IAAK;EACtD,MAAM;IAAEC,OAAO;IAAEC;EAAY,CAAC,GAAGF,OAAO;EAExC,MAAMG,YAAY,GAAIC,KAAa,IAAK;IACpC,MAAMC,GAAG,GAAGD,KAAK,CAACE,QAAQ,CAAC,CAAC;IAC5B,OAAOD,GAAG,CAACE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAACA,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;EAC1D,CAAC;EAED,MAAMC,SAAS,GAAGN,WAAW,GAAGC,YAAY,CAACD,WAAW,CAACE,KAAK,CAAC,GAAGK,SAAS;EAC3E,MAAMC,WAAW,GAAGR,WAAW,GACzB,4BAA4BM,SAAS,uHAAuH,GAC5J,gIAAgI;EAEtI,OAAOb,CAAC,CACHgB,MAAM,CAAC,CAAC,CACRC,QAAQ,CAACF,WAAW,CAAC,CACrBG,SAAS,CAAEC,GAAG,IAAcA,GAAc,CAAC,CAC3CC,WAAW,CAAC,OAAOC,GAAG,EAAEC,GAAG,KAAK;IAC7B;IACA,IAAI,CAACnB,oBAAoB,CAACoB,UAAU,CAACF,GAAG,EAAEf,OAAO,CAAC,EAAE;MAChDgB,GAAG,CAACE,QAAQ,CAAC;QACTC,IAAI,EAAEzB,CAAC,CAAC0B,YAAY,CAACC,MAAM;QAC3BC,OAAO,EAAE1B,YAAY,CAAC2B,aAAa,CAC/B,0DAA0D,EAC1DR,GACJ;MACJ,CAAC,CAAC;MACF;IACJ;;IAEA;IACA,IAAId,WAAW,EAAE;MACb,MAAMuB,eAAe,GAAG3B,oBAAoB,CAAC4B,WAAW,CAACV,GAAG,EAAEf,OAAO,CAAC;MACtE,MAAM0B,UAAU,GAAG/B,IAAI,CAClBgC,QAAQ,CAACH,eAAe,CAAC,CACzBlB,OAAO,CAACX,IAAI,CAACiC,OAAO,CAACJ,eAAe,CAAC,EAAE,EAAE,CAAC;MAE/C,MAAMK,sBAAsB,GAAG,MAAMhC,oBAAoB,CAACiC,cAAc,CACpEf,GAAG,EACHf,OACJ,CAAC;MAED,IAAI,CAAC6B,sBAAsB,EAAE;QACzBb,GAAG,CAACE,QAAQ,CAAC;UACTC,IAAI,EAAEzB,CAAC,CAAC0B,YAAY,CAACC,MAAM;UAC3BC,OAAO,EAAE1B,YAAY,CAAC2B,aAAa,CAC/B,kEAAkE,EAClER,GAAG,EACHW,UACJ;QACJ,CAAC,CAAC;QACF;MACJ;MAEA,MAAMK,QAAQ,GAAG,IAAItC,QAAQ,CAACoC,sBAAsB,CAAC;MACrD,MAAMG,YAAY,GAAGD,QAAQ,CAACE,cAAc,CAAC,CAAC,CAAC5B,QAAQ,CAAC,CAAC;MACzD,MAAM6B,OAAO,GAAGjC,WAAW,CAACI,QAAQ,CAAC,CAAC;MACtC,MAAM8B,oBAAoB,GAAGH,YAAY,KAAKE,OAAO;MAErD,IAAI,CAACC,oBAAoB,EAAE;QACvBnB,GAAG,CAACE,QAAQ,CAAC;UACTC,IAAI,EAAEzB,CAAC,CAAC0B,YAAY,CAACC,MAAM;UAC3BC,OAAO,EAAE1B,YAAY,CAAC2B,aAAa,CAC/B,qDAAqD,EACrDG,UAAU,EACVX,GAAG,EACHR,SAAS,IAAI,EACjB;QACJ,CAAC,CAAC;MACN;IACJ;EACJ,CAAC,CAAC;AACV,CAAC","ignoreList":[]}
|
package/exports/extensions.d.ts
CHANGED
package/exports/extensions.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["EnvVar"],"sources":["extensions.ts"],"sourcesContent":["export { EnvVar } from \"~/extensions/EnvVar.js\";\n"],"mappings":"AAAA,SAASA,MAAM","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["EnvVar","FeatureFlags"],"sources":["extensions.ts"],"sourcesContent":["export { EnvVar } from \"~/extensions/EnvVar.js\";\nexport { FeatureFlags } from \"~/extensions/FeatureFlags.js\";\n"],"mappings":"AAAA,SAASA,MAAM;AACf,SAASC,YAAY","ignoreList":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const AdminBuildParam: import("~/defineExtension/index.js").ExtensionComponent<z.ZodObject<{
|
|
3
|
+
paramName: z.ZodString;
|
|
4
|
+
value: z.ZodUnion<[z.ZodString, z.ZodRecord<z.ZodString, z.ZodAny>, z.ZodArray<z.ZodAny, "many">, z.ZodNumber, z.ZodBoolean]>;
|
|
5
|
+
}, "strip", z.ZodTypeAny, {
|
|
6
|
+
value: string | number | boolean | any[] | Record<string, any>;
|
|
7
|
+
paramName: string;
|
|
8
|
+
}, {
|
|
9
|
+
value: string | number | boolean | any[] | Record<string, any>;
|
|
10
|
+
paramName: string;
|
|
11
|
+
}>>;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { defineExtension } from "../defineExtension/index.js";
|
|
3
|
+
import crypto from "crypto";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import { Node, Project } from "ts-morph";
|
|
7
|
+
async function generateBuildParamsFeature(buildParamsDir, ctx) {
|
|
8
|
+
const featureFilePath = path.join(buildParamsDir, "feature.ts");
|
|
9
|
+
|
|
10
|
+
// Get all BuildParam_*.ts files.
|
|
11
|
+
const files = fs.readdirSync(buildParamsDir).filter(f => f.startsWith("BuildParam_") && f.endsWith(".ts") && f !== "feature.ts");
|
|
12
|
+
|
|
13
|
+
// Generate imports and registrations.
|
|
14
|
+
const imports = files.map(file => {
|
|
15
|
+
const className = path.parse(file).name;
|
|
16
|
+
return `import ${className} from "./${className}.js";`;
|
|
17
|
+
}).join("\n");
|
|
18
|
+
const registrations = files.map(file => {
|
|
19
|
+
const className = path.parse(file).name;
|
|
20
|
+
return ` container.register(${className});`;
|
|
21
|
+
}).join("\n");
|
|
22
|
+
const featureContent = `import { createFeature } from "@webiny/feature/admin";
|
|
23
|
+
import { Container } from "@webiny/di";
|
|
24
|
+
${imports}
|
|
25
|
+
|
|
26
|
+
export const BuildParamsInternalFeature = createFeature({
|
|
27
|
+
name: "BuildParamsInternal",
|
|
28
|
+
register(container: Container) {
|
|
29
|
+
${registrations}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
`;
|
|
33
|
+
fs.writeFileSync(featureFilePath, featureContent, "utf8");
|
|
34
|
+
|
|
35
|
+
// Now we need to update Extensions.tsx to use RegisterFeature with this feature.
|
|
36
|
+
await updateExtensionsTsx(ctx);
|
|
37
|
+
}
|
|
38
|
+
async function updateExtensionsTsx(ctx) {
|
|
39
|
+
const extensionsTsxFilePath = ctx.project.paths.workspaceFolder.join("apps", "admin", "src", "Extensions.tsx").toString();
|
|
40
|
+
const project = new Project();
|
|
41
|
+
project.addSourceFileAtPath(extensionsTsxFilePath);
|
|
42
|
+
const source = project.getSourceFileOrThrow(extensionsTsxFilePath);
|
|
43
|
+
|
|
44
|
+
// Check if we already have the imports.
|
|
45
|
+
const buildParamsFeatureImport = "./buildParams/feature.js";
|
|
46
|
+
const existingFeatureImport = source.getImportDeclaration(buildParamsFeatureImport);
|
|
47
|
+
if (!existingFeatureImport) {
|
|
48
|
+
let index = 1;
|
|
49
|
+
const importDeclarations = source.getImportDeclarations();
|
|
50
|
+
if (importDeclarations.length) {
|
|
51
|
+
const last = importDeclarations[importDeclarations.length - 1];
|
|
52
|
+
index = last.getChildIndex() + 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Add import for BuildParamsInternalFeature.
|
|
56
|
+
source.insertImportDeclaration(index, {
|
|
57
|
+
namedImports: ["BuildParamsInternalFeature"],
|
|
58
|
+
moduleSpecifier: buildParamsFeatureImport
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Add import for BuildParamsFeature.
|
|
62
|
+
const buildParamsFeatureImportPath = "@webiny/app-admin";
|
|
63
|
+
const existingBuildParamsImport = source.getImportDeclaration(buildParamsFeatureImportPath);
|
|
64
|
+
if (!existingBuildParamsImport) {
|
|
65
|
+
source.insertImportDeclaration(index, {
|
|
66
|
+
namedImports: ["BuildParamsFeature"],
|
|
67
|
+
moduleSpecifier: buildParamsFeatureImportPath
|
|
68
|
+
});
|
|
69
|
+
} else {
|
|
70
|
+
// Add to existing import if BuildParamsFeature not already there.
|
|
71
|
+
const namedImports = existingBuildParamsImport.getNamedImports();
|
|
72
|
+
const hasBuildParamsFeature = namedImports.some(ni => ni.getName() === "BuildParamsFeature");
|
|
73
|
+
if (!hasBuildParamsFeature) {
|
|
74
|
+
existingBuildParamsImport.addNamedImport("BuildParamsFeature");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Add import for RegisterFeature if not present.
|
|
79
|
+
const registerFeatureImportPath = "@webiny/app-admin";
|
|
80
|
+
const existingRegisterFeatureImport = source.getImportDeclaration(registerFeatureImportPath);
|
|
81
|
+
if (existingRegisterFeatureImport) {
|
|
82
|
+
const namedImports = existingRegisterFeatureImport.getNamedImports();
|
|
83
|
+
const hasRegisterFeature = namedImports.some(ni => ni.getName() === "RegisterFeature");
|
|
84
|
+
if (!hasRegisterFeature) {
|
|
85
|
+
existingRegisterFeatureImport.addNamedImport("RegisterFeature");
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
source.insertImportDeclaration(index, {
|
|
89
|
+
namedImports: ["RegisterFeature"],
|
|
90
|
+
moduleSpecifier: registerFeatureImportPath
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Now add <RegisterFeature> components to the Extensions component.
|
|
96
|
+
const extensionsIdentifier = source.getFirstDescendant(node => {
|
|
97
|
+
if (!Node.isIdentifier(node)) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return node.getText() === "Extensions";
|
|
101
|
+
});
|
|
102
|
+
if (!extensionsIdentifier) {
|
|
103
|
+
throw new Error(`Could not find the "Extensions" React component in "${extensionsTsxFilePath}".`);
|
|
104
|
+
}
|
|
105
|
+
const extensionsArrowFn = extensionsIdentifier.getNextSibling(node => Node.isArrowFunction(node));
|
|
106
|
+
if (!extensionsArrowFn) {
|
|
107
|
+
throw new Error(`Could not find the "Extensions" React component arrow function.`);
|
|
108
|
+
}
|
|
109
|
+
const extensionsArrowFnFragment = extensionsArrowFn.getFirstDescendant(node => {
|
|
110
|
+
return Node.isJsxFragment(node);
|
|
111
|
+
});
|
|
112
|
+
if (!extensionsArrowFnFragment) {
|
|
113
|
+
throw new Error(`Could not find JSX fragment in Extensions component.`);
|
|
114
|
+
}
|
|
115
|
+
const currentContent = extensionsArrowFnFragment.getFullText().replace("<>", "").replace("</>", "").trim();
|
|
116
|
+
|
|
117
|
+
// Check if we already have the RegisterFeature components.
|
|
118
|
+
if (!currentContent.includes("BuildParamsFeature")) {
|
|
119
|
+
const newContent = `<><RegisterFeature feature={BuildParamsFeature} /><RegisterFeature feature={BuildParamsInternalFeature} />${currentContent}</>`;
|
|
120
|
+
extensionsArrowFnFragment.replaceWithText(newContent);
|
|
121
|
+
}
|
|
122
|
+
await source.save();
|
|
123
|
+
}
|
|
124
|
+
export const AdminBuildParam = defineExtension({
|
|
125
|
+
type: "Admin/BuildParam",
|
|
126
|
+
tags: {
|
|
127
|
+
runtimeContext: "app-build",
|
|
128
|
+
appName: "admin"
|
|
129
|
+
},
|
|
130
|
+
description: "Add build-time parameter to Admin app.",
|
|
131
|
+
multiple: true,
|
|
132
|
+
paramsSchema: () => {
|
|
133
|
+
return z.object({
|
|
134
|
+
paramName: z.string(),
|
|
135
|
+
value: z.union([z.string(), z.record(z.any()), z.array(z.any()), z.number(), z.boolean()])
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
async build(params, ctx) {
|
|
139
|
+
const buildParamsDir = ctx.project.paths.workspaceFolder.join("apps", "admin", "src", "buildParams").toString();
|
|
140
|
+
const {
|
|
141
|
+
paramName,
|
|
142
|
+
value
|
|
143
|
+
} = params;
|
|
144
|
+
|
|
145
|
+
// Serialize value to a TypeScript literal.
|
|
146
|
+
const valueStr = JSON.stringify(value, null, 4);
|
|
147
|
+
|
|
148
|
+
// Generate a unique class name based on the paramName.
|
|
149
|
+
const hash = crypto.createHash("sha256").update(paramName).digest("hex");
|
|
150
|
+
const className = `BuildParam_${hash.slice(-10)}`;
|
|
151
|
+
const fileName = `${className}.ts`;
|
|
152
|
+
const filePath = path.join(buildParamsDir, fileName);
|
|
153
|
+
|
|
154
|
+
// Ensure buildParams directory exists.
|
|
155
|
+
if (!fs.existsSync(buildParamsDir)) {
|
|
156
|
+
fs.mkdirSync(buildParamsDir, {
|
|
157
|
+
recursive: true
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Check if file already exists.
|
|
162
|
+
if (!fs.existsSync(filePath)) {
|
|
163
|
+
// Create the BuildParam implementation file.
|
|
164
|
+
const fileContent = `import { BuildParam } from "webiny/admin/buildParams";
|
|
165
|
+
|
|
166
|
+
class ${className} implements BuildParam.Interface {
|
|
167
|
+
key = "${paramName}";
|
|
168
|
+
value = ${valueStr};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export default BuildParam.createImplementation({
|
|
172
|
+
implementation: ${className},
|
|
173
|
+
dependencies: []
|
|
174
|
+
});
|
|
175
|
+
`;
|
|
176
|
+
fs.writeFileSync(filePath, fileContent, "utf8");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Now we need to generate/update the feature file that imports all BuildParams.
|
|
180
|
+
await generateBuildParamsFeature(buildParamsDir, ctx);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
//# sourceMappingURL=AdminBuildParam.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["z","defineExtension","crypto","path","fs","Node","Project","generateBuildParamsFeature","buildParamsDir","ctx","featureFilePath","join","files","readdirSync","filter","f","startsWith","endsWith","imports","map","file","className","parse","name","registrations","featureContent","writeFileSync","updateExtensionsTsx","extensionsTsxFilePath","project","paths","workspaceFolder","toString","addSourceFileAtPath","source","getSourceFileOrThrow","buildParamsFeatureImport","existingFeatureImport","getImportDeclaration","index","importDeclarations","getImportDeclarations","length","last","getChildIndex","insertImportDeclaration","namedImports","moduleSpecifier","buildParamsFeatureImportPath","existingBuildParamsImport","getNamedImports","hasBuildParamsFeature","some","ni","getName","addNamedImport","registerFeatureImportPath","existingRegisterFeatureImport","hasRegisterFeature","extensionsIdentifier","getFirstDescendant","node","isIdentifier","getText","Error","extensionsArrowFn","getNextSibling","isArrowFunction","extensionsArrowFnFragment","isJsxFragment","currentContent","getFullText","replace","trim","includes","newContent","replaceWithText","save","AdminBuildParam","type","tags","runtimeContext","appName","description","multiple","paramsSchema","object","paramName","string","value","union","record","any","array","number","boolean","build","params","valueStr","JSON","stringify","hash","createHash","update","digest","slice","fileName","filePath","existsSync","mkdirSync","recursive","fileContent"],"sources":["AdminBuildParam.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { defineExtension } from \"~/defineExtension/index.js\";\nimport crypto from \"crypto\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport { Node, Project } from \"ts-morph\";\n\nasync function generateBuildParamsFeature(buildParamsDir: string, ctx: any) {\n const featureFilePath = path.join(buildParamsDir, \"feature.ts\");\n\n // Get all BuildParam_*.ts files.\n const files = fs\n .readdirSync(buildParamsDir)\n .filter(f => f.startsWith(\"BuildParam_\") && f.endsWith(\".ts\") && f !== \"feature.ts\");\n\n // Generate imports and registrations.\n const imports = files\n .map(file => {\n const className = path.parse(file).name;\n return `import ${className} from \"./${className}.js\";`;\n })\n .join(\"\\n\");\n\n const registrations = files\n .map(file => {\n const className = path.parse(file).name;\n return ` container.register(${className});`;\n })\n .join(\"\\n\");\n\n const featureContent = `import { createFeature } from \"@webiny/feature/admin\";\nimport { Container } from \"@webiny/di\";\n${imports}\n\nexport const BuildParamsInternalFeature = createFeature({\n name: \"BuildParamsInternal\",\n register(container: Container) {\n${registrations}\n }\n});\n`;\n\n fs.writeFileSync(featureFilePath, featureContent, \"utf8\");\n\n // Now we need to update Extensions.tsx to use RegisterFeature with this feature.\n await updateExtensionsTsx(ctx);\n}\n\nasync function updateExtensionsTsx(ctx: any) {\n const extensionsTsxFilePath = ctx.project.paths.workspaceFolder\n .join(\"apps\", \"admin\", \"src\", \"Extensions.tsx\")\n .toString();\n\n const project = new Project();\n project.addSourceFileAtPath(extensionsTsxFilePath);\n\n const source = project.getSourceFileOrThrow(extensionsTsxFilePath);\n\n // Check if we already have the imports.\n const buildParamsFeatureImport = \"./buildParams/feature.js\";\n const existingFeatureImport = source.getImportDeclaration(buildParamsFeatureImport);\n\n if (!existingFeatureImport) {\n let index = 1;\n const importDeclarations = source.getImportDeclarations();\n if (importDeclarations.length) {\n const last = importDeclarations[importDeclarations.length - 1];\n index = last.getChildIndex() + 1;\n }\n\n // Add import for BuildParamsInternalFeature.\n source.insertImportDeclaration(index, {\n namedImports: [\"BuildParamsInternalFeature\"],\n moduleSpecifier: buildParamsFeatureImport\n });\n\n // Add import for BuildParamsFeature.\n const buildParamsFeatureImportPath = \"@webiny/app-admin\";\n const existingBuildParamsImport = source.getImportDeclaration(buildParamsFeatureImportPath);\n\n if (!existingBuildParamsImport) {\n source.insertImportDeclaration(index, {\n namedImports: [\"BuildParamsFeature\"],\n moduleSpecifier: buildParamsFeatureImportPath\n });\n } else {\n // Add to existing import if BuildParamsFeature not already there.\n const namedImports = existingBuildParamsImport.getNamedImports();\n const hasBuildParamsFeature = namedImports.some(\n ni => ni.getName() === \"BuildParamsFeature\"\n );\n if (!hasBuildParamsFeature) {\n existingBuildParamsImport.addNamedImport(\"BuildParamsFeature\");\n }\n }\n\n // Add import for RegisterFeature if not present.\n const registerFeatureImportPath = \"@webiny/app-admin\";\n const existingRegisterFeatureImport =\n source.getImportDeclaration(registerFeatureImportPath);\n\n if (existingRegisterFeatureImport) {\n const namedImports = existingRegisterFeatureImport.getNamedImports();\n const hasRegisterFeature = namedImports.some(ni => ni.getName() === \"RegisterFeature\");\n if (!hasRegisterFeature) {\n existingRegisterFeatureImport.addNamedImport(\"RegisterFeature\");\n }\n } else {\n source.insertImportDeclaration(index, {\n namedImports: [\"RegisterFeature\"],\n moduleSpecifier: registerFeatureImportPath\n });\n }\n }\n\n // Now add <RegisterFeature> components to the Extensions component.\n const extensionsIdentifier = source.getFirstDescendant(node => {\n if (!Node.isIdentifier(node)) {\n return false;\n }\n return node.getText() === \"Extensions\";\n });\n\n if (!extensionsIdentifier) {\n throw new Error(\n `Could not find the \"Extensions\" React component in \"${extensionsTsxFilePath}\".`\n );\n }\n\n const extensionsArrowFn = extensionsIdentifier.getNextSibling(node =>\n Node.isArrowFunction(node)\n );\n\n if (!extensionsArrowFn) {\n throw new Error(`Could not find the \"Extensions\" React component arrow function.`);\n }\n\n const extensionsArrowFnFragment = extensionsArrowFn.getFirstDescendant(node => {\n return Node.isJsxFragment(node);\n });\n\n if (!extensionsArrowFnFragment) {\n throw new Error(`Could not find JSX fragment in Extensions component.`);\n }\n\n const currentContent = extensionsArrowFnFragment\n .getFullText()\n .replace(\"<>\", \"\")\n .replace(\"</>\", \"\")\n .trim();\n\n // Check if we already have the RegisterFeature components.\n if (!currentContent.includes(\"BuildParamsFeature\")) {\n const newContent = `<><RegisterFeature feature={BuildParamsFeature} /><RegisterFeature feature={BuildParamsInternalFeature} />${currentContent}</>`;\n extensionsArrowFnFragment.replaceWithText(newContent);\n }\n\n await source.save();\n}\n\nexport const AdminBuildParam = defineExtension({\n type: \"Admin/BuildParam\",\n tags: { runtimeContext: \"app-build\", appName: \"admin\" },\n description: \"Add build-time parameter to Admin app.\",\n multiple: true,\n paramsSchema: () => {\n return z.object({\n paramName: z.string(),\n value: z.union([\n z.string(),\n z.record(z.any()),\n z.array(z.any()),\n z.number(),\n z.boolean()\n ])\n });\n },\n async build(params, ctx) {\n const buildParamsDir = ctx.project.paths.workspaceFolder\n .join(\"apps\", \"admin\", \"src\", \"buildParams\")\n .toString();\n\n const { paramName, value } = params;\n\n // Serialize value to a TypeScript literal.\n const valueStr = JSON.stringify(value, null, 4);\n\n // Generate a unique class name based on the paramName.\n const hash = crypto.createHash(\"sha256\").update(paramName).digest(\"hex\");\n const className = `BuildParam_${hash.slice(-10)}`;\n const fileName = `${className}.ts`;\n const filePath = path.join(buildParamsDir, fileName);\n\n // Ensure buildParams directory exists.\n if (!fs.existsSync(buildParamsDir)) {\n fs.mkdirSync(buildParamsDir, { recursive: true });\n }\n\n // Check if file already exists.\n if (!fs.existsSync(filePath)) {\n // Create the BuildParam implementation file.\n const fileContent = `import { BuildParam } from \"webiny/admin/buildParams\";\n\nclass ${className} implements BuildParam.Interface {\n key = \"${paramName}\";\n value = ${valueStr};\n}\n\nexport default BuildParam.createImplementation({\n implementation: ${className},\n dependencies: []\n});\n`;\n fs.writeFileSync(filePath, fileContent, \"utf8\");\n }\n\n // Now we need to generate/update the feature file that imports all BuildParams.\n await generateBuildParamsFeature(buildParamsDir, ctx);\n }\n});\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const AdminExtension: import("~/extensions/index.js").ExtensionComponent<z.ZodObject<{
|
|
3
|
+
src: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
|
|
4
|
+
exportName: z.ZodOptional<z.ZodString>;
|
|
5
|
+
}, "strip", z.ZodTypeAny, {
|
|
6
|
+
src: string;
|
|
7
|
+
exportName?: string | undefined;
|
|
8
|
+
}, {
|
|
9
|
+
src: string;
|
|
10
|
+
exportName?: string | undefined;
|
|
11
|
+
}>>;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { defineExtension, zodSrcPath } from "./index.js";
|
|
2
|
+
import { ExtensionSrcResolver } from "@webiny/project";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { Node, Project } from "ts-morph";
|
|
6
|
+
import crypto from "crypto";
|
|
7
|
+
export const AdminExtension = defineExtension({
|
|
8
|
+
type: "Admin/Extension",
|
|
9
|
+
tags: {
|
|
10
|
+
runtimeContext: "app-build",
|
|
11
|
+
appName: "admin"
|
|
12
|
+
},
|
|
13
|
+
description: "Extend the Admin application with custom functionality.",
|
|
14
|
+
multiple: true,
|
|
15
|
+
paramsSchema: ({
|
|
16
|
+
project
|
|
17
|
+
}) => {
|
|
18
|
+
return z.object({
|
|
19
|
+
src: zodSrcPath({
|
|
20
|
+
project
|
|
21
|
+
}),
|
|
22
|
+
exportName: z.string().optional()
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
async build(params, ctx) {
|
|
26
|
+
const extensionsTsxFilePath = ctx.project.paths.workspaceFolder.join("apps", "admin", "src", "Extensions.tsx").toString();
|
|
27
|
+
const {
|
|
28
|
+
src: extensionFilePath
|
|
29
|
+
} = params;
|
|
30
|
+
|
|
31
|
+
// Resolve to absolute path for file operations.
|
|
32
|
+
const absoluteExtensionFilePath = ExtensionSrcResolver.resolvePath(extensionFilePath, ctx.project);
|
|
33
|
+
const extensionFileName = path.basename(absoluteExtensionFilePath);
|
|
34
|
+
|
|
35
|
+
// Export name can be customized or defaults to the file name without extension.
|
|
36
|
+
const exportName = params.exportName ?? path.parse(extensionFileName).name;
|
|
37
|
+
|
|
38
|
+
// Generate a constant hash-based component name to avoid using timestamps.
|
|
39
|
+
const hash = crypto.createHash("sha256").update(extensionFilePath).digest("hex");
|
|
40
|
+
const componentName = `AdminExtension_${hash.slice(-10)}`;
|
|
41
|
+
const project = new Project();
|
|
42
|
+
const importPath = path.relative(path.dirname(extensionsTsxFilePath), absoluteExtensionFilePath).replace(/\.tsx?$/, ".js");
|
|
43
|
+
project.addSourceFileAtPath(extensionsTsxFilePath);
|
|
44
|
+
const source = project.getSourceFileOrThrow(extensionsTsxFilePath);
|
|
45
|
+
const existingImportDeclaration = source.getImportDeclaration(importPath);
|
|
46
|
+
if (existingImportDeclaration) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check if the extension file has a default export or named export.
|
|
51
|
+
const extensionProject = new Project();
|
|
52
|
+
extensionProject.addSourceFileAtPath(absoluteExtensionFilePath);
|
|
53
|
+
const extensionSource = extensionProject.getSourceFileOrThrow(absoluteExtensionFilePath);
|
|
54
|
+
const hasDefaultExport = extensionSource.getDefaultExportSymbol() !== undefined;
|
|
55
|
+
let index = 1;
|
|
56
|
+
const importDeclarations = source.getImportDeclarations();
|
|
57
|
+
if (importDeclarations.length) {
|
|
58
|
+
const last = importDeclarations[importDeclarations.length - 1];
|
|
59
|
+
index = last.getChildIndex() + 1;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Import as default export if available, otherwise import named export.
|
|
63
|
+
if (hasDefaultExport) {
|
|
64
|
+
source.insertImportDeclaration(index, {
|
|
65
|
+
defaultImport: componentName,
|
|
66
|
+
moduleSpecifier: importPath
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
source.insertImportDeclaration(index, {
|
|
70
|
+
namedImports: [{
|
|
71
|
+
name: exportName,
|
|
72
|
+
alias: componentName
|
|
73
|
+
}],
|
|
74
|
+
moduleSpecifier: importPath
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const extensionsIdentifier = source.getFirstDescendant(node => {
|
|
78
|
+
if (!Node.isIdentifier(node)) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
return node.getText() === "Extensions";
|
|
82
|
+
});
|
|
83
|
+
if (!extensionsIdentifier) {
|
|
84
|
+
throw new Error(`Could not find the "Extensions" React component in "${extensionsTsxFilePath}". Did you maybe change the name of the component?`);
|
|
85
|
+
}
|
|
86
|
+
const extensionsArrowFn = extensionsIdentifier.getNextSibling(node => Node.isArrowFunction(node));
|
|
87
|
+
if (!extensionsArrowFn) {
|
|
88
|
+
throw new Error(`Could not find the "Extensions" React component in "${extensionsTsxFilePath}". Did you maybe change its definition? It should be an arrow function.`);
|
|
89
|
+
}
|
|
90
|
+
const extensionsArrowFnFragment = extensionsArrowFn.getFirstDescendant(node => {
|
|
91
|
+
return Node.isJsxFragment(node);
|
|
92
|
+
});
|
|
93
|
+
const extensionsArrowFnFragmentChildrenText = extensionsArrowFnFragment.getFullText().replace("<>", "").replace("</>", "").trim();
|
|
94
|
+
extensionsArrowFnFragment.replaceWithText(`<><${componentName}/>${extensionsArrowFnFragmentChildrenText}</>`);
|
|
95
|
+
await source.save();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
//# sourceMappingURL=AdminExtension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["defineExtension","zodSrcPath","ExtensionSrcResolver","z","path","Node","Project","crypto","AdminExtension","type","tags","runtimeContext","appName","description","multiple","paramsSchema","project","object","src","exportName","string","optional","build","params","ctx","extensionsTsxFilePath","paths","workspaceFolder","join","toString","extensionFilePath","absoluteExtensionFilePath","resolvePath","extensionFileName","basename","parse","name","hash","createHash","update","digest","componentName","slice","importPath","relative","dirname","replace","addSourceFileAtPath","source","getSourceFileOrThrow","existingImportDeclaration","getImportDeclaration","extensionProject","extensionSource","hasDefaultExport","getDefaultExportSymbol","undefined","index","importDeclarations","getImportDeclarations","length","last","getChildIndex","insertImportDeclaration","defaultImport","moduleSpecifier","namedImports","alias","extensionsIdentifier","getFirstDescendant","node","isIdentifier","getText","Error","extensionsArrowFn","getNextSibling","isArrowFunction","extensionsArrowFnFragment","isJsxFragment","extensionsArrowFnFragmentChildrenText","getFullText","trim","replaceWithText","save"],"sources":["AdminExtension.ts"],"sourcesContent":["import { defineExtension, zodSrcPath } from \"~/extensions/index.js\";\nimport { ExtensionSrcResolver } from \"@webiny/project\";\nimport { z } from \"zod\";\nimport path from \"path\";\nimport { type JsxFragment, Node, Project } from \"ts-morph\";\nimport crypto from \"crypto\";\n\nexport const AdminExtension = defineExtension({\n type: \"Admin/Extension\",\n tags: { runtimeContext: \"app-build\", appName: \"admin\" },\n description: \"Extend the Admin application with custom functionality.\",\n multiple: true,\n paramsSchema: ({ project }) => {\n return z.object({\n src: zodSrcPath({ project }),\n exportName: z.string().optional()\n });\n },\n async build(params, ctx) {\n const extensionsTsxFilePath = ctx.project.paths.workspaceFolder\n .join(\"apps\", \"admin\", \"src\", \"Extensions.tsx\")\n .toString();\n\n const { src: extensionFilePath } = params;\n\n // Resolve to absolute path for file operations.\n const absoluteExtensionFilePath = ExtensionSrcResolver.resolvePath(\n extensionFilePath,\n ctx.project\n );\n\n const extensionFileName = path.basename(absoluteExtensionFilePath);\n\n // Export name can be customized or defaults to the file name without extension.\n const exportName = params.exportName ?? path.parse(extensionFileName).name;\n\n // Generate a constant hash-based component name to avoid using timestamps.\n const hash = crypto.createHash(\"sha256\").update(extensionFilePath).digest(\"hex\");\n const componentName = `AdminExtension_${hash.slice(-10)}`;\n\n const project = new Project();\n\n const importPath = path\n .relative(path.dirname(extensionsTsxFilePath), absoluteExtensionFilePath)\n .replace(/\\.tsx?$/, \".js\");\n\n project.addSourceFileAtPath(extensionsTsxFilePath);\n\n const source = project.getSourceFileOrThrow(extensionsTsxFilePath);\n\n const existingImportDeclaration = source.getImportDeclaration(importPath);\n if (existingImportDeclaration) {\n return;\n }\n\n // Check if the extension file has a default export or named export.\n const extensionProject = new Project();\n extensionProject.addSourceFileAtPath(absoluteExtensionFilePath);\n const extensionSource = extensionProject.getSourceFileOrThrow(absoluteExtensionFilePath);\n const hasDefaultExport = extensionSource.getDefaultExportSymbol() !== undefined;\n\n let index = 1;\n\n const importDeclarations = source.getImportDeclarations();\n if (importDeclarations.length) {\n const last = importDeclarations[importDeclarations.length - 1];\n index = last.getChildIndex() + 1;\n }\n\n // Import as default export if available, otherwise import named export.\n if (hasDefaultExport) {\n source.insertImportDeclaration(index, {\n defaultImport: componentName,\n moduleSpecifier: importPath\n });\n } else {\n source.insertImportDeclaration(index, {\n namedImports: [{ name: exportName, alias: componentName }],\n moduleSpecifier: importPath\n });\n }\n\n const extensionsIdentifier = source.getFirstDescendant(node => {\n if (!Node.isIdentifier(node)) {\n return false;\n }\n\n return node.getText() === \"Extensions\";\n });\n\n if (!extensionsIdentifier) {\n throw new Error(\n `Could not find the \"Extensions\" React component in \"${extensionsTsxFilePath}\". Did you maybe change the name of the component?`\n );\n }\n\n const extensionsArrowFn = extensionsIdentifier.getNextSibling(node =>\n Node.isArrowFunction(node)\n );\n if (!extensionsArrowFn) {\n throw new Error(\n `Could not find the \"Extensions\" React component in \"${extensionsTsxFilePath}\". Did you maybe change its definition? It should be an arrow function.`\n );\n }\n\n const extensionsArrowFnFragment = extensionsArrowFn.getFirstDescendant(node => {\n return Node.isJsxFragment(node);\n }) as JsxFragment;\n\n const extensionsArrowFnFragmentChildrenText = extensionsArrowFnFragment\n .getFullText()\n .replace(\"<>\", \"\")\n .replace(\"</>\", \"\")\n .trim();\n\n extensionsArrowFnFragment.replaceWithText(\n `<><${componentName}/>${extensionsArrowFnFragmentChildrenText}</>`\n );\n\n await source.save();\n }\n});\n"],"mappings":"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","ignoreList":[]}
|