voltra 2.0.0-rc.4 → 2.1.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/config/normalize.js +93 -0
- package/build/cjs/config/normalize.js.map +1 -1
- package/build/cjs/index.js +5 -2
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/platforms/android/apply.js +11 -2
- package/build/cjs/platforms/android/apply.js.map +1 -1
- package/build/cjs/platforms/android/generated.js +152 -130
- package/build/cjs/platforms/android/generated.js.map +1 -1
- package/build/cjs/platforms/android/gradle.js +120 -0
- package/build/cjs/platforms/android/gradle.js.map +1 -0
- package/build/cjs/platforms/ios/generated.js +246 -142
- package/build/cjs/platforms/ios/generated.js.map +1 -1
- package/build/cjs/platforms/ios/xcodeTarget.js +68 -0
- package/build/cjs/platforms/ios/xcodeTarget.js.map +1 -1
- package/build/cjs/platforms/shared/widgetModule.js +151 -0
- package/build/cjs/platforms/shared/widgetModule.js.map +1 -0
- package/build/esm/config/normalize.js +93 -0
- package/build/esm/config/normalize.js.map +1 -1
- package/build/esm/index.js +1 -0
- package/build/esm/index.js.map +1 -1
- package/build/esm/platforms/android/apply.js +11 -2
- package/build/esm/platforms/android/apply.js.map +1 -1
- package/build/esm/platforms/android/generated.js +152 -97
- package/build/esm/platforms/android/generated.js.map +1 -1
- package/build/esm/platforms/android/gradle.js +112 -0
- package/build/esm/platforms/android/gradle.js.map +1 -0
- package/build/esm/platforms/ios/generated.js +246 -109
- package/build/esm/platforms/ios/generated.js.map +1 -1
- package/build/esm/platforms/ios/xcodeTarget.js +69 -1
- package/build/esm/platforms/ios/xcodeTarget.js.map +1 -1
- package/build/esm/platforms/shared/widgetModule.js +111 -0
- package/build/esm/platforms/shared/widgetModule.js.map +1 -0
- package/build/types/config/normalize.d.ts.map +1 -1
- package/build/types/config/types.d.ts +32 -0
- package/build/types/config/types.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/apply.d.ts.map +1 -1
- package/build/types/platforms/android/generated.d.ts.map +1 -1
- package/build/types/platforms/android/gradle.d.ts +18 -0
- package/build/types/platforms/android/gradle.d.ts.map +1 -0
- package/build/types/platforms/ios/generated.d.ts.map +1 -1
- package/build/types/platforms/ios/xcodeTarget.d.ts.map +1 -1
- package/build/types/platforms/shared/widgetModule.d.ts +9 -0
- package/build/types/platforms/shared/widgetModule.d.ts.map +1 -0
- package/package.json +2 -1
- package/src/apply/index.ts +309 -0
- package/src/apply/preflight.ts +172 -0
- package/src/bin.ts +14 -0
- package/src/commands/apply.ts +114 -0
- package/src/config/defaults.ts +34 -0
- package/src/config/load.ts +100 -0
- package/src/config/normalize.ts +562 -0
- package/src/config/types.ts +317 -0
- package/src/cosmiconfig.d.ts +21 -0
- package/src/dependencies/platformPackages.ts +75 -0
- package/src/discovery/android.ts +233 -0
- package/src/discovery/ios.ts +579 -0
- package/src/fs/path.ts +25 -0
- package/src/fs/readWrite.ts +102 -0
- package/src/git/status.ts +205 -0
- package/src/index.ts +204 -0
- package/src/platforms/android/apply.ts +106 -0
- package/src/platforms/android/generated.ts +1284 -0
- package/src/platforms/android/gradle.ts +155 -0
- package/src/platforms/android/manifest.ts +379 -0
- package/src/platforms/ios/apply.ts +139 -0
- package/src/platforms/ios/deploymentTarget.ts +47 -0
- package/src/platforms/ios/entitlements.ts +146 -0
- package/src/platforms/ios/generated.ts +1233 -0
- package/src/platforms/ios/mainAppEntitlements.ts +11 -0
- package/src/platforms/ios/plist.ts +321 -0
- package/src/platforms/ios/podfile.ts +255 -0
- package/src/platforms/ios/targetName.ts +11 -0
- package/src/platforms/ios/xcode.ts +181 -0
- package/src/platforms/ios/xcodeTarget.ts +899 -0
- package/src/platforms/shared/widgetModule.ts +153 -0
- package/src/reporting/clack.ts +67 -0
- package/src/reporting/summary.ts +116 -0
- package/src/state/diff.ts +21 -0
- package/src/state/files.ts +52 -0
- package/src/state/load.ts +66 -0
- package/src/state/save.ts +31 -0
- package/src/xml2js.d.ts +23 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ensureAndroidGradleWidgetBundling = ensureAndroidGradleWidgetBundling;
|
|
7
|
+
exports.addDynamicWidgetBundlingSnippet = addDynamicWidgetBundlingSnippet;
|
|
8
|
+
exports.removeDynamicWidgetBundlingSnippet = removeDynamicWidgetBundlingSnippet;
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const path_1 = require("../../fs/path");
|
|
11
|
+
const readWrite_1 = require("../../fs/readWrite");
|
|
12
|
+
const MARKER = '// @voltra-widget-bundling';
|
|
13
|
+
const END_MARKER = '// @voltra-widget-bundling-end';
|
|
14
|
+
async function ensureAndroidGradleWidgetBundling(options) {
|
|
15
|
+
const { projectRoot, discovery, hasDynamicWidgets } = options;
|
|
16
|
+
const isKotlinDsl = discovery.buildGradlePath.endsWith('.kts');
|
|
17
|
+
const projectRootRelativeToAppModule = (0, path_1.normalizeRelativePath)(node_path_1.default.relative(discovery.appModuleRoot, projectRoot)) || '.';
|
|
18
|
+
if (isKotlinDsl) {
|
|
19
|
+
if (!hasDynamicWidgets) {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
warnings: ['Voltra: app/build.gradle is not Groovy - skipping Dynamic Widget release bundling wiring.'],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const previousContent = await (0, readWrite_1.readTextFile)(discovery.buildGradlePath);
|
|
27
|
+
const removal = removeDynamicWidgetBundlingSnippet(previousContent, projectRootRelativeToAppModule);
|
|
28
|
+
const nextContent = hasDynamicWidgets
|
|
29
|
+
? addDynamicWidgetBundlingSnippet(removal.contents, projectRootRelativeToAppModule)
|
|
30
|
+
: removal.contents;
|
|
31
|
+
if (nextContent === previousContent) {
|
|
32
|
+
return removal.warning ? { warnings: [removal.warning] } : {};
|
|
33
|
+
}
|
|
34
|
+
await (0, readWrite_1.writeTextFile)(discovery.buildGradlePath, nextContent);
|
|
35
|
+
return {
|
|
36
|
+
change: {
|
|
37
|
+
kind: 'updated',
|
|
38
|
+
path: (0, path_1.toRelativePath)(projectRoot, discovery.buildGradlePath),
|
|
39
|
+
},
|
|
40
|
+
warnings: removal.warning ? [removal.warning] : undefined,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function addDynamicWidgetBundlingSnippet(contents, projectRootRelativeToAppModule) {
|
|
44
|
+
if (contents.includes(MARKER)) {
|
|
45
|
+
return contents;
|
|
46
|
+
}
|
|
47
|
+
return `${contents.trimEnd()}\n\n${createDynamicWidgetBundlingSnippet(projectRootRelativeToAppModule)}\n`;
|
|
48
|
+
}
|
|
49
|
+
function removeDynamicWidgetBundlingSnippet(contents, projectRootRelativeToAppModule) {
|
|
50
|
+
const range = findManagedSnippetRange(contents);
|
|
51
|
+
if (range) {
|
|
52
|
+
return {
|
|
53
|
+
contents: collapseRemovedRange(contents, range.start, range.end),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const legacySnippet = createLegacyDynamicWidgetBundlingSnippet(projectRootRelativeToAppModule);
|
|
57
|
+
const legacyIndex = contents.indexOf(legacySnippet);
|
|
58
|
+
if (legacyIndex >= 0) {
|
|
59
|
+
return {
|
|
60
|
+
contents: collapseRemovedRange(contents, legacyIndex, legacyIndex + legacySnippet.length),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (!contents.includes(MARKER)) {
|
|
64
|
+
return { contents };
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
contents,
|
|
68
|
+
warning: 'Voltra: found legacy Dynamic Widget Gradle marker without managed end marker. Preserved trailing Gradle content; remove old @voltra-widget-bundling block manually if no longer needed.',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function createDynamicWidgetBundlingSnippet(projectRootRelativeToAppModule) {
|
|
72
|
+
return `
|
|
73
|
+
${MARKER}
|
|
74
|
+
def voltraProjectRoot = file("${projectRootRelativeToAppModule}")
|
|
75
|
+
def voltraWidgetAssetsDir = file("\${buildDir}/generated/voltra/assets")
|
|
76
|
+
android.sourceSets.getByName("main").assets.srcDir(voltraWidgetAssetsDir)
|
|
77
|
+
|
|
78
|
+
def voltraBundleWidgets = tasks.register("voltraBundleWidgets", Exec) {
|
|
79
|
+
description = "Bake Dynamic Widget Voltra bundles into assets (release)."
|
|
80
|
+
workingDir voltraProjectRoot
|
|
81
|
+
environment "VOLTRA_PROJECT_ROOT", voltraProjectRoot.absolutePath
|
|
82
|
+
environment "VOLTRA_OUT_DIR", new File(voltraWidgetAssetsDir, "voltra").absolutePath
|
|
83
|
+
environment "VOLTRA_BUNDLER_RESOLVER", "const m=require('module'),p=require('path');process.stdout.write(m.createRequire(p.join(process.argv[1],'package.json')).resolve('@use-voltra/metro/bundle-widgets'))"
|
|
84
|
+
commandLine "bash", "-c", 'BUNDLER="$(node -e "$VOLTRA_BUNDLER_RESOLVER" "$VOLTRA_PROJECT_ROOT")"; if [ -z "$BUNDLER" ]; then echo "error: Voltra could not resolve @use-voltra/metro/bundle-widgets from $VOLTRA_PROJECT_ROOT - install @use-voltra/metro so release widgets can be baked." >&2; exit 1; fi; node "$BUNDLER" --platform android --out-dir "$VOLTRA_OUT_DIR" --project-root "$VOLTRA_PROJECT_ROOT"'
|
|
85
|
+
outputs.upToDateWhen { false }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
android.applicationVariants.all { variant ->
|
|
89
|
+
if (variant.buildType.name == "release") {
|
|
90
|
+
tasks.named("merge\${variant.name.capitalize()}Assets").configure { dependsOn voltraBundleWidgets }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
${END_MARKER}
|
|
94
|
+
`.trim();
|
|
95
|
+
}
|
|
96
|
+
function createLegacyDynamicWidgetBundlingSnippet(projectRootRelativeToAppModule) {
|
|
97
|
+
return createDynamicWidgetBundlingSnippet(projectRootRelativeToAppModule).replace(`\n${END_MARKER}`, '');
|
|
98
|
+
}
|
|
99
|
+
function findManagedSnippetRange(contents) {
|
|
100
|
+
const markerIndex = contents.indexOf(MARKER);
|
|
101
|
+
if (markerIndex < 0) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const endMarkerIndex = contents.indexOf(END_MARKER, markerIndex);
|
|
105
|
+
if (endMarkerIndex < 0) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const lineEndIndex = contents.indexOf('\n', endMarkerIndex);
|
|
109
|
+
return {
|
|
110
|
+
start: markerIndex,
|
|
111
|
+
end: lineEndIndex >= 0 ? lineEndIndex + 1 : contents.length,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function collapseRemovedRange(contents, start, end) {
|
|
115
|
+
const before = contents.slice(0, start).trimEnd();
|
|
116
|
+
const after = contents.slice(end).replace(/^\s+/, '');
|
|
117
|
+
const merged = [before, after].filter(Boolean).join('\n\n');
|
|
118
|
+
return merged ? `${merged}\n` : '';
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=gradle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gradle.js","sourceRoot":"","sources":["../../../../src/platforms/android/gradle.ts"],"names":[],"mappings":";;;;;AAsBA,8EAqCC;AAED,0EAMC;AAED,gFA8BC;AAnGD,0DAA4B;AAE5B,wCAAqE;AACrE,kDAAgE;AAKhE,MAAM,MAAM,GAAG,4BAA4B,CAAA;AAC3C,MAAM,UAAU,GAAG,gCAAgC,CAAA;AAa5C,KAAK,UAAU,iCAAiC,CACrD,OAAiD;IAEjD,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAA;IAC7D,MAAM,WAAW,GAAG,SAAS,CAAC,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IAC9D,MAAM,8BAA8B,GAClC,IAAA,4BAAqB,EAAC,mBAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC,IAAI,GAAG,CAAA;IAEnF,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACvB,OAAO,EAAE,CAAA;QACX,CAAC;QAED,OAAO;YACL,QAAQ,EAAE,CAAC,2FAA2F,CAAC;SACxG,CAAA;IACH,CAAC;IAED,MAAM,eAAe,GAAG,MAAM,IAAA,wBAAY,EAAC,SAAS,CAAC,eAAe,CAAC,CAAA;IACrE,MAAM,OAAO,GAAG,kCAAkC,CAAC,eAAe,EAAE,8BAA8B,CAAC,CAAA;IACnG,MAAM,WAAW,GAAG,iBAAiB;QACnC,CAAC,CAAC,+BAA+B,CAAC,OAAO,CAAC,QAAQ,EAAE,8BAA8B,CAAC;QACnF,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAA;IAEpB,IAAI,WAAW,KAAK,eAAe,EAAE,CAAC;QACpC,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/D,CAAC;IAED,MAAM,IAAA,yBAAa,EAAC,SAAS,CAAC,eAAe,EAAE,WAAW,CAAC,CAAA;IAE3D,OAAO;QACL,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,IAAA,qBAAc,EAAC,WAAW,EAAE,SAAS,CAAC,eAAe,CAAC;SAC7D;QACD,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;KAC1D,CAAA;AACH,CAAC;AAED,SAAgB,+BAA+B,CAAC,QAAgB,EAAE,8BAAsC;IACtG,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9B,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAE,OAAO,kCAAkC,CAAC,8BAA8B,CAAC,IAAI,CAAA;AAC3G,CAAC;AAED,SAAgB,kCAAkC,CAChD,QAAgB,EAChB,8BAAsC;IAEtC,MAAM,KAAK,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAA;IAE/C,IAAI,KAAK,EAAE,CAAC;QACV,OAAO;YACL,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC;SACjE,CAAA;IACH,CAAC;IAED,MAAM,aAAa,GAAG,wCAAwC,CAAC,8BAA8B,CAAC,CAAA;IAC9F,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,CAAA;IAEnD,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;QACrB,OAAO;YACL,QAAQ,EAAE,oBAAoB,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC;SAC1F,CAAA;IACH,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,QAAQ,EAAE,CAAA;IACrB,CAAC;IAED,OAAO;QACL,QAAQ;QACR,OAAO,EACL,yLAAyL;KAC5L,CAAA;AACH,CAAC;AAED,SAAS,kCAAkC,CAAC,8BAAsC;IAChF,OAAO;EACP,MAAM;gCACwB,8BAA8B;;;;;;;;;;;;;;;;;;;EAmB5D,UAAU;CACX,CAAC,IAAI,EAAE,CAAA;AACR,CAAC;AAED,SAAS,wCAAwC,CAAC,8BAAsC;IACtF,OAAO,kCAAkC,CAAC,8BAA8B,CAAC,CAAC,OAAO,CAAC,KAAK,UAAU,EAAE,EAAE,EAAE,CAAC,CAAA;AAC1G,CAAC;AAED,SAAS,uBAAuB,CAAC,QAAgB;IAC/C,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IAC5C,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;QACpB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC,CAAA;IAChE,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAA;IAC3D,OAAO;QACL,KAAK,EAAE,WAAW;QAClB,GAAG,EAAE,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM;KAC5D,CAAA;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,QAAgB,EAAE,KAAa,EAAE,GAAW;IACxE,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,CAAA;IACjD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACrD,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAC3D,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;AACpC,CAAC"}
|
|
@@ -1,37 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
4
|
};
|
|
@@ -41,21 +8,20 @@ exports.generateIOSFiles = generateIOSFiles;
|
|
|
41
8
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
42
9
|
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
43
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
44
|
-
const node_vm_1 = __importDefault(require("node:vm"));
|
|
45
11
|
const node_module_1 = require("node:module");
|
|
46
|
-
const babel = __importStar(require("@babel/core"));
|
|
47
12
|
const platformPackages_1 = require("../../dependencies/platformPackages");
|
|
48
13
|
const readWrite_1 = require("../../fs/readWrite");
|
|
49
14
|
const path_1 = require("../../fs/path");
|
|
50
15
|
const summary_1 = require("../../reporting/summary");
|
|
16
|
+
const widgetModule_1 = require("../shared/widgetModule");
|
|
51
17
|
const plist_1 = require("./plist");
|
|
52
18
|
const targetName_1 = require("./targetName");
|
|
53
|
-
const MODULE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', ''];
|
|
54
19
|
const VALID_IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg']);
|
|
55
20
|
const FONT_EXTENSIONS = new Set(['.ttf', '.otf', '.woff', '.woff2']);
|
|
56
21
|
const MAX_IMAGE_SIZE_BYTES = 4096;
|
|
57
22
|
const DEFAULT_INITIAL_STATE_LOCALE = '__default';
|
|
58
23
|
const VOLTRA_WIDGET_STRINGS_BASENAME = 'VoltraWidgets.strings';
|
|
24
|
+
const IOS_DYNAMIC_WIDGET_MANIFEST_PATH = node_path_1.default.join('.voltra', 'manifest.ios.json');
|
|
59
25
|
const IOS_WIDGET_FAMILY_MAP = {
|
|
60
26
|
systemSmall: '.systemSmall',
|
|
61
27
|
systemMedium: '.systemMedium',
|
|
@@ -137,11 +103,13 @@ async function generateIOSFiles(options) {
|
|
|
137
103
|
const { projectRoot, ios, discovery } = options;
|
|
138
104
|
const targetName = (0, targetName_1.resolveIOSWidgetTargetName)(ios, discovery);
|
|
139
105
|
const targetPath = node_path_1.default.join(discovery.iosRoot, targetName);
|
|
106
|
+
const detectedWidgets = detectClientRenderedWidgets(projectRoot, ios.widgets);
|
|
140
107
|
const mainAppMetadata = await readMainAppMetadata(discovery.infoPlistPath);
|
|
141
108
|
const changes = [];
|
|
142
109
|
const warnings = [];
|
|
143
110
|
const generatedFiles = new Set();
|
|
144
|
-
|
|
111
|
+
mergeSingleResult(await writeGeneratedTextFile(projectRoot, node_path_1.default.join(projectRoot, IOS_DYNAMIC_WIDGET_MANIFEST_PATH), `${JSON.stringify(createDynamicWidgetsManifest(detectedWidgets), null, 2)}\n`), changes, generatedFiles);
|
|
112
|
+
const infoPlistResult = await generateInfoPlistFile(projectRoot, targetPath, targetName, ios, mainAppMetadata, detectedWidgets);
|
|
145
113
|
mergeSingleResult(infoPlistResult, changes, generatedFiles);
|
|
146
114
|
const entitlementsResult = await generateEntitlementsFile(projectRoot, targetPath, targetName, ios);
|
|
147
115
|
mergeSingleResult(entitlementsResult, changes, generatedFiles);
|
|
@@ -149,11 +117,11 @@ async function generateIOSFiles(options) {
|
|
|
149
117
|
mergeResult(assetResult, changes, warnings, generatedFiles);
|
|
150
118
|
const fontsResult = await copyIOSFonts(projectRoot, targetPath, ios.fonts);
|
|
151
119
|
mergeResult(fontsResult, changes, warnings, generatedFiles);
|
|
152
|
-
const initialStatesResult = await generateInitialStatesSwift(projectRoot,
|
|
120
|
+
const initialStatesResult = await generateInitialStatesSwift(projectRoot, detectedWidgets);
|
|
153
121
|
mergeSingleResult(await writeGeneratedTextFile(projectRoot, node_path_1.default.join(targetPath, 'VoltraWidgetInitialStates.swift'), initialStatesResult), changes, generatedFiles);
|
|
154
|
-
const widgetBundleResult = await writeGeneratedTextFile(projectRoot, node_path_1.default.join(targetPath, 'VoltraWidgetBundle.swift'), generateWidgetBundleSwift(
|
|
122
|
+
const widgetBundleResult = await writeGeneratedTextFile(projectRoot, node_path_1.default.join(targetPath, 'VoltraWidgetBundle.swift'), generateWidgetBundleSwift(detectedWidgets));
|
|
155
123
|
mergeSingleResult(widgetBundleResult, changes, generatedFiles);
|
|
156
|
-
const localizedStringResults = await generateLocalizedWidgetStrings(projectRoot, targetPath,
|
|
124
|
+
const localizedStringResults = await generateLocalizedWidgetStrings(projectRoot, targetPath, detectedWidgets);
|
|
157
125
|
mergeResult(localizedStringResults, changes, warnings, generatedFiles);
|
|
158
126
|
return {
|
|
159
127
|
changes,
|
|
@@ -163,10 +131,11 @@ async function generateIOSFiles(options) {
|
|
|
163
131
|
targetPath,
|
|
164
132
|
};
|
|
165
133
|
}
|
|
166
|
-
async function generateInfoPlistFile(projectRoot, targetPath, targetName, ios, mainAppMetadata) {
|
|
134
|
+
async function generateInfoPlistFile(projectRoot, targetPath, targetName, ios, mainAppMetadata, widgets) {
|
|
167
135
|
const plistPath = node_path_1.default.join(targetPath, 'Info.plist');
|
|
168
136
|
const fontNames = ios.fonts.map((fontPath) => node_path_1.default.basename(fontPath)).sort();
|
|
169
|
-
const serverWidgets =
|
|
137
|
+
const serverWidgets = widgets.filter((widget) => widget.serverUpdate);
|
|
138
|
+
const hasClientRenderedWidget = widgets.some((widget) => widget.clientRendered);
|
|
170
139
|
const serverUrls = Object.fromEntries(serverWidgets.map((widget) => [widget.id, widget.serverUpdate?.url]));
|
|
171
140
|
const serverIntervals = Object.fromEntries(serverWidgets.map((widget) => [widget.id, widget.serverUpdate?.intervalMinutes]));
|
|
172
141
|
const serverRefresh = Object.fromEntries(serverWidgets.map((widget) => [widget.id, widget.serverUpdate?.refresh ?? false]));
|
|
@@ -190,16 +159,30 @@ async function generateInfoPlistFile(projectRoot, targetPath, targetName, ios, m
|
|
|
190
159
|
Voltra_KeychainGroup: ios.keychainGroup,
|
|
191
160
|
Voltra_WidgetServerIntervals: Object.keys(serverIntervals).length > 0 ? serverIntervals : undefined,
|
|
192
161
|
Voltra_WidgetServerRefresh: Object.keys(serverRefresh).length > 0 ? serverRefresh : undefined,
|
|
193
|
-
NSAppTransportSecurity: serverWidgets.length > 0
|
|
194
|
-
? {
|
|
195
|
-
NSAllowsLocalNetworking: true,
|
|
196
|
-
NSAllowsArbitraryLoads: false,
|
|
197
|
-
}
|
|
198
|
-
: undefined,
|
|
162
|
+
NSAppTransportSecurity: createWidgetAppTransportSecurity(hasClientRenderedWidget, serverWidgets.length > 0),
|
|
199
163
|
Voltra_WidgetServerUrls: Object.keys(serverUrls).length > 0 ? serverUrls : undefined,
|
|
200
164
|
}, createGeneratedFilesError);
|
|
201
165
|
return writeGeneratedTextFile(projectRoot, plistPath, infoPlist);
|
|
202
166
|
}
|
|
167
|
+
function createWidgetAppTransportSecurity(hasClientRenderedWidget, hasServerWidgets) {
|
|
168
|
+
if (!hasClientRenderedWidget && !hasServerWidgets) {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
NSAllowsLocalNetworking: true,
|
|
173
|
+
...(hasClientRenderedWidget
|
|
174
|
+
? {
|
|
175
|
+
NSExceptionDomains: {
|
|
176
|
+
localhost: {
|
|
177
|
+
NSExceptionAllowsInsecureHTTPLoads: true,
|
|
178
|
+
NSIncludesSubdomains: true,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
}
|
|
182
|
+
: {}),
|
|
183
|
+
...(hasServerWidgets ? { NSAllowsArbitraryLoads: false } : {}),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
203
186
|
async function generateEntitlementsFile(projectRoot, targetPath, targetName, ios) {
|
|
204
187
|
const entitlementsPath = node_path_1.default.join(targetPath, `${targetName}.entitlements`);
|
|
205
188
|
const entitlements = (0, plist_1.buildPlistXml)({
|
|
@@ -294,8 +277,12 @@ async function readMainAppMetadata(infoPlistPath) {
|
|
|
294
277
|
};
|
|
295
278
|
}
|
|
296
279
|
async function generateInitialStatesSwift(projectRoot, widgets) {
|
|
297
|
-
const
|
|
298
|
-
|
|
280
|
+
const serverWidgets = widgets.filter((widget) => !widget.clientRendered);
|
|
281
|
+
const prerenderableServerWidgets = serverWidgets.filter((widget) => widget.initialStatePath);
|
|
282
|
+
const serverStates = await prerenderWidgetStates(projectRoot, prerenderableServerWidgets, loadIOSWidgetRenderer(projectRoot));
|
|
283
|
+
const clientStates = await prerenderClientRenderedWidgets(projectRoot, widgets);
|
|
284
|
+
const prerenderedStates = new Map([...serverStates, ...clientStates]);
|
|
285
|
+
if (prerenderedStates.size === 0) {
|
|
299
286
|
return [
|
|
300
287
|
'//',
|
|
301
288
|
'// VoltraWidgetInitialStates.swift',
|
|
@@ -314,7 +301,6 @@ async function generateInitialStatesSwift(projectRoot, widgets) {
|
|
|
314
301
|
'',
|
|
315
302
|
].join('\n');
|
|
316
303
|
}
|
|
317
|
-
const prerenderedStates = await prerenderWidgetStates(projectRoot, prerenderableWidgets, loadIOSWidgetRenderer(projectRoot));
|
|
318
304
|
const widgetEntries = [...prerenderedStates.entries()]
|
|
319
305
|
.map(([widgetId, localeMap]) => {
|
|
320
306
|
const localeEntries = [...localeMap.entries()]
|
|
@@ -357,8 +343,10 @@ async function generateInitialStatesSwift(projectRoot, widgets) {
|
|
|
357
343
|
}
|
|
358
344
|
function generateWidgetBundleSwift(widgets) {
|
|
359
345
|
const needsFoundation = widgets.some((widget) => isWidgetLocalizedMap(widget.displayName) || isWidgetLocalizedMap(widget.description));
|
|
346
|
+
const appIntentWidgets = widgets.filter(widgetUsesAppIntent);
|
|
360
347
|
const imports = [
|
|
361
348
|
needsFoundation ? 'import Foundation' : undefined,
|
|
349
|
+
appIntentWidgets.length > 0 ? 'import AppIntents' : undefined,
|
|
362
350
|
'import SwiftUI',
|
|
363
351
|
'import WidgetKit',
|
|
364
352
|
'import VoltraWidget',
|
|
@@ -385,7 +373,14 @@ function generateWidgetBundleSwift(widgets) {
|
|
|
385
373
|
].join('\n');
|
|
386
374
|
}
|
|
387
375
|
const widgetStructs = widgets.map(generateWidgetStruct).join('\n\n');
|
|
388
|
-
const
|
|
376
|
+
const plainWidgets = widgets.filter((widget) => !widgetUsesAppIntent(widget));
|
|
377
|
+
const plainInstances = plainWidgets.map((widget) => ` VoltraWidget_${widget.id}()`).join('\n');
|
|
378
|
+
const appIntentInstances = appIntentWidgets.length > 0
|
|
379
|
+
? ` if #available(iOS 17.0, *) {\n${appIntentWidgets
|
|
380
|
+
.map((widget) => ` VoltraWidget_${widget.id}()`)
|
|
381
|
+
.join('\n')}\n }`
|
|
382
|
+
: '';
|
|
383
|
+
const widgetInstances = [plainInstances, appIntentInstances].filter(Boolean).join('\n');
|
|
389
384
|
return [
|
|
390
385
|
'//',
|
|
391
386
|
'// VoltraWidgetBundle.swift',
|
|
@@ -408,9 +403,32 @@ function generateWidgetBundleSwift(widgets) {
|
|
|
408
403
|
].join('\n');
|
|
409
404
|
}
|
|
410
405
|
function generateWidgetStruct(widget) {
|
|
406
|
+
if (widgetUsesAppIntent(widget)) {
|
|
407
|
+
return generateClientAppIntentWidgetCode(widget);
|
|
408
|
+
}
|
|
411
409
|
const familiesSwift = widget.supportedFamilies.map((family) => IOS_WIDGET_FAMILY_MAP[family]).join(', ');
|
|
412
410
|
const displayNameExpr = createSwiftLabelExpression(widget.id, 'displayName', widget.displayName);
|
|
413
411
|
const descriptionExpr = createSwiftLabelExpression(widget.id, 'description', widget.description);
|
|
412
|
+
const providerAndContent = widget.clientRendered
|
|
413
|
+
? [
|
|
414
|
+
' provider: VoltraClientWidgetProvider(',
|
|
415
|
+
' widgetId: widgetId,',
|
|
416
|
+
' initialState: VoltraWidgetInitialStates.getInitialState(for: widgetId)',
|
|
417
|
+
' )',
|
|
418
|
+
' ) { entry in',
|
|
419
|
+
' VoltraClientWidgetContentView(',
|
|
420
|
+
' entry: entry,',
|
|
421
|
+
' initialState: VoltraWidgetInitialStates.getInitialState(for: widgetId)',
|
|
422
|
+
' )',
|
|
423
|
+
].join('\n')
|
|
424
|
+
: [
|
|
425
|
+
' provider: VoltraHomeWidgetProvider(',
|
|
426
|
+
' widgetId: widgetId,',
|
|
427
|
+
' initialState: VoltraWidgetInitialStates.getInitialState(for: widgetId)',
|
|
428
|
+
' )',
|
|
429
|
+
' ) { entry in',
|
|
430
|
+
' VoltraHomeWidgetView(entry: entry)',
|
|
431
|
+
].join('\n');
|
|
414
432
|
return [
|
|
415
433
|
`public struct VoltraWidget_${widget.id}: Widget {`,
|
|
416
434
|
` private let widgetId = ${JSON.stringify(widget.id)}`,
|
|
@@ -420,12 +438,85 @@ function generateWidgetStruct(widget) {
|
|
|
420
438
|
' public var body: some WidgetConfiguration {',
|
|
421
439
|
' StaticConfiguration(',
|
|
422
440
|
` kind: ${JSON.stringify(`Voltra_Widget_${widget.id}`)},`,
|
|
423
|
-
|
|
424
|
-
'
|
|
441
|
+
providerAndContent,
|
|
442
|
+
' }',
|
|
443
|
+
` .configurationDisplayName(${displayNameExpr})`,
|
|
444
|
+
` .description(${descriptionExpr})`,
|
|
445
|
+
` .supportedFamilies([${familiesSwift}])`,
|
|
446
|
+
' .contentMarginsDisabled()',
|
|
447
|
+
' }',
|
|
448
|
+
'}',
|
|
449
|
+
].join('\n');
|
|
450
|
+
}
|
|
451
|
+
function widgetUsesAppIntent(widget) {
|
|
452
|
+
return widget.clientRendered && !!widget.appIntent && widget.appIntent.parameters.length > 0;
|
|
453
|
+
}
|
|
454
|
+
function generateClientAppIntentWidgetCode(widget) {
|
|
455
|
+
const familiesSwift = widget.supportedFamilies.map((family) => IOS_WIDGET_FAMILY_MAP[family]).join(', ');
|
|
456
|
+
const intentName = `VoltraWidget_${widget.id}_Intent`;
|
|
457
|
+
const providerName = `VoltraWidget_${widget.id}_ClientProvider`;
|
|
458
|
+
const intentTitle = `Configure ${widgetLabelEnglish(widget.displayName)}`;
|
|
459
|
+
const displayNameExpr = createSwiftLabelExpression(widget.id, 'displayName', widget.displayName);
|
|
460
|
+
const descriptionExpr = createSwiftLabelExpression(widget.id, 'description', widget.description);
|
|
461
|
+
const parameterDeclarations = widget.appIntent.parameters
|
|
462
|
+
.map((parameter) => ` @Parameter(title: ${JSON.stringify(parameter.title)}, default: ${swiftDefaultValue(parameter)})\n var ${parameter.name}: String`)
|
|
463
|
+
.join('\n\n');
|
|
464
|
+
const initializerParameters = widget.appIntent.parameters.map((parameter) => `${parameter.name}: String`).join(', ');
|
|
465
|
+
const initializerAssignments = widget.appIntent.parameters
|
|
466
|
+
.map((parameter) => ` self.${parameter.name} = ${parameter.name}`)
|
|
467
|
+
.join('\n');
|
|
468
|
+
const configuredDictionary = createSwiftDictionaryLiteral(widget.appIntent.parameters.map((parameter) => `${JSON.stringify(parameter.name)}: configuration.${parameter.name}`));
|
|
469
|
+
const defaultDictionary = createSwiftDictionaryLiteral(widget.appIntent.parameters.map((parameter) => `${JSON.stringify(parameter.name)}: ${swiftDefaultValue(parameter)}`));
|
|
470
|
+
return [
|
|
471
|
+
`@available(iOS 17.0, *)`,
|
|
472
|
+
`struct ${intentName}: WidgetConfigurationIntent {`,
|
|
473
|
+
` static var title: LocalizedStringResource = ${JSON.stringify(intentTitle)}`,
|
|
474
|
+
'',
|
|
475
|
+
parameterDeclarations,
|
|
476
|
+
'',
|
|
477
|
+
' init() {}',
|
|
478
|
+
` init(${initializerParameters}) {`,
|
|
479
|
+
initializerAssignments,
|
|
480
|
+
' }',
|
|
481
|
+
'}',
|
|
482
|
+
'',
|
|
483
|
+
`@available(iOS 17.0, *)`,
|
|
484
|
+
`private struct ${providerName}: AppIntentTimelineProvider {`,
|
|
485
|
+
` typealias Intent = ${intentName}`,
|
|
486
|
+
' typealias Entry = VoltraClientWidgetEntry',
|
|
487
|
+
'',
|
|
488
|
+
` private let widgetId = ${JSON.stringify(widget.id)}`,
|
|
489
|
+
'',
|
|
490
|
+
' func placeholder(in _: Context) -> VoltraClientWidgetEntry {',
|
|
491
|
+
` VoltraClientWidgetEntry(date: Date(), widgetId: widgetId, bundleReady: false, configuration: ${defaultDictionary})`,
|
|
492
|
+
' }',
|
|
493
|
+
'',
|
|
494
|
+
` func snapshot(for configuration: ${intentName}, in _: Context) async -> VoltraClientWidgetEntry {`,
|
|
495
|
+
` await VoltraClientWidgetProvider.loadEntry(widgetId: widgetId, configuration: ${configuredDictionary})`,
|
|
496
|
+
' }',
|
|
497
|
+
'',
|
|
498
|
+
` func timeline(for configuration: ${intentName}, in _: Context) async -> Timeline<VoltraClientWidgetEntry> {`,
|
|
499
|
+
` let entry = await VoltraClientWidgetProvider.loadEntry(widgetId: widgetId, configuration: ${configuredDictionary})`,
|
|
500
|
+
' return Timeline(entries: [entry], policy: .never)',
|
|
501
|
+
' }',
|
|
502
|
+
'}',
|
|
503
|
+
'',
|
|
504
|
+
`@available(iOS 17.0, *)`,
|
|
505
|
+
`public struct VoltraWidget_${widget.id}: Widget {`,
|
|
506
|
+
` private let widgetId = ${JSON.stringify(widget.id)}`,
|
|
507
|
+
'',
|
|
508
|
+
' public init() {}',
|
|
509
|
+
'',
|
|
510
|
+
' public var body: some WidgetConfiguration {',
|
|
511
|
+
' AppIntentConfiguration(',
|
|
512
|
+
` kind: ${JSON.stringify(`Voltra_Widget_${widget.id}`)},`,
|
|
513
|
+
` intent: ${intentName}.self,`,
|
|
514
|
+
` provider: ${providerName}()`,
|
|
515
|
+
' ) { entry in',
|
|
516
|
+
' VoltraClientWidgetContentView(',
|
|
517
|
+
' entry: entry,',
|
|
425
518
|
' initialState: VoltraWidgetInitialStates.getInitialState(for: widgetId)',
|
|
426
519
|
' )',
|
|
427
|
-
' ) { entry in',
|
|
428
|
-
' VoltraHomeWidgetView(entry: entry)',
|
|
429
520
|
' }',
|
|
430
521
|
` .configurationDisplayName(${displayNameExpr})`,
|
|
431
522
|
` .description(${descriptionExpr})`,
|
|
@@ -443,6 +534,12 @@ function createSwiftLabelExpression(widgetId, field, label) {
|
|
|
443
534
|
const defaultEnglish = widgetLabelEnglish(label);
|
|
444
535
|
return `Text(LocalizedStringResource(${JSON.stringify(key)}, defaultValue: String.LocalizationValue(${JSON.stringify(defaultEnglish)}), table: ${JSON.stringify('VoltraWidgets')}))`;
|
|
445
536
|
}
|
|
537
|
+
function swiftDefaultValue(parameter) {
|
|
538
|
+
return JSON.stringify(parameter.default ?? '');
|
|
539
|
+
}
|
|
540
|
+
function createSwiftDictionaryLiteral(entries) {
|
|
541
|
+
return entries.length > 0 ? `[${entries.join(', ')}]` : '[:]';
|
|
542
|
+
}
|
|
446
543
|
async function prerenderWidgetStates(projectRoot, widgets, renderer) {
|
|
447
544
|
const prerenderedStates = new Map();
|
|
448
545
|
for (const widget of widgets) {
|
|
@@ -456,47 +553,15 @@ async function prerenderWidgetStates(projectRoot, widgets, renderer) {
|
|
|
456
553
|
if (!(await (0, readWrite_1.pathExists)(modulePath))) {
|
|
457
554
|
throw new IOSGeneratedFilesError(`Initial state file not found for widget '${widget.id}' at ${modulePath}`);
|
|
458
555
|
}
|
|
459
|
-
const widgetVariants =
|
|
556
|
+
const widgetVariants = evaluateLegacyWidgetModule(projectRoot, modulePath);
|
|
460
557
|
localeStates.set(localeKey, renderer(widgetVariants));
|
|
461
558
|
}
|
|
462
559
|
prerenderedStates.set(widget.id, localeStates);
|
|
463
560
|
}
|
|
464
561
|
return prerenderedStates;
|
|
465
562
|
}
|
|
466
|
-
function
|
|
467
|
-
const
|
|
468
|
-
const moduleCache = new Map();
|
|
469
|
-
const customRequire = (moduleSpecifier, currentDir) => {
|
|
470
|
-
if (!isLocalModule(moduleSpecifier)) {
|
|
471
|
-
return projectRequire(moduleSpecifier);
|
|
472
|
-
}
|
|
473
|
-
const resolvedModulePath = resolveModulePath(moduleSpecifier, currentDir);
|
|
474
|
-
if (!resolvedModulePath) {
|
|
475
|
-
throw new IOSGeneratedFilesError(`Cannot resolve module '${moduleSpecifier}' from '${currentDir}'`);
|
|
476
|
-
}
|
|
477
|
-
const cachedModule = moduleCache.get(resolvedModulePath);
|
|
478
|
-
if (cachedModule !== undefined) {
|
|
479
|
-
return cachedModule;
|
|
480
|
-
}
|
|
481
|
-
const transpiledCode = transpileWidgetModule(projectRoot, resolvedModulePath, projectRequire);
|
|
482
|
-
const moduleDir = node_path_1.default.dirname(resolvedModulePath);
|
|
483
|
-
const moduleRecord = { exports: {} };
|
|
484
|
-
moduleCache.set(resolvedModulePath, moduleRecord.exports);
|
|
485
|
-
const context = node_vm_1.default.createContext({
|
|
486
|
-
__dirname: moduleDir,
|
|
487
|
-
__filename: resolvedModulePath,
|
|
488
|
-
console,
|
|
489
|
-
exports: moduleRecord.exports,
|
|
490
|
-
module: moduleRecord,
|
|
491
|
-
process,
|
|
492
|
-
require: (specifier) => customRequire(specifier, moduleDir),
|
|
493
|
-
});
|
|
494
|
-
const script = new node_vm_1.default.Script(transpiledCode, { filename: resolvedModulePath });
|
|
495
|
-
script.runInContext(context);
|
|
496
|
-
moduleCache.set(resolvedModulePath, moduleRecord.exports);
|
|
497
|
-
return moduleRecord.exports;
|
|
498
|
-
};
|
|
499
|
-
const exports = customRequire(filePath, node_path_1.default.dirname(filePath));
|
|
563
|
+
function evaluateLegacyWidgetModule(projectRoot, filePath) {
|
|
564
|
+
const exports = (0, widgetModule_1.evaluateWidgetModuleExports)(projectRoot, filePath, createGeneratedFilesError);
|
|
500
565
|
const widgetVariants = exports.default ?? exports;
|
|
501
566
|
if (!widgetVariants || typeof widgetVariants !== 'object') {
|
|
502
567
|
throw new IOSGeneratedFilesError(`Widget file must export widget variants: ${filePath}`);
|
|
@@ -510,68 +575,107 @@ function loadIOSWidgetRenderer(projectRoot) {
|
|
|
510
575
|
}
|
|
511
576
|
return iosPackage.renderWidgetToString;
|
|
512
577
|
}
|
|
513
|
-
function
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
babelrc: false,
|
|
518
|
-
configFile: projectBabelConfigPath,
|
|
519
|
-
cwd: projectRoot,
|
|
520
|
-
filename: filePath,
|
|
521
|
-
presets: projectBabelConfigPath ? undefined : [resolveFallbackBabelPreset(projectRequire)],
|
|
522
|
-
});
|
|
523
|
-
if (!result?.code) {
|
|
524
|
-
throw new IOSGeneratedFilesError(`Babel transpilation failed for ${filePath}`);
|
|
525
|
-
}
|
|
526
|
-
return result.code;
|
|
527
|
-
}
|
|
528
|
-
function resolveProjectBabelConfig(projectRoot) {
|
|
529
|
-
const candidates = ['babel.config.js', 'babel.config.cjs', 'babel.config.mjs'];
|
|
530
|
-
for (const candidate of candidates) {
|
|
531
|
-
const candidatePath = node_path_1.default.join(projectRoot, candidate);
|
|
532
|
-
if (node_fs_1.default.existsSync(candidatePath)) {
|
|
533
|
-
return candidatePath;
|
|
534
|
-
}
|
|
578
|
+
function loadIOSDynamicWidgetRenderer(projectRoot) {
|
|
579
|
+
const iosPackage = (0, platformPackages_1.requirePlatformPackage)(projectRoot, 'ios');
|
|
580
|
+
if (typeof iosPackage.renderVoltraVariantToJson !== 'function') {
|
|
581
|
+
throw new IOSGeneratedFilesError('Installed @use-voltra/ios package does not export renderVoltraVariantToJson.');
|
|
535
582
|
}
|
|
536
|
-
return
|
|
583
|
+
return iosPackage.renderVoltraVariantToJson;
|
|
537
584
|
}
|
|
538
|
-
function
|
|
539
|
-
|
|
540
|
-
|
|
585
|
+
function createDynamicWidgetsManifest(widgets) {
|
|
586
|
+
return {
|
|
587
|
+
version: 1,
|
|
588
|
+
platform: 'ios',
|
|
589
|
+
widgets: widgets
|
|
590
|
+
.filter((widget) => widget.clientRendered)
|
|
591
|
+
.map((widget) => ({
|
|
592
|
+
id: widget.id,
|
|
593
|
+
entry: widget.entry,
|
|
594
|
+
})),
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
function detectClientRenderedWidgets(projectRoot, widgets) {
|
|
598
|
+
return widgets.map((widget) => detectSingleWidget(projectRoot, widget));
|
|
599
|
+
}
|
|
600
|
+
function detectSingleWidget(projectRoot, widget) {
|
|
601
|
+
if (!widget.entry) {
|
|
602
|
+
return {
|
|
603
|
+
...widget,
|
|
604
|
+
clientRendered: false,
|
|
605
|
+
};
|
|
541
606
|
}
|
|
542
|
-
|
|
607
|
+
const clientSourcePath = node_path_1.default.join(projectRoot, widget.entry);
|
|
608
|
+
if (!node_fs_1.default.existsSync(clientSourcePath) || !node_fs_1.default.statSync(clientSourcePath).isFile()) {
|
|
609
|
+
throw createGeneratedFilesError(`[voltra] Dynamic Widget "${widget.id}" entry not found at ${widget.entry}`);
|
|
610
|
+
}
|
|
611
|
+
const widgetModule = safelyEvaluateDynamicWidget(projectRoot, widget.id, widget.entry, clientSourcePath);
|
|
612
|
+
const widgetFn = readDynamicWidgetExport(widget.id, widget.entry, widgetModule);
|
|
613
|
+
if (typeof widgetFn !== 'function') {
|
|
614
|
+
throw createGeneratedFilesError(`[voltra] Dynamic Widget "${widget.id}" at ${widget.entry} must default-export a function or component.`);
|
|
615
|
+
}
|
|
616
|
+
return {
|
|
617
|
+
...widget,
|
|
618
|
+
entry: widget.entry,
|
|
619
|
+
clientRendered: true,
|
|
620
|
+
clientSourcePath,
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
async function prerenderClientRenderedWidgets(projectRoot, widgets) {
|
|
624
|
+
const clientWidgets = widgets.filter((widget) => widget.clientRendered);
|
|
625
|
+
if (clientWidgets.length === 0) {
|
|
626
|
+
return new Map();
|
|
627
|
+
}
|
|
628
|
+
const renderer = loadIOSDynamicWidgetRenderer(projectRoot);
|
|
629
|
+
const placeholderEnv = {
|
|
630
|
+
date: Date.now(),
|
|
631
|
+
widgetFamily: 'systemMedium',
|
|
632
|
+
colorScheme: 'light',
|
|
633
|
+
locale: 'en-US',
|
|
634
|
+
widgetRenderingMode: 'fullColor',
|
|
635
|
+
showsWidgetContainerBackground: true,
|
|
636
|
+
configuration: undefined,
|
|
637
|
+
build: widgetModule_1.DYNAMIC_WIDGET_BUILD_INFO,
|
|
638
|
+
};
|
|
639
|
+
const prerenderedStates = new Map();
|
|
640
|
+
for (const widget of clientWidgets) {
|
|
543
641
|
try {
|
|
544
|
-
|
|
642
|
+
const widgetModule = safelyEvaluateDynamicWidget(projectRoot, widget.id, widget.entry, widget.clientSourcePath);
|
|
643
|
+
const widgetFn = readDynamicWidgetExport(widget.id, widget.entry, widgetModule);
|
|
644
|
+
const element = widgetFn({}, placeholderEnv);
|
|
645
|
+
prerenderedStates.set(widget.id, new Map([[DEFAULT_INITIAL_STATE_LOCALE, JSON.stringify(renderer(element))]]));
|
|
545
646
|
}
|
|
546
|
-
catch {
|
|
547
|
-
|
|
647
|
+
catch (error) {
|
|
648
|
+
if (error instanceof IOSGeneratedFilesError) {
|
|
649
|
+
throw error;
|
|
650
|
+
}
|
|
651
|
+
throw createGeneratedFilesError(`[voltra] Dynamic Widget "${widget.id}" failed placeholder prerender at ${widget.entry}: ${error instanceof Error ? error.message : String(error)}`);
|
|
548
652
|
}
|
|
549
653
|
}
|
|
654
|
+
return prerenderedStates;
|
|
550
655
|
}
|
|
551
|
-
function
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
function isLocalModule(moduleSpecifier) {
|
|
555
|
-
return moduleSpecifier.startsWith('.') || moduleSpecifier.startsWith('/');
|
|
556
|
-
}
|
|
557
|
-
function resolveModulePath(moduleSpecifier, fromDir) {
|
|
558
|
-
const basePath = node_path_1.default.resolve(fromDir, moduleSpecifier);
|
|
559
|
-
for (const extension of MODULE_EXTENSIONS) {
|
|
560
|
-
const candidate = `${basePath}${extension}`;
|
|
561
|
-
if (node_fs_1.default.existsSync(candidate) && node_fs_1.default.statSync(candidate).isFile()) {
|
|
562
|
-
return candidate;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
if (!node_fs_1.default.existsSync(basePath) || !node_fs_1.default.statSync(basePath).isDirectory()) {
|
|
566
|
-
return null;
|
|
656
|
+
function safelyEvaluateDynamicWidget(projectRoot, widgetId, widgetEntry, clientSourcePath) {
|
|
657
|
+
try {
|
|
658
|
+
return (0, widgetModule_1.evaluateWidgetModuleExports)(projectRoot, clientSourcePath, createGeneratedFilesError);
|
|
567
659
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
return indexCandidate;
|
|
660
|
+
catch (error) {
|
|
661
|
+
if (error instanceof IOSGeneratedFilesError) {
|
|
662
|
+
throw error;
|
|
572
663
|
}
|
|
664
|
+
throw createGeneratedFilesError(`[voltra] Dynamic Widget "${widgetId}" failed to evaluate entry at ${widgetEntry}: ${error instanceof Error ? error.message : String(error)}`);
|
|
573
665
|
}
|
|
574
|
-
|
|
666
|
+
}
|
|
667
|
+
function readDynamicWidgetExport(widgetId, widgetEntry, widgetModule) {
|
|
668
|
+
const exports = widgetModule && typeof widgetModule === 'object'
|
|
669
|
+
? widgetModule
|
|
670
|
+
: { default: widgetModule };
|
|
671
|
+
const widgetFn = exports.default ?? widgetModule;
|
|
672
|
+
if (typeof widgetFn !== 'function') {
|
|
673
|
+
throw createGeneratedFilesError(`[voltra] Dynamic Widget "${widgetId}" at ${widgetEntry} must default-export a function or component.`);
|
|
674
|
+
}
|
|
675
|
+
return widgetFn;
|
|
676
|
+
}
|
|
677
|
+
function createProjectRequire(projectRoot) {
|
|
678
|
+
return (0, node_module_1.createRequire)(node_path_1.default.join(projectRoot, 'package.json'));
|
|
575
679
|
}
|
|
576
680
|
async function resolveFontPaths(projectRoot, fonts) {
|
|
577
681
|
const projectRequire = createProjectRequire(projectRoot);
|