voltra 2.1.1 → 2.3.0
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/build/cjs/apply/index.js +4 -1
- package/build/cjs/apply/index.js.map +1 -1
- package/build/cjs/config/normalize.js +131 -29
- package/build/cjs/config/normalize.js.map +1 -1
- package/build/cjs/config/perConfiguration.js +29 -0
- package/build/cjs/config/perConfiguration.js.map +1 -0
- package/build/cjs/config/serverUpdate.js +119 -0
- package/build/cjs/config/serverUpdate.js.map +1 -0
- package/build/cjs/config/widgetKind.js +25 -0
- package/build/cjs/config/widgetKind.js.map +1 -0
- package/build/cjs/dependencies/platformPackages.js +9 -0
- package/build/cjs/dependencies/platformPackages.js.map +1 -1
- package/build/cjs/discovery/ios.js +50 -31
- package/build/cjs/discovery/ios.js.map +1 -1
- package/build/cjs/index.js +6 -2
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/platforms/android/generated.js +98 -40
- package/build/cjs/platforms/android/generated.js.map +1 -1
- package/build/cjs/platforms/android/widgetSizing.js +89 -0
- package/build/cjs/platforms/android/widgetSizing.js.map +1 -0
- package/build/cjs/platforms/ios/apply.js +21 -11
- package/build/cjs/platforms/ios/apply.js.map +1 -1
- package/build/cjs/platforms/ios/buildConfigurationValues.js +73 -0
- package/build/cjs/platforms/ios/buildConfigurationValues.js.map +1 -0
- package/build/cjs/platforms/ios/entitlements.js +34 -19
- package/build/cjs/platforms/ios/entitlements.js.map +1 -1
- package/build/cjs/platforms/ios/generated.js +79 -32
- package/build/cjs/platforms/ios/generated.js.map +1 -1
- package/build/cjs/platforms/ios/plist.js +22 -4
- package/build/cjs/platforms/ios/plist.js.map +1 -1
- package/build/cjs/platforms/ios/targetName.js.map +1 -1
- package/build/cjs/platforms/ios/xcodeTarget.js +166 -23
- package/build/cjs/platforms/ios/xcodeTarget.js.map +1 -1
- package/build/cjs/platforms/shared/widgetModule.js +18 -145
- package/build/cjs/platforms/shared/widgetModule.js.map +1 -1
- package/build/esm/apply/index.js +4 -1
- package/build/esm/apply/index.js.map +1 -1
- package/build/esm/config/normalize.js +131 -29
- package/build/esm/config/normalize.js.map +1 -1
- package/build/esm/config/perConfiguration.js +25 -0
- package/build/esm/config/perConfiguration.js.map +1 -0
- package/build/esm/config/serverUpdate.js +112 -0
- package/build/esm/config/serverUpdate.js.map +1 -0
- package/build/esm/config/widgetKind.js +20 -0
- package/build/esm/config/widgetKind.js.map +1 -0
- package/build/esm/dependencies/platformPackages.js +8 -0
- package/build/esm/dependencies/platformPackages.js.map +1 -1
- package/build/esm/discovery/ios.js +50 -31
- package/build/esm/discovery/ios.js.map +1 -1
- package/build/esm/index.js +1 -0
- package/build/esm/index.js.map +1 -1
- package/build/esm/platforms/android/generated.js +100 -42
- package/build/esm/platforms/android/generated.js.map +1 -1
- package/build/esm/platforms/android/widgetSizing.js +85 -0
- package/build/esm/platforms/android/widgetSizing.js.map +1 -0
- package/build/esm/platforms/ios/apply.js +21 -11
- package/build/esm/platforms/ios/apply.js.map +1 -1
- package/build/esm/platforms/ios/buildConfigurationValues.js +68 -0
- package/build/esm/platforms/ios/buildConfigurationValues.js.map +1 -0
- package/build/esm/platforms/ios/entitlements.js +34 -19
- package/build/esm/platforms/ios/entitlements.js.map +1 -1
- package/build/esm/platforms/ios/generated.js +80 -33
- package/build/esm/platforms/ios/generated.js.map +1 -1
- package/build/esm/platforms/ios/plist.js +22 -4
- package/build/esm/platforms/ios/plist.js.map +1 -1
- package/build/esm/platforms/ios/targetName.js.map +1 -1
- package/build/esm/platforms/ios/xcodeTarget.js +166 -23
- package/build/esm/platforms/ios/xcodeTarget.js.map +1 -1
- package/build/esm/platforms/shared/widgetModule.js +16 -107
- package/build/esm/platforms/shared/widgetModule.js.map +1 -1
- package/build/types/apply/index.d.ts.map +1 -1
- package/build/types/config/normalize.d.ts.map +1 -1
- package/build/types/config/perConfiguration.d.ts +18 -0
- package/build/types/config/perConfiguration.d.ts.map +1 -0
- package/build/types/config/serverUpdate.d.ts +80 -0
- package/build/types/config/serverUpdate.d.ts.map +1 -0
- package/build/types/config/types.d.ts +91 -30
- package/build/types/config/types.d.ts.map +1 -1
- package/build/types/config/widgetKind.d.ts +11 -0
- package/build/types/config/widgetKind.d.ts.map +1 -0
- package/build/types/dependencies/platformPackages.d.ts +1 -0
- package/build/types/dependencies/platformPackages.d.ts.map +1 -1
- package/build/types/discovery/ios.d.ts +10 -0
- package/build/types/discovery/ios.d.ts.map +1 -1
- package/build/types/index.d.ts +3 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/platforms/android/generated.d.ts.map +1 -1
- package/build/types/platforms/android/widgetSizing.d.ts +50 -0
- package/build/types/platforms/android/widgetSizing.d.ts.map +1 -0
- package/build/types/platforms/ios/apply.d.ts.map +1 -1
- package/build/types/platforms/ios/buildConfigurationValues.d.ts +33 -0
- package/build/types/platforms/ios/buildConfigurationValues.d.ts.map +1 -0
- package/build/types/platforms/ios/entitlements.d.ts +4 -4
- package/build/types/platforms/ios/entitlements.d.ts.map +1 -1
- package/build/types/platforms/ios/generated.d.ts +14 -2
- package/build/types/platforms/ios/generated.d.ts.map +1 -1
- package/build/types/platforms/ios/plist.d.ts +3 -3
- package/build/types/platforms/ios/plist.d.ts.map +1 -1
- package/build/types/platforms/ios/podfile.d.ts +2 -2
- package/build/types/platforms/ios/podfile.d.ts.map +1 -1
- package/build/types/platforms/ios/targetName.d.ts +2 -2
- package/build/types/platforms/ios/targetName.d.ts.map +1 -1
- package/build/types/platforms/ios/xcodeTarget.d.ts +4 -2
- package/build/types/platforms/ios/xcodeTarget.d.ts.map +1 -1
- package/build/types/platforms/shared/widgetModule.d.ts +12 -3
- package/build/types/platforms/shared/widgetModule.d.ts.map +1 -1
- package/package.json +5 -17
- package/src/apply/index.ts +4 -1
- package/src/config/normalize.node.test.ts +61 -0
- package/src/config/normalize.ts +188 -44
- package/src/config/perConfiguration.ts +49 -0
- package/src/config/serverUpdate.ts +160 -0
- package/src/config/types.ts +97 -30
- package/src/config/widgetKind.node.test.ts +27 -0
- package/src/config/widgetKind.ts +27 -0
- package/src/dependencies/platformPackages.ts +11 -0
- package/src/discovery/ios.ts +104 -60
- package/src/index.ts +8 -0
- package/src/platforms/android/generated.ts +144 -47
- package/src/platforms/android/widgetSizing.ts +112 -0
- package/src/platforms/ios/apply.ts +21 -11
- package/src/platforms/ios/buildConfigurationValues.ts +105 -0
- package/src/platforms/ios/entitlements.ts +55 -31
- package/src/platforms/ios/generated.node.test.ts +61 -0
- package/src/platforms/ios/generated.ts +137 -38
- package/src/platforms/ios/plist.ts +36 -7
- package/src/platforms/ios/podfile.ts +2 -2
- package/src/platforms/ios/targetName.ts +2 -2
- package/src/platforms/ios/xcodeTarget.ts +248 -43
- package/src/platforms/shared/widgetModule.ts +22 -140
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { VoltraCliError } from '../../reporting/summary';
|
|
2
2
|
import type { IOSProjectDiscovery } from '../../discovery/ios';
|
|
3
|
-
import type {
|
|
3
|
+
import type { ResolvedVoltraIOSConfig } from '../../config/types';
|
|
4
4
|
import type { ReportedChange } from '../../reporting/summary';
|
|
5
5
|
type PlistErrorFactory = (message: string) => Error;
|
|
6
6
|
export interface EnsureInfoPlistOptions {
|
|
7
7
|
projectRoot: string;
|
|
8
|
-
ios:
|
|
8
|
+
ios: ResolvedVoltraIOSConfig;
|
|
9
9
|
discovery: IOSProjectDiscovery;
|
|
10
10
|
}
|
|
11
11
|
export interface EnsureInfoPlistResult {
|
|
12
|
-
|
|
12
|
+
changes: ReportedChange[];
|
|
13
13
|
}
|
|
14
14
|
export declare class IOSInfoPlistMutationError extends VoltraCliError {
|
|
15
15
|
constructor(message: string);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plist.d.ts","sourceRoot":"","sources":["../../../../src/platforms/ios/plist.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plist.d.ts","sourceRoot":"","sources":["../../../../src/platforms/ios/plist.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAExD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAa7D,KAAK,iBAAiB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,KAAK,CAAA;AAEnD,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,uBAAuB,CAAA;IAC5B,SAAS,EAAE,mBAAmB,CAAA;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,cAAc,EAAE,CAAA;CAC1B;AAED,qBAAa,yBAA0B,SAAQ,cAAc;gBAC/C,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAcrG;AAmDD,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,iBAAiB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAuBlC;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,iBAAiB,GAAG,MAAM,CAiBpF"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { VoltraCliError } from '../../reporting/summary';
|
|
2
2
|
import type { IOSProjectDiscovery } from '../../discovery/ios';
|
|
3
|
-
import type {
|
|
3
|
+
import type { ResolvedVoltraIOSConfig } from '../../config/types';
|
|
4
4
|
import type { ReportedChange } from '../../reporting/summary';
|
|
5
5
|
export interface EnsurePodfileBlockOptions {
|
|
6
6
|
projectRoot: string;
|
|
7
|
-
ios:
|
|
7
|
+
ios: ResolvedVoltraIOSConfig;
|
|
8
8
|
discovery: IOSProjectDiscovery;
|
|
9
9
|
}
|
|
10
10
|
export interface EnsurePodfileBlockResult {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"podfile.d.ts","sourceRoot":"","sources":["../../../../src/platforms/ios/podfile.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAIxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"podfile.d.ts","sourceRoot":"","sources":["../../../../src/platforms/ios/podfile.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAIxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAO7D,MAAM,WAAW,yBAAyB;IACxC,WAAW,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,uBAAuB,CAAA;IAC5B,SAAS,EAAE,mBAAmB,CAAA;CAC/B;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,cAAc,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,qBAAa,uBAAwB,SAAQ,cAAc;gBAC7C,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAsB9G"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { IOSProjectDiscovery } from '../../discovery/ios';
|
|
2
|
-
import type {
|
|
3
|
-
export declare function resolveIOSWidgetTargetName(ios:
|
|
2
|
+
import type { ResolvedVoltraIOSConfig } from '../../config/types';
|
|
3
|
+
export declare function resolveIOSWidgetTargetName(ios: ResolvedVoltraIOSConfig, discovery: IOSProjectDiscovery): string;
|
|
4
4
|
//# sourceMappingURL=targetName.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"targetName.d.ts","sourceRoot":"","sources":["../../../../src/platforms/ios/targetName.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"targetName.d.ts","sourceRoot":"","sources":["../../../../src/platforms/ios/targetName.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AAEjE,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,uBAAuB,EAAE,SAAS,EAAE,mBAAmB,GAAG,MAAM,CAO/G"}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { VoltraCliError } from '../../reporting/summary';
|
|
2
2
|
import type { IOSProjectDiscovery } from '../../discovery/ios';
|
|
3
|
-
import type {
|
|
3
|
+
import type { ResolvedVoltraIOSConfig } from '../../config/types';
|
|
4
4
|
import type { ReportedChange } from '../../reporting/summary';
|
|
5
5
|
export interface EnsureIOSWidgetTargetOptions {
|
|
6
6
|
projectRoot: string;
|
|
7
|
-
ios:
|
|
7
|
+
ios: ResolvedVoltraIOSConfig;
|
|
8
8
|
discovery: IOSProjectDiscovery;
|
|
9
9
|
generatedFiles: string[];
|
|
10
10
|
previousGeneratedFiles?: string[];
|
|
11
|
+
/** User-defined build settings to write at project level, keyed by build configuration name. */
|
|
12
|
+
buildSettings?: Map<string, Record<string, string>>;
|
|
11
13
|
}
|
|
12
14
|
export interface EnsureIOSWidgetTargetResult {
|
|
13
15
|
change?: ReportedChange;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xcodeTarget.d.ts","sourceRoot":"","sources":["../../../../src/platforms/ios/xcodeTarget.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;
|
|
1
|
+
{"version":3,"file":"xcodeTarget.d.ts","sourceRoot":"","sources":["../../../../src/platforms/ios/xcodeTarget.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAQxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAC9D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAgE7D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,uBAAuB,CAAA;IAC5B,SAAS,EAAE,mBAAmB,CAAA;IAC9B,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAA;IACjC,gGAAgG;IAChG,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CACpD;AAED,MAAM,WAAW,2BAA2B;IAC1C,MAAM,CAAC,EAAE,cAAc,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,qBAAa,4BAA6B,SAAQ,cAAc;gBAClD,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,2BAA2B,CAAC,CAwDtC"}
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
import { type WidgetModuleLoader } from '@use-voltra/compiler';
|
|
2
|
+
import type { VoltraPlatform } from '../../config/types';
|
|
1
3
|
export interface WidgetModuleBuildInfo {
|
|
2
4
|
isDev: false;
|
|
3
5
|
metroUrl: null;
|
|
4
6
|
appVersion: 'unknown';
|
|
5
|
-
voltraVersion:
|
|
7
|
+
voltraVersion: string;
|
|
6
8
|
}
|
|
7
|
-
export declare
|
|
8
|
-
|
|
9
|
+
export declare function createDynamicWidgetBuildInfo(voltraVersion: string): WidgetModuleBuildInfo;
|
|
10
|
+
/**
|
|
11
|
+
* Loader used by the apply pipeline to evaluate widget source at build time.
|
|
12
|
+
*
|
|
13
|
+
* The evaluation rules — which imports are allowed and what they resolve to — live in
|
|
14
|
+
* `@use-voltra/compiler` so that `voltra apply`, the Expo config plugins, and the Metro
|
|
15
|
+
* widget bundler all apply the same contract.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createGeneratedWidgetModuleLoader(projectRoot: string, platform: VoltraPlatform, createError: (message: string) => Error, onWarning?: (message: string) => void): WidgetModuleLoader;
|
|
9
18
|
//# sourceMappingURL=widgetModule.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widgetModule.d.ts","sourceRoot":"","sources":["../../../../src/platforms/shared/widgetModule.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"widgetModule.d.ts","sourceRoot":"","sources":["../../../../src/platforms/shared/widgetModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAExF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,KAAK,CAAA;IACZ,QAAQ,EAAE,IAAI,CAAA;IACd,UAAU,EAAE,SAAS,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,wBAAgB,4BAA4B,CAAC,aAAa,EAAE,MAAM,GAAG,qBAAqB,CAOzF;AAED;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAC/C,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,cAAc,EACxB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,KAAK,EACvC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GACpC,kBAAkB,CAEpB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "voltra",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "CLI for applying Voltra to native React Native projects",
|
|
5
5
|
"main": "build/cjs/index.js",
|
|
6
6
|
"module": "build/esm/index.js",
|
|
@@ -40,34 +40,22 @@
|
|
|
40
40
|
"license": "MIT",
|
|
41
41
|
"homepage": "https://use-voltra.dev",
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@babel/core": "^7.27.4",
|
|
44
43
|
"@bacons/xcode": "^1.0.0-alpha.33",
|
|
45
44
|
"@clack/prompts": "^1.0.0-alpha.5",
|
|
46
45
|
"commander": "^12.1.0",
|
|
47
46
|
"cosmiconfig": "^9.0.0",
|
|
48
47
|
"vd-tool": "^4.0.2",
|
|
49
|
-
"xml2js": "^0.6.2"
|
|
48
|
+
"xml2js": "^0.6.2",
|
|
49
|
+
"@use-voltra/compiler": "^2.3.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"
|
|
53
|
-
},
|
|
54
|
-
"peerDependencies": {
|
|
55
|
-
"@use-voltra/android": "*",
|
|
56
|
-
"@use-voltra/ios": "*"
|
|
57
|
-
},
|
|
58
|
-
"peerDependenciesMeta": {
|
|
59
|
-
"@use-voltra/android": {
|
|
60
|
-
"optional": true
|
|
61
|
-
},
|
|
62
|
-
"@use-voltra/ios": {
|
|
63
|
-
"optional": true
|
|
64
|
-
}
|
|
52
|
+
"tsx": "^4.19.0"
|
|
65
53
|
},
|
|
66
54
|
"scripts": {
|
|
67
55
|
"build": "node ../../scripts/build-package.mjs packages/cli",
|
|
68
56
|
"clean": "rm -rf build",
|
|
69
57
|
"lint": "oxlint src",
|
|
70
58
|
"typecheck": "tsc -p tsconfig.typecheck.json --noEmit",
|
|
71
|
-
"test": "node --test"
|
|
59
|
+
"test": "node --import tsx --test"
|
|
72
60
|
}
|
|
73
61
|
}
|
package/src/apply/index.ts
CHANGED
|
@@ -108,7 +108,10 @@ export async function runApplyPipeline(options: ApplyOptions, dependencies: Appl
|
|
|
108
108
|
const deletedChanges = await removeStaleGeneratedFiles(normalizedConfig.projectRoot, stateDiff.staleFiles)
|
|
109
109
|
await saveVoltraState(normalizedConfig.projectRoot, { files: stateDiff.nextFiles })
|
|
110
110
|
|
|
111
|
-
const summaryWarnings =
|
|
111
|
+
const summaryWarnings = [
|
|
112
|
+
...(normalizedConfig.warnings ?? []),
|
|
113
|
+
...platformResults.flatMap((result) => result.warnings ?? []),
|
|
114
|
+
].filter(isDefined)
|
|
112
115
|
const summaryChanges = [...platformResults.flatMap((result) => result.changes), ...deletedChanges]
|
|
113
116
|
|
|
114
117
|
await resolvedDependencies.writeSummary({ changes: summaryChanges, warnings: summaryWarnings })
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { describe, test } from 'node:test'
|
|
3
|
+
|
|
4
|
+
import { normalizeVoltraConfig, VoltraConfigNormalizationError } from './normalize.ts'
|
|
5
|
+
|
|
6
|
+
import type { IOSWidgetConfig } from './types.ts'
|
|
7
|
+
|
|
8
|
+
function normalizeWidgets(widgets: IOSWidgetConfig[]) {
|
|
9
|
+
return normalizeVoltraConfig({
|
|
10
|
+
config: { ios: { widgets } },
|
|
11
|
+
configDir: process.cwd(),
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const streak: IOSWidgetConfig = { id: 'streak', displayName: 'Streak', description: 'Your daily streak' }
|
|
16
|
+
const weather: IOSWidgetConfig = { id: 'weather', displayName: 'Weather', description: 'Shows weather' }
|
|
17
|
+
|
|
18
|
+
describe('ios widget kind', () => {
|
|
19
|
+
test('accepts a custom kind', () => {
|
|
20
|
+
const config = normalizeWidgets([{ ...streak, kind: 'StreakWidget' }])
|
|
21
|
+
|
|
22
|
+
assert.equal(config.ios?.widgets[0]?.kind, 'StreakWidget')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('leaves the kind unset when the config does not pin one', () => {
|
|
26
|
+
const config = normalizeWidgets([streak])
|
|
27
|
+
|
|
28
|
+
assert.equal(config.ios?.widgets[0]?.kind, undefined)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('rejects an empty kind', () => {
|
|
32
|
+
assert.throws(
|
|
33
|
+
() => normalizeWidgets([{ ...streak, kind: '' }]),
|
|
34
|
+
(error: unknown) =>
|
|
35
|
+
error instanceof VoltraConfigNormalizationError && /ios\.widgets\[streak\]\.kind/.test(error.message)
|
|
36
|
+
)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('rejects two widgets sharing a kind', () => {
|
|
40
|
+
assert.throws(
|
|
41
|
+
() =>
|
|
42
|
+
normalizeWidgets([
|
|
43
|
+
{ ...streak, kind: 'Widgets' },
|
|
44
|
+
{ ...weather, kind: 'Widgets' },
|
|
45
|
+
]),
|
|
46
|
+
(error: unknown) =>
|
|
47
|
+
error instanceof VoltraConfigNormalizationError && /Duplicate ios widget kind 'Widgets'/.test(error.message)
|
|
48
|
+
)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('rejects a custom kind that collides with another widget default kind', () => {
|
|
52
|
+
// `weather` would answer to `Voltra_Widget_weather` too, so both would fight over the same
|
|
53
|
+
// placed instances.
|
|
54
|
+
assert.throws(
|
|
55
|
+
() => normalizeWidgets([{ ...streak, kind: 'Voltra_Widget_weather' }, weather]),
|
|
56
|
+
(error: unknown) =>
|
|
57
|
+
error instanceof VoltraConfigNormalizationError &&
|
|
58
|
+
/Duplicate ios widget kind 'Voltra_Widget_weather'/.test(error.message)
|
|
59
|
+
)
|
|
60
|
+
})
|
|
61
|
+
})
|
package/src/config/normalize.ts
CHANGED
|
@@ -2,6 +2,11 @@ import path from 'node:path'
|
|
|
2
2
|
|
|
3
3
|
import { resolveFromRoot } from '../fs/path'
|
|
4
4
|
import { CLI_DEFAULTS } from './defaults'
|
|
5
|
+
import { isPerConfigurationMap } from './perConfiguration'
|
|
6
|
+
import { resolveServerUpdateInterval, resolveServerUpdateUrl, validateServerUpdateRefresh } from './serverUpdate'
|
|
7
|
+
import { iosWidgetKind } from './widgetKind'
|
|
8
|
+
|
|
9
|
+
import type { PerConfiguration } from './perConfiguration'
|
|
5
10
|
|
|
6
11
|
import type {
|
|
7
12
|
AndroidWidgetAppIntentConfig,
|
|
@@ -10,6 +15,7 @@ import type {
|
|
|
10
15
|
IOSWidgetConfig,
|
|
11
16
|
LoadedVoltraConfig,
|
|
12
17
|
NormalizedAndroidWidgetConfig,
|
|
18
|
+
NormalizedWidgetServerUpdateConfig,
|
|
13
19
|
NormalizedVoltraAndroidConfig,
|
|
14
20
|
NormalizedVoltraConfig,
|
|
15
21
|
NormalizedVoltraIOSConfig,
|
|
@@ -53,6 +59,33 @@ function assertOptionalString(value: unknown, context: string): asserts value is
|
|
|
53
59
|
}
|
|
54
60
|
}
|
|
55
61
|
|
|
62
|
+
function assertOptionalPerConfigurationString(
|
|
63
|
+
value: unknown,
|
|
64
|
+
context: string
|
|
65
|
+
): asserts value is PerConfiguration<string> | undefined {
|
|
66
|
+
if (value === undefined || typeof value === 'string') {
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!isPerConfigurationMap(value as PerConfiguration<unknown>)) {
|
|
71
|
+
throw new VoltraConfigNormalizationError(
|
|
72
|
+
`${context} must be a string, or an object of strings keyed by build configuration name`
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const entries = Object.entries(value as Record<string, unknown>)
|
|
77
|
+
|
|
78
|
+
if (entries.length === 0) {
|
|
79
|
+
throw new VoltraConfigNormalizationError(`${context} must not be an empty object`)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const [buildConfigurationName, configurationValue] of entries) {
|
|
83
|
+
if (typeof configurationValue !== 'string' || !configurationValue.trim()) {
|
|
84
|
+
throw new VoltraConfigNormalizationError(`${context}.${buildConfigurationName} must be a non-empty string`)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
56
89
|
function assertOptionalBoolean(value: unknown, context: string): asserts value is boolean | undefined {
|
|
57
90
|
if (value !== undefined && typeof value !== 'boolean') {
|
|
58
91
|
throw new VoltraConfigNormalizationError(`${context} must be a boolean`)
|
|
@@ -105,6 +138,26 @@ function resolveOptionalPathFromProjectRoot(projectRoot: string, filePath: strin
|
|
|
105
138
|
return resolvePathFromProjectRoot(projectRoot, filePath)
|
|
106
139
|
}
|
|
107
140
|
|
|
141
|
+
function resolveOptionalPerConfigurationPath(
|
|
142
|
+
projectRoot: string,
|
|
143
|
+
filePath: PerConfiguration<string> | undefined
|
|
144
|
+
): PerConfiguration<string> | undefined {
|
|
145
|
+
if (!filePath) {
|
|
146
|
+
return undefined
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!isPerConfigurationMap(filePath)) {
|
|
150
|
+
return resolvePathFromProjectRoot(projectRoot, filePath)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return Object.fromEntries(
|
|
154
|
+
Object.entries(filePath).map(([buildConfigurationName, configurationPath]) => [
|
|
155
|
+
buildConfigurationName,
|
|
156
|
+
resolvePathFromProjectRoot(projectRoot, configurationPath),
|
|
157
|
+
])
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
108
161
|
function isAbsoluteWidgetPath(value: string): boolean {
|
|
109
162
|
return path.isAbsolute(value) || path.win32.isAbsolute(value) || /^[a-zA-Z]:[\\/]/.test(value)
|
|
110
163
|
}
|
|
@@ -294,42 +347,68 @@ function normalizeIOSAppIntent(
|
|
|
294
347
|
return { parameters }
|
|
295
348
|
}
|
|
296
349
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
350
|
+
interface NormalizeServerUpdateOptions {
|
|
351
|
+
context: string
|
|
352
|
+
/** True when the widget has an `entry`, so the response is props rather than a payload. */
|
|
353
|
+
hasEntry: boolean
|
|
354
|
+
defaultIntervalMinutes: number
|
|
355
|
+
defaultRefresh: boolean
|
|
302
356
|
minimumIntervalMinutes: number
|
|
303
|
-
|
|
357
|
+
warnings: string[]
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function normalizeServerUpdate(
|
|
361
|
+
serverUpdate: { url?: string; intervalMinutes?: number; refresh?: boolean },
|
|
362
|
+
options: NormalizeServerUpdateOptions
|
|
363
|
+
): NormalizedWidgetServerUpdateConfig {
|
|
364
|
+
const { context, hasEntry, defaultIntervalMinutes, defaultRefresh, minimumIntervalMinutes, warnings } = options
|
|
365
|
+
|
|
304
366
|
assertObject(serverUpdate, context)
|
|
305
|
-
assertNonEmptyString(serverUpdate.url, `${context}.url`)
|
|
306
367
|
|
|
307
|
-
|
|
308
|
-
if (typeof serverUpdate.intervalMinutes !== 'number' || !Number.isFinite(serverUpdate.intervalMinutes)) {
|
|
309
|
-
throw new VoltraConfigNormalizationError(`${context}.intervalMinutes must be a number`)
|
|
310
|
-
}
|
|
368
|
+
const url = resolveServerUpdateUrl(serverUpdate.url, context)
|
|
311
369
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
370
|
+
if (url.kind === 'invalid') {
|
|
371
|
+
throw new VoltraConfigNormalizationError(url.error)
|
|
372
|
+
}
|
|
315
373
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
}
|
|
374
|
+
if (url.kind === 'insecure') {
|
|
375
|
+
warnings.push(url.warning)
|
|
319
376
|
}
|
|
320
377
|
|
|
321
|
-
|
|
322
|
-
|
|
378
|
+
const interval = resolveServerUpdateInterval({
|
|
379
|
+
intervalMinutes: serverUpdate.intervalMinutes,
|
|
380
|
+
context,
|
|
381
|
+
hasEntry,
|
|
382
|
+
defaultIntervalMinutes,
|
|
383
|
+
minimumIntervalMinutes,
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
if (interval.kind === 'invalid') {
|
|
387
|
+
throw new VoltraConfigNormalizationError(interval.error)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (interval.kind === 'clamped') {
|
|
391
|
+
warnings.push(interval.warning)
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const refreshError = validateServerUpdateRefresh(serverUpdate.refresh, context)
|
|
395
|
+
|
|
396
|
+
if (refreshError) {
|
|
397
|
+
throw new VoltraConfigNormalizationError(refreshError)
|
|
323
398
|
}
|
|
324
399
|
|
|
325
400
|
return {
|
|
326
401
|
url: serverUpdate.url,
|
|
327
|
-
intervalMinutes:
|
|
402
|
+
intervalMinutes: interval.intervalMinutes,
|
|
328
403
|
refresh: serverUpdate.refresh ?? defaultRefresh,
|
|
329
404
|
}
|
|
330
405
|
}
|
|
331
406
|
|
|
332
|
-
function normalizeAndroidWidget(
|
|
407
|
+
function normalizeAndroidWidget(
|
|
408
|
+
projectRoot: string,
|
|
409
|
+
widget: AndroidWidgetConfig,
|
|
410
|
+
warnings: string[]
|
|
411
|
+
): NormalizedAndroidWidgetConfig {
|
|
333
412
|
assertObject(widget, 'android.widgets[]')
|
|
334
413
|
assertNonEmptyString(widget.id, 'android.widgets[].id')
|
|
335
414
|
assertValidWidgetId(widget.id, 'android.widgets[].id')
|
|
@@ -337,6 +416,12 @@ function normalizeAndroidWidget(projectRoot: string, widget: AndroidWidgetConfig
|
|
|
337
416
|
assertPositiveInteger(widget.targetCellHeight, `android.widgets[${widget.id}].targetCellHeight`)
|
|
338
417
|
assertOptionalPositiveInteger(widget.minCellWidth, `android.widgets[${widget.id}].minCellWidth`)
|
|
339
418
|
assertOptionalPositiveInteger(widget.minCellHeight, `android.widgets[${widget.id}].minCellHeight`)
|
|
419
|
+
assertOptionalPositiveInteger(widget.minWidth, `android.widgets[${widget.id}].minWidth`)
|
|
420
|
+
assertOptionalPositiveInteger(widget.minHeight, `android.widgets[${widget.id}].minHeight`)
|
|
421
|
+
assertOptionalPositiveInteger(widget.minResizeWidth, `android.widgets[${widget.id}].minResizeWidth`)
|
|
422
|
+
assertOptionalPositiveInteger(widget.minResizeHeight, `android.widgets[${widget.id}].minResizeHeight`)
|
|
423
|
+
assertOptionalPositiveInteger(widget.maxResizeWidth, `android.widgets[${widget.id}].maxResizeWidth`)
|
|
424
|
+
assertOptionalPositiveInteger(widget.maxResizeHeight, `android.widgets[${widget.id}].maxResizeHeight`)
|
|
340
425
|
|
|
341
426
|
return {
|
|
342
427
|
...widget,
|
|
@@ -352,22 +437,31 @@ function normalizeAndroidWidget(projectRoot: string, widget: AndroidWidgetConfig
|
|
|
352
437
|
previewLayout: resolveOptionalPathFromProjectRoot(projectRoot, widget.previewLayout),
|
|
353
438
|
appIntent: normalizeAndroidAppIntent(widget.appIntent, `android.widgets[${widget.id}].appIntent`),
|
|
354
439
|
serverUpdate: widget.serverUpdate
|
|
355
|
-
? normalizeServerUpdate(
|
|
356
|
-
widget.serverUpdate
|
|
357
|
-
|
|
358
|
-
CLI_DEFAULTS.android.serverUpdateIntervalMinutes,
|
|
359
|
-
CLI_DEFAULTS.android.serverUpdateRefresh,
|
|
360
|
-
15
|
|
361
|
-
|
|
440
|
+
? normalizeServerUpdate(widget.serverUpdate, {
|
|
441
|
+
context: `android.widgets[${widget.id}].serverUpdate`,
|
|
442
|
+
hasEntry: widget.entry !== undefined,
|
|
443
|
+
defaultIntervalMinutes: CLI_DEFAULTS.android.serverUpdateIntervalMinutes,
|
|
444
|
+
defaultRefresh: CLI_DEFAULTS.android.serverUpdateRefresh,
|
|
445
|
+
minimumIntervalMinutes: 15,
|
|
446
|
+
warnings,
|
|
447
|
+
})
|
|
362
448
|
: undefined,
|
|
363
449
|
}
|
|
364
450
|
}
|
|
365
451
|
|
|
366
|
-
function normalizeIOSWidget(
|
|
452
|
+
function normalizeIOSWidget(
|
|
453
|
+
projectRoot: string,
|
|
454
|
+
widget: IOSWidgetConfig,
|
|
455
|
+
warnings: string[]
|
|
456
|
+
): NormalizedIOSWidgetConfig {
|
|
367
457
|
assertObject(widget, 'ios.widgets[]')
|
|
368
458
|
assertNonEmptyString(widget.id, 'ios.widgets[].id')
|
|
369
459
|
assertValidWidgetId(widget.id, 'ios.widgets[].id')
|
|
370
460
|
|
|
461
|
+
if (widget.kind !== undefined) {
|
|
462
|
+
assertNonEmptyString(widget.kind, `ios.widgets[${widget.id}].kind`)
|
|
463
|
+
}
|
|
464
|
+
|
|
371
465
|
if (widget.supportedFamilies !== undefined) {
|
|
372
466
|
if (!Array.isArray(widget.supportedFamilies)) {
|
|
373
467
|
throw new VoltraConfigNormalizationError(`ios.widgets[${widget.id}].supportedFamilies must be an array`)
|
|
@@ -395,13 +489,14 @@ function normalizeIOSWidget(projectRoot: string, widget: IOSWidgetConfig): Norma
|
|
|
395
489
|
),
|
|
396
490
|
appIntent: normalizeIOSAppIntent(widget.appIntent, `ios.widgets[${widget.id}].appIntent`),
|
|
397
491
|
serverUpdate: widget.serverUpdate
|
|
398
|
-
? normalizeServerUpdate(
|
|
399
|
-
widget.serverUpdate
|
|
400
|
-
|
|
401
|
-
CLI_DEFAULTS.ios.serverUpdateIntervalMinutes,
|
|
402
|
-
CLI_DEFAULTS.ios.serverUpdateRefresh,
|
|
403
|
-
1
|
|
404
|
-
|
|
492
|
+
? normalizeServerUpdate(widget.serverUpdate, {
|
|
493
|
+
context: `ios.widgets[${widget.id}].serverUpdate`,
|
|
494
|
+
hasEntry: widget.entry !== undefined,
|
|
495
|
+
defaultIntervalMinutes: CLI_DEFAULTS.ios.serverUpdateIntervalMinutes,
|
|
496
|
+
defaultRefresh: CLI_DEFAULTS.ios.serverUpdateRefresh,
|
|
497
|
+
minimumIntervalMinutes: 1,
|
|
498
|
+
warnings,
|
|
499
|
+
})
|
|
405
500
|
: undefined,
|
|
406
501
|
}
|
|
407
502
|
}
|
|
@@ -418,6 +513,25 @@ function assertUniqueWidgetIds(widgetIds: string[], context: string): void {
|
|
|
418
513
|
}
|
|
419
514
|
}
|
|
420
515
|
|
|
516
|
+
/**
|
|
517
|
+
* WidgetKit identifies a placed widget by extension bundle id + kind, so two widgets sharing a kind
|
|
518
|
+
* would fight over the same Home Screen instances. Compared after defaulting, which also catches a
|
|
519
|
+
* custom kind that collides with another widget's `Voltra_Widget_<id>`.
|
|
520
|
+
*/
|
|
521
|
+
function assertUniqueIOSWidgetKinds(widgets: Pick<IOSWidgetConfig, 'id' | 'kind'>[]): void {
|
|
522
|
+
const seen = new Set<string>()
|
|
523
|
+
|
|
524
|
+
for (const widget of widgets) {
|
|
525
|
+
const kind = iosWidgetKind(widget)
|
|
526
|
+
|
|
527
|
+
if (seen.has(kind)) {
|
|
528
|
+
throw new VoltraConfigNormalizationError(`Duplicate ios widget kind '${kind}'`)
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
seen.add(kind)
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
421
535
|
function assertValidWidgetId(widgetId: string, context: string): void {
|
|
422
536
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(widgetId)) {
|
|
423
537
|
throw new VoltraConfigNormalizationError(
|
|
@@ -435,6 +549,7 @@ function assertValidIOSTargetName(targetName: string, context: string): void {
|
|
|
435
549
|
}
|
|
436
550
|
|
|
437
551
|
function normalizeAndroidConfig(
|
|
552
|
+
warnings: string[],
|
|
438
553
|
projectRoot: string,
|
|
439
554
|
config: LoadedVoltraConfig['config']['android']
|
|
440
555
|
): NormalizedVoltraAndroidConfig | undefined {
|
|
@@ -459,7 +574,7 @@ function normalizeAndroidConfig(
|
|
|
459
574
|
throw new VoltraConfigNormalizationError('android.widgets must be an array')
|
|
460
575
|
}
|
|
461
576
|
|
|
462
|
-
const widgets = (config.widgets ?? []).map((widget) => normalizeAndroidWidget(projectRoot, widget))
|
|
577
|
+
const widgets = (config.widgets ?? []).map((widget) => normalizeAndroidWidget(projectRoot, widget, warnings))
|
|
463
578
|
assertUniqueWidgetIds(
|
|
464
579
|
widgets.map((widget) => widget.id),
|
|
465
580
|
'android'
|
|
@@ -483,6 +598,7 @@ function normalizeAndroidConfig(
|
|
|
483
598
|
}
|
|
484
599
|
|
|
485
600
|
function normalizeIOSConfig(
|
|
601
|
+
warnings: string[],
|
|
486
602
|
projectRoot: string,
|
|
487
603
|
config: LoadedVoltraConfig['config']['ios']
|
|
488
604
|
): NormalizedVoltraIOSConfig | undefined {
|
|
@@ -492,12 +608,12 @@ function normalizeIOSConfig(
|
|
|
492
608
|
|
|
493
609
|
assertObject(config, 'ios')
|
|
494
610
|
assertOptionalBoolean(config.enablePushNotifications, 'ios.enablePushNotifications')
|
|
495
|
-
|
|
611
|
+
assertOptionalPerConfigurationString(config.groupIdentifier, 'ios.groupIdentifier')
|
|
496
612
|
assertOptionalString(config.deploymentTarget, 'ios.deploymentTarget')
|
|
497
613
|
assertOptionalString(config.targetName, 'ios.targetName')
|
|
498
614
|
assertOptionalStringArray(config.fonts, 'ios.fonts')
|
|
499
615
|
assertOptionalString(config.userImagesPath, 'ios.userImagesPath')
|
|
500
|
-
|
|
616
|
+
assertOptionalPerConfigurationString(config.keychainGroup, 'ios.keychainGroup')
|
|
501
617
|
|
|
502
618
|
if (config.project !== undefined) {
|
|
503
619
|
assertObject(config.project, 'ios.project')
|
|
@@ -505,7 +621,7 @@ function normalizeIOSConfig(
|
|
|
505
621
|
assertOptionalString(config.project.xcodeprojPath, 'ios.project.xcodeprojPath')
|
|
506
622
|
assertOptionalString(config.project.mainTargetName, 'ios.project.mainTargetName')
|
|
507
623
|
assertOptionalString(config.project.infoPlistPath, 'ios.project.infoPlistPath')
|
|
508
|
-
|
|
624
|
+
assertOptionalPerConfigurationString(config.project.entitlementsPath, 'ios.project.entitlementsPath')
|
|
509
625
|
assertOptionalString(config.project.podfilePath, 'ios.project.podfilePath')
|
|
510
626
|
}
|
|
511
627
|
|
|
@@ -517,11 +633,12 @@ function normalizeIOSConfig(
|
|
|
517
633
|
assertValidIOSTargetName(config.targetName, 'ios.targetName')
|
|
518
634
|
}
|
|
519
635
|
|
|
520
|
-
const widgets = (config.widgets ?? []).map((widget) => normalizeIOSWidget(projectRoot, widget))
|
|
636
|
+
const widgets = (config.widgets ?? []).map((widget) => normalizeIOSWidget(projectRoot, widget, warnings))
|
|
521
637
|
assertUniqueWidgetIds(
|
|
522
638
|
widgets.map((widget) => widget.id),
|
|
523
639
|
'ios'
|
|
524
640
|
)
|
|
641
|
+
assertUniqueIOSWidgetKinds(widgets)
|
|
525
642
|
|
|
526
643
|
return {
|
|
527
644
|
enablePushNotifications: config.enablePushNotifications ?? CLI_DEFAULTS.ios.enablePushNotifications,
|
|
@@ -537,7 +654,7 @@ function normalizeIOSConfig(
|
|
|
537
654
|
xcodeprojPath: resolveOptionalPathFromProjectRoot(projectRoot, config.project?.xcodeprojPath),
|
|
538
655
|
mainTargetName: config.project?.mainTargetName,
|
|
539
656
|
infoPlistPath: resolveOptionalPathFromProjectRoot(projectRoot, config.project?.infoPlistPath),
|
|
540
|
-
entitlementsPath:
|
|
657
|
+
entitlementsPath: resolveOptionalPerConfigurationPath(projectRoot, config.project?.entitlementsPath),
|
|
541
658
|
podfilePath: resolveOptionalPathFromProjectRoot(projectRoot, config.project?.podfilePath),
|
|
542
659
|
},
|
|
543
660
|
}
|
|
@@ -552,11 +669,38 @@ export function normalizeVoltraConfig(loadedConfig: LoadedVoltraConfig): Normali
|
|
|
552
669
|
loadedConfig.config.projectRoot ?? loadedConfig.configDir
|
|
553
670
|
)
|
|
554
671
|
|
|
672
|
+
const warnings: string[] = []
|
|
673
|
+
const android = normalizeAndroidConfig(warnings, projectRoot, loadedConfig.config.android)
|
|
674
|
+
const ios = normalizeIOSConfig(warnings, projectRoot, loadedConfig.config.ios)
|
|
675
|
+
|
|
676
|
+
assertServerDrivenDynamicWidgetsAreSupported(ios)
|
|
677
|
+
|
|
555
678
|
return {
|
|
556
679
|
configPath: loadedConfig.configPath,
|
|
557
680
|
configDir: loadedConfig.configDir,
|
|
558
681
|
projectRoot,
|
|
559
|
-
android
|
|
560
|
-
ios
|
|
682
|
+
android,
|
|
683
|
+
ios,
|
|
684
|
+
warnings,
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* A Dynamic Widget commits fetched props to the App Group so the widget extension can read them,
|
|
690
|
+
* so a server-driven one without a `groupIdentifier` would fetch and have nowhere to put the
|
|
691
|
+
* result.
|
|
692
|
+
*/
|
|
693
|
+
function assertServerDrivenDynamicWidgetsAreSupported(ios: NormalizedVoltraIOSConfig | undefined): void {
|
|
694
|
+
if (ios === undefined || ios.groupIdentifier !== undefined) {
|
|
695
|
+
return
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
for (const widget of ios.widgets) {
|
|
699
|
+
if (widget.entry !== undefined && widget.serverUpdate !== undefined) {
|
|
700
|
+
throw new VoltraConfigNormalizationError(
|
|
701
|
+
`ios.widgets[${widget.id}] has both entry and serverUpdate, which requires ios.groupIdentifier ` +
|
|
702
|
+
'so fetched props can be shared with the widget extension.'
|
|
703
|
+
)
|
|
704
|
+
}
|
|
561
705
|
}
|
|
562
706
|
}
|