agent-scenario-loop 0.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/LICENSE +21 -0
- package/README.md +119 -0
- package/app/profile-session.ts +812 -0
- package/core/config-template.json +41 -0
- package/dist/core/agent-summary.d.ts +15 -0
- package/dist/core/agent-summary.js +177 -0
- package/dist/core/artifact-contract.d.ts +151 -0
- package/dist/core/artifact-contract.js +897 -0
- package/dist/core/artifact-layout.d.ts +56 -0
- package/dist/core/artifact-layout.js +61 -0
- package/dist/core/artifact-writer.d.ts +44 -0
- package/dist/core/artifact-writer.js +55 -0
- package/dist/core/comparison.d.ts +133 -0
- package/dist/core/comparison.js +294 -0
- package/dist/core/evidence-interpreter.d.ts +28 -0
- package/dist/core/evidence-interpreter.js +69 -0
- package/dist/core/execution-plan.d.ts +44 -0
- package/dist/core/execution-plan.js +95 -0
- package/dist/core/planner.d.ts +132 -0
- package/dist/core/planner.js +812 -0
- package/dist/core/ports.d.ts +198 -0
- package/dist/core/ports.js +146 -0
- package/dist/core/run-index.d.ts +62 -0
- package/dist/core/run-index.js +143 -0
- package/dist/core/schema-validator.d.ts +86 -0
- package/dist/core/schema-validator.js +407 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +27 -0
- package/dist/runner/agent-device-driver.d.ts +126 -0
- package/dist/runner/agent-device-driver.js +168 -0
- package/dist/runner/agent-device.d.ts +295 -0
- package/dist/runner/agent-device.js +1271 -0
- package/dist/runner/android-adb-driver.d.ts +175 -0
- package/dist/runner/android-adb-driver.js +399 -0
- package/dist/runner/android-adb.d.ts +254 -0
- package/dist/runner/android-adb.js +1618 -0
- package/dist/runner/argent-driver.d.ts +183 -0
- package/dist/runner/argent-driver.js +297 -0
- package/dist/runner/argent.d.ts +349 -0
- package/dist/runner/argent.js +1211 -0
- package/dist/runner/check-plan.d.ts +45 -0
- package/dist/runner/check-plan.js +210 -0
- package/dist/runner/cli.d.ts +20 -0
- package/dist/runner/cli.js +23 -0
- package/dist/runner/compare-latest.d.ts +99 -0
- package/dist/runner/compare-latest.js +233 -0
- package/dist/runner/compare.d.ts +58 -0
- package/dist/runner/compare.js +157 -0
- package/dist/runner/demo-loop.d.ts +45 -0
- package/dist/runner/demo-loop.js +170 -0
- package/dist/runner/example-android-live.d.ts +137 -0
- package/dist/runner/example-android-live.js +454 -0
- package/dist/runner/example-ios-live.d.ts +137 -0
- package/dist/runner/example-ios-live.js +471 -0
- package/dist/runner/host-doctor.d.ts +131 -0
- package/dist/runner/host-doctor.js +628 -0
- package/dist/runner/init-project.d.ts +88 -0
- package/dist/runner/init-project.js +263 -0
- package/dist/runner/ios-simctl-driver.d.ts +69 -0
- package/dist/runner/ios-simctl-driver.js +97 -0
- package/dist/runner/ios-simctl.d.ts +254 -0
- package/dist/runner/ios-simctl.js +1415 -0
- package/dist/runner/live-android.d.ts +137 -0
- package/dist/runner/live-android.js +539 -0
- package/dist/runner/live-comparison.d.ts +67 -0
- package/dist/runner/live-comparison.js +147 -0
- package/dist/runner/live-ios.d.ts +137 -0
- package/dist/runner/live-ios.js +460 -0
- package/dist/runner/live-proof-summary.d.ts +263 -0
- package/dist/runner/live-proof-summary.js +465 -0
- package/dist/runner/live-proof.d.ts +467 -0
- package/dist/runner/live-proof.js +920 -0
- package/dist/runner/local-env.d.ts +64 -0
- package/dist/runner/local-env.js +155 -0
- package/dist/runner/profile-android.d.ts +82 -0
- package/dist/runner/profile-android.js +671 -0
- package/dist/runner/profile-ios.d.ts +108 -0
- package/dist/runner/profile-ios.js +532 -0
- package/dist/runner/profile-mobile.d.ts +254 -0
- package/dist/runner/profile-mobile.js +1307 -0
- package/dist/runner/validate-project.d.ts +273 -0
- package/dist/runner/validate-project.js +1501 -0
- package/docs/adapters.md +145 -0
- package/docs/api.md +94 -0
- package/docs/authoring.md +196 -0
- package/docs/concepts.md +136 -0
- package/docs/consumer-rehearsal.md +115 -0
- package/docs/contracts.md +267 -0
- package/docs/live-proofs.md +270 -0
- package/docs/principles.md +46 -0
- package/examples/event-logs/app-startup-baseline.log +4 -0
- package/examples/event-logs/app-startup-current.log +4 -0
- package/examples/minimal-app/README.md +70 -0
- package/examples/mobile-app/README.md +302 -0
- package/examples/mobile-app/app.json +22 -0
- package/examples/mobile-app/asl/package-scripts.json +32 -0
- package/examples/mobile-app/asl.config.json +37 -0
- package/examples/mobile-app/event-logs/android-app-startup.log +4 -0
- package/examples/mobile-app/event-logs/android-open-close-cycle.log +12 -0
- package/examples/mobile-app/event-logs/android-scroll-settle.log +12 -0
- package/examples/mobile-app/event-logs/app-startup.log +4 -0
- package/examples/mobile-app/event-logs/open-close-cycle.log +12 -0
- package/examples/mobile-app/event-logs/scroll-settle.log +12 -0
- package/examples/mobile-app/index.ts +20 -0
- package/examples/mobile-app/metro.config.js +20 -0
- package/examples/mobile-app/package.json +62 -0
- package/examples/mobile-app/patches/expo-modules-jsi@56.0.10.patch +19 -0
- package/examples/mobile-app/plugins/with-ios-build-compat.js +271 -0
- package/examples/mobile-app/pnpm-lock.yaml +4440 -0
- package/examples/mobile-app/runner-manifests/evidence-provider.json +79 -0
- package/examples/mobile-app/runner-manifests/primary-runner.json +19 -0
- package/examples/mobile-app/scenarios/android/app-startup-video.json +73 -0
- package/examples/mobile-app/scenarios/android/app-startup.json +44 -0
- package/examples/mobile-app/scenarios/android/open-close-cycle.json +54 -0
- package/examples/mobile-app/scenarios/android/scroll-settle.json +49 -0
- package/examples/mobile-app/scenarios/ios/app-startup.json +44 -0
- package/examples/mobile-app/scenarios/ios/open-close-cycle.json +54 -0
- package/examples/mobile-app/scenarios/ios/scroll-settle.json +49 -0
- package/examples/mobile-app/scenarios/mobile/app-startup.json +91 -0
- package/examples/mobile-app/scenarios/mobile/open-close-cycle.json +160 -0
- package/examples/mobile-app/scenarios/mobile/scroll-settle.json +148 -0
- package/examples/mobile-app/scripts/asl-capture-accessibility-provider.mjs +112 -0
- package/examples/mobile-app/scripts/asl-capture-profiler-provider.mjs +127 -0
- package/examples/mobile-app/src/devtools/profile-session.ts +7 -0
- package/examples/mobile-app/src/example-screen.tsx +322 -0
- package/examples/mobile-app/tsconfig.json +16 -0
- package/examples/mobile-app/tsconfig.typecheck.json +13 -0
- package/examples/runners/README.md +44 -0
- package/examples/runners/adb-android.json +25 -0
- package/examples/runners/agent-device-android.json +27 -0
- package/examples/runners/agent-device-ios.json +27 -0
- package/examples/runners/argent-android.json +32 -0
- package/examples/runners/argent-ios.json +32 -0
- package/examples/runners/argent-react-profiler-provider.json +15 -0
- package/examples/runners/axe-accessibility-provider.json +24 -0
- package/examples/runners/manual-log-ingest.json +9 -0
- package/examples/runners/rozenite-profiler-provider.json +9 -0
- package/examples/runners/script-accessibility-provider.json +24 -0
- package/examples/runners/script-memory-provider.json +24 -0
- package/examples/runners/script-network-provider.json +24 -0
- package/examples/runners/script-profiler-provider.json +30 -0
- package/examples/runners/xcodebuildmcp-ios.json +29 -0
- package/examples/scenarios/ios/app-startup.json +28 -0
- package/examples/scenarios/ios/open-close-cycle.json +35 -0
- package/examples/scenarios/mobile/app-startup.json +72 -0
- package/examples/scenarios/mobile/media-open-close.json +141 -0
- package/examples/scenarios/mobile/open-close-cycle.json +135 -0
- package/examples/scenarios/mobile/scroll-settle.json +106 -0
- package/package.json +240 -0
- package/schemas/budget-verdict.schema.json +115 -0
- package/schemas/causal-run.schema.json +279 -0
- package/schemas/comparison.schema.json +196 -0
- package/schemas/health.schema.json +108 -0
- package/schemas/live-proof-set.schema.json +195 -0
- package/schemas/live-proof.schema.json +413 -0
- package/schemas/manifest.schema.json +204 -0
- package/schemas/metrics.schema.json +137 -0
- package/schemas/project-validation.schema.json +343 -0
- package/schemas/runner-capabilities.schema.json +217 -0
- package/schemas/scenario.schema.json +400 -0
- package/schemas/verdict.schema.json +88 -0
- package/templates/evidence-provider.json +83 -0
- package/templates/gitignore-snippet +9 -0
- package/templates/integration-readme.md +125 -0
- package/templates/mobile-scenario.json +133 -0
- package/templates/package-scripts.json +32 -0
- package/templates/primary-runner.json +19 -0
- package/templates/project.config.json +37 -0
- package/templates/scripts/asl-capture-accessibility-provider.mjs +112 -0
- package/templates/scripts/asl-capture-profiler-provider.mjs +127 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
diff --git a/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRuntime.swift b/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRuntime.swift
|
|
2
|
+
index 38f7305..c8156cd 100644
|
|
3
|
+
--- a/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRuntime.swift
|
|
4
|
+
+++ b/apple/Sources/ExpoModulesJSI/Runtime/JavaScriptRuntime.swift
|
|
5
|
+
@@ -216,6 +216,12 @@ public final class JavaScriptRuntime: @unchecked Sendable {
|
|
6
|
+
.toOpaque()
|
|
7
|
+
// Pass a null setter to C++ when the Swift setter is nil so that JS assignment
|
|
8
|
+
// raises a `jsi::JSError` directly, without crossing the Swift boundary.
|
|
9
|
+
- let callbacks = expo.HostObjectCallbacks(
|
|
10
|
+
- context, getter, set == nil ? nil : setter, propertyNamesGetter, deallocate)
|
|
11
|
+
+ let callbacks: expo.HostObjectCallbacks
|
|
12
|
+
+ if set == nil {
|
|
13
|
+
+ callbacks = expo.HostObjectCallbacks(
|
|
14
|
+
+ context, getter, nil, propertyNamesGetter, deallocate)
|
|
15
|
+
+ } else {
|
|
16
|
+
+ callbacks = expo.HostObjectCallbacks(
|
|
17
|
+
+ context, getter, setter, propertyNamesGetter, deallocate)
|
|
18
|
+
+ }
|
|
19
|
+
let hostObject = expo.HostObject.makeObject(pointee, consume callbacks)
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
const fs = require('node:fs');
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
|
|
4
|
+
const sceneDelegateContents = `import UIKit
|
|
5
|
+
|
|
6
|
+
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|
7
|
+
var window: UIWindow?
|
|
8
|
+
|
|
9
|
+
func scene(
|
|
10
|
+
_ scene: UIScene,
|
|
11
|
+
willConnectTo session: UISceneSession,
|
|
12
|
+
options connectionOptions: UIScene.ConnectionOptions
|
|
13
|
+
) {
|
|
14
|
+
guard let windowScene = scene as? UIWindowScene else {
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let window = UIWindow(windowScene: windowScene)
|
|
19
|
+
self.window = window
|
|
20
|
+
|
|
21
|
+
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
|
|
22
|
+
appDelegate.window = window
|
|
23
|
+
appDelegate.startReactNative(in: window)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
const deploymentTargetPatch = `
|
|
30
|
+
installer.pods_project.targets.each do |target|
|
|
31
|
+
target.build_configurations.each do |config|
|
|
32
|
+
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = podfile_properties['ios.deploymentTarget'] || '16.4'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
const reactNativeFactorySetup = ` let delegate = ReactNativeDelegate()
|
|
38
|
+
let factory = ExpoReactNativeFactory(delegate: delegate)
|
|
39
|
+
delegate.dependencyProvider = RCTAppDependencyProvider()
|
|
40
|
+
|
|
41
|
+
reactNativeDelegate = delegate
|
|
42
|
+
reactNativeFactory = factory`;
|
|
43
|
+
|
|
44
|
+
const prepareReactNativeFactoryFunction = ` func prepareReactNativeFactory() {
|
|
45
|
+
if reactNativeFactory != nil {
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let delegate = ReactNativeDelegate()
|
|
50
|
+
let factory = ExpoReactNativeFactory(delegate: delegate)
|
|
51
|
+
delegate.dependencyProvider = RCTAppDependencyProvider()
|
|
52
|
+
|
|
53
|
+
reactNativeDelegate = delegate
|
|
54
|
+
reactNativeFactory = factory
|
|
55
|
+
}`;
|
|
56
|
+
|
|
57
|
+
const recursivePrepareReactNativeFactoryFunction = ` func prepareReactNativeFactory() {
|
|
58
|
+
if reactNativeFactory != nil {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
prepareReactNativeFactory()
|
|
63
|
+
}`;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Applies the generated iOS compatibility patches needed by the Expo example app.
|
|
67
|
+
*/
|
|
68
|
+
function withIosBuildCompat(config) {
|
|
69
|
+
config = withPodsDeploymentTarget(config);
|
|
70
|
+
config = withSceneInfoPlist(config);
|
|
71
|
+
config = loadExpoConfigPlugins().IOSConfig.XcodeProjectFile.withBuildSourceFile(config, {
|
|
72
|
+
filePath: 'SceneDelegate.swift',
|
|
73
|
+
contents: sceneDelegateContents,
|
|
74
|
+
overwrite: true,
|
|
75
|
+
});
|
|
76
|
+
config = withSceneAppDelegate(config);
|
|
77
|
+
|
|
78
|
+
return config;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Loads Expo config plugins only when Expo executes the app-local plugin.
|
|
83
|
+
*/
|
|
84
|
+
function loadExpoConfigPlugins() {
|
|
85
|
+
return require('expo/config-plugins');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Pins all generated Pods deployment targets to the app target to avoid Xcode beta drift.
|
|
90
|
+
*/
|
|
91
|
+
function withPodsDeploymentTarget(config) {
|
|
92
|
+
const { withDangerousMod } = loadExpoConfigPlugins();
|
|
93
|
+
return withDangerousMod(config, [
|
|
94
|
+
'ios',
|
|
95
|
+
async (modConfig) => {
|
|
96
|
+
const podfilePath = path.join(modConfig.modRequest.platformProjectRoot, 'Podfile');
|
|
97
|
+
let podfile = fs.readFileSync(podfilePath, 'utf8');
|
|
98
|
+
|
|
99
|
+
if (podfile.includes("config.build_settings['IPHONEOS_DEPLOYMENT_TARGET']")) {
|
|
100
|
+
return modConfig;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const anchor = ` )
|
|
104
|
+
end
|
|
105
|
+
end`;
|
|
106
|
+
const replacement = ` )
|
|
107
|
+
${deploymentTargetPatch} end
|
|
108
|
+
end`;
|
|
109
|
+
|
|
110
|
+
if (!podfile.includes(anchor)) {
|
|
111
|
+
throw new Error('Unable to insert iOS build compatibility settings into generated Podfile.');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
podfile = podfile.replace(anchor, replacement);
|
|
115
|
+
fs.writeFileSync(podfilePath, podfile);
|
|
116
|
+
|
|
117
|
+
return modConfig;
|
|
118
|
+
},
|
|
119
|
+
]);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Declares a scene delegate so UIKit owns the window lifecycle on modern iOS.
|
|
124
|
+
*/
|
|
125
|
+
function withSceneInfoPlist(config) {
|
|
126
|
+
const { withInfoPlist } = loadExpoConfigPlugins();
|
|
127
|
+
return withInfoPlist(config, (modConfig) => {
|
|
128
|
+
modConfig.modResults.UIApplicationSceneManifest = {
|
|
129
|
+
UIApplicationSupportsMultipleScenes: false,
|
|
130
|
+
UISceneConfigurations: {
|
|
131
|
+
UIWindowSceneSessionRoleApplication: [
|
|
132
|
+
{
|
|
133
|
+
UISceneConfigurationName: 'Default Configuration',
|
|
134
|
+
UISceneDelegateClassName: '$(PRODUCT_MODULE_NAME).SceneDelegate',
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
return modConfig;
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Rewrites the generated Swift AppDelegate to defer React Native startup to SceneDelegate.
|
|
146
|
+
*/
|
|
147
|
+
function withSceneAppDelegate(config) {
|
|
148
|
+
const { withAppDelegate } = loadExpoConfigPlugins();
|
|
149
|
+
return withAppDelegate(config, (modConfig) => {
|
|
150
|
+
if (modConfig.modResults.language !== 'swift') {
|
|
151
|
+
throw new Error('Expected a Swift AppDelegate for the ASL example iOS app.');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
modConfig.modResults.contents = patchAppDelegate(modConfig.modResults.contents);
|
|
155
|
+
return modConfig;
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Produces an idempotent AppDelegate patch that works across repeated Expo prebuilds.
|
|
161
|
+
*/
|
|
162
|
+
function patchAppDelegate(contents) {
|
|
163
|
+
let next = contents;
|
|
164
|
+
|
|
165
|
+
if (next.includes(recursivePrepareReactNativeFactoryFunction)) {
|
|
166
|
+
next = next.replace(recursivePrepareReactNativeFactoryFunction, prepareReactNativeFactoryFunction);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
next = replaceBeforeAnchor(
|
|
170
|
+
next,
|
|
171
|
+
reactNativeFactorySetup,
|
|
172
|
+
' prepareReactNativeFactory()',
|
|
173
|
+
'#if os(iOS) || os(tvOS)',
|
|
174
|
+
'Unable to replace React Native factory setup in AppDelegate.swift.'
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
next = replaceOnce(
|
|
178
|
+
next,
|
|
179
|
+
`#if os(iOS) || os(tvOS)
|
|
180
|
+
window = UIWindow(frame: UIScreen.main.bounds)
|
|
181
|
+
factory.startReactNative(
|
|
182
|
+
withModuleName: "main",
|
|
183
|
+
in: window,
|
|
184
|
+
launchOptions: launchOptions)
|
|
185
|
+
#endif`,
|
|
186
|
+
`#if os(iOS) || os(tvOS)
|
|
187
|
+
if #unavailable(iOS 13.0) {
|
|
188
|
+
window = UIWindow(frame: UIScreen.main.bounds)
|
|
189
|
+
if let window {
|
|
190
|
+
startReactNative(in: window, launchOptions: launchOptions)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
#endif`,
|
|
194
|
+
'Unable to replace React Native startup window setup in AppDelegate.swift.'
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
if (!next.includes('func prepareReactNativeFactory()')) {
|
|
198
|
+
next = replaceOnce(
|
|
199
|
+
next,
|
|
200
|
+
` // Linking API`,
|
|
201
|
+
`${prepareReactNativeFactoryFunction}
|
|
202
|
+
|
|
203
|
+
func startReactNative(
|
|
204
|
+
in window: UIWindow,
|
|
205
|
+
launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
|
|
206
|
+
) {
|
|
207
|
+
prepareReactNativeFactory()
|
|
208
|
+
reactNativeFactory?.startReactNative(
|
|
209
|
+
withModuleName: "main",
|
|
210
|
+
in: window,
|
|
211
|
+
launchOptions: launchOptions)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public func application(
|
|
215
|
+
_ application: UIApplication,
|
|
216
|
+
configurationForConnecting connectingSceneSession: UISceneSession,
|
|
217
|
+
options: UIScene.ConnectionOptions
|
|
218
|
+
) -> UISceneConfiguration {
|
|
219
|
+
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Linking API`,
|
|
223
|
+
'Unable to insert scene lifecycle helpers into AppDelegate.swift.'
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return next;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Replaces one generated Swift fragment and fails loudly when the template shape changes.
|
|
232
|
+
*/
|
|
233
|
+
function replaceOnce(contents, search, replacement, message) {
|
|
234
|
+
const first = contents.indexOf(search);
|
|
235
|
+
if (first === -1) {
|
|
236
|
+
if (contents.includes(replacement)) {
|
|
237
|
+
return contents;
|
|
238
|
+
}
|
|
239
|
+
throw new Error(message);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const second = contents.indexOf(search, first + search.length);
|
|
243
|
+
if (second !== -1) {
|
|
244
|
+
throw new Error(`${message} Found multiple matches.`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return contents.slice(0, first) + replacement + contents.slice(first + search.length);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Replaces a generated Swift fragment only when it appears before a known anchor.
|
|
252
|
+
*/
|
|
253
|
+
function replaceBeforeAnchor(contents, search, replacement, anchor, message) {
|
|
254
|
+
const anchorIndex = contents.indexOf(anchor);
|
|
255
|
+
if (anchorIndex === -1) {
|
|
256
|
+
throw new Error(message);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const first = contents.indexOf(search);
|
|
260
|
+
if (first === -1 || first > anchorIndex) {
|
|
261
|
+
if (contents.slice(0, anchorIndex).includes(replacement)) {
|
|
262
|
+
return contents;
|
|
263
|
+
}
|
|
264
|
+
throw new Error(message);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return contents.slice(0, first) + replacement + contents.slice(first + search.length);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
module.exports = withIosBuildCompat;
|
|
271
|
+
module.exports.patchAppDelegate = patchAppDelegate;
|