peachsim 0.1.646 → 0.1.648
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/cli/desktop-companion.ts +48 -8
- package/cli/drivers/electron.ts +1 -3
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +1 -1
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +1 -1
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/native-app-identity.cjs +1 -1
- package/dist-lib/native-app-identity.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +24 -8
- package/dist-lib/swift-compile.cjs +15 -3
- package/dist-lib/swift-compile.mjs +15 -3
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +2 -2
- package/dist-lib/swift-submit.mjs +2 -2
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +1067 -1052
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/src/swift-compile.ts +31 -7
- package/src/swift-submit.ts +3 -1
- package/src/vite-plugin-swift.ts +10 -6
package/dist-lib/vite-swift.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.648 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -69,1141 +69,1153 @@ function swiftEntryModuleEsm(args) {
|
|
|
69
69
|
].join("\n");
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
// src/swift-
|
|
73
|
-
var
|
|
74
|
-
var
|
|
75
|
-
var
|
|
76
|
-
var
|
|
72
|
+
// src/swift-compile.ts
|
|
73
|
+
var import_node_child_process2 = require("node:child_process");
|
|
74
|
+
var import_node_crypto2 = require("node:crypto");
|
|
75
|
+
var import_node_fs2 = require("node:fs");
|
|
76
|
+
var import_node_os = __toESM(require("node:os"), 1);
|
|
77
|
+
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
78
|
+
var import_node_util2 = require("node:util");
|
|
77
79
|
|
|
78
|
-
//
|
|
79
|
-
var
|
|
80
|
-
var
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
80
|
+
// src/swift-icu.ts
|
|
81
|
+
var import_node_child_process = require("node:child_process");
|
|
82
|
+
var import_node_crypto = require("node:crypto");
|
|
83
|
+
var import_node_fs = require("node:fs");
|
|
84
|
+
var import_node_path = __toESM(require("node:path"), 1);
|
|
85
|
+
var import_node_util = require("node:util");
|
|
86
|
+
var import_node_zlib = require("node:zlib");
|
|
87
|
+
var run = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
88
|
+
var deflate = (0, import_node_util.promisify)(import_node_zlib.gzip);
|
|
89
|
+
var ARCHIVE = "wasi/lib_FoundationICU.a";
|
|
90
|
+
var MEMBER = "icu_packaged_data.cpp.obj";
|
|
91
|
+
var raw = /* @__PURE__ */ new Map();
|
|
92
|
+
var assets = /* @__PURE__ */ new Map();
|
|
93
|
+
function memo(cache, key, load2) {
|
|
94
|
+
let pending = cache.get(key);
|
|
95
|
+
if (!pending) {
|
|
96
|
+
pending = load2();
|
|
97
|
+
pending.catch(() => cache.delete(key));
|
|
98
|
+
cache.set(key, pending);
|
|
99
|
+
}
|
|
100
|
+
return pending;
|
|
93
101
|
}
|
|
94
|
-
function
|
|
95
|
-
|
|
96
|
-
return slash < 0 ? file : file.slice(slash + 1);
|
|
102
|
+
function swiftIcuData(toolchainBin, release) {
|
|
103
|
+
return memo(raw, `${toolchainBin}\0${release}`, () => load(toolchainBin, release));
|
|
97
104
|
}
|
|
98
|
-
function
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const rank = (scale) => scale === "2x" ? 0 : scale === "3x" ? 1 : scale === "1x" ? 2 : 3;
|
|
104
|
-
const pick = [...rasters].sort((a, b) => rank(a.scale) - rank(b.scale))[0];
|
|
105
|
-
return {
|
|
106
|
-
filename: pick.filename,
|
|
107
|
-
scale: pick.scale === "2x" ? 2 : pick.scale === "3x" ? 3 : 1
|
|
108
|
-
};
|
|
105
|
+
function swiftIcuAsset(toolchainBin, release) {
|
|
106
|
+
return memo(assets, `${toolchainBin}\0${release}`, async () => {
|
|
107
|
+
const zipped = await deflate(await swiftIcuData(toolchainBin, release));
|
|
108
|
+
return { sha256: (0, import_node_crypto.createHash)("sha256").update(zipped).digest("hex"), gzip: zipped };
|
|
109
|
+
});
|
|
109
110
|
}
|
|
110
|
-
function
|
|
111
|
-
const
|
|
112
|
-
|
|
111
|
+
async function load(toolchainBin, release) {
|
|
112
|
+
const { stdout } = await run(import_node_path.default.join(toolchainBin, "swift"), [
|
|
113
|
+
"sdk",
|
|
114
|
+
"configure",
|
|
115
|
+
"--show-configuration",
|
|
116
|
+
`${release}_wasm`,
|
|
117
|
+
"wasm32-unknown-wasip1"
|
|
118
|
+
]);
|
|
119
|
+
const resources = /^swiftStaticResourcesPath: (.+)$/m.exec(stdout)?.[1]?.trim();
|
|
120
|
+
if (!resources) throw new Error(`swift-icu: ${release}_wasm names no static resources`);
|
|
121
|
+
return Buffer.from(
|
|
122
|
+
icuSegment(archiveMember((0, import_node_fs.readFileSync)(import_node_path.default.join(resources, ARCHIVE)), MEMBER))
|
|
123
|
+
);
|
|
113
124
|
}
|
|
114
|
-
function
|
|
115
|
-
if (
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
125
|
+
function archiveMember(archive, name) {
|
|
126
|
+
if (archive.toString("latin1", 0, 8) !== "!<arch>\n")
|
|
127
|
+
throw new Error("swift-icu: not an ar archive");
|
|
128
|
+
let names = "";
|
|
129
|
+
for (let at = 8; at + 60 <= archive.length; ) {
|
|
130
|
+
const raw2 = archive.toString("latin1", at, at + 16).trimEnd();
|
|
131
|
+
const size = Number(archive.toString("latin1", at + 48, at + 58).trim());
|
|
132
|
+
const body = archive.subarray(at + 60, at + 60 + size);
|
|
133
|
+
if (raw2 === "//") names = body.toString("latin1");
|
|
134
|
+
const member = /^\/\d+$/.test(raw2) ? names.slice(Number(raw2.slice(1)), names.indexOf("/\n", Number(raw2.slice(1)))) : raw2.replace(/\/$/, "");
|
|
135
|
+
if (member === name) return body;
|
|
136
|
+
at += 60 + size + size % 2;
|
|
121
137
|
}
|
|
138
|
+
throw new Error(`swift-icu: ${name} is not in the sdk's icu archive`);
|
|
122
139
|
}
|
|
123
|
-
function
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
140
|
+
function icuSegment(object) {
|
|
141
|
+
let at = 8;
|
|
142
|
+
const leb = () => {
|
|
143
|
+
let result = 0;
|
|
144
|
+
let shift = 0;
|
|
145
|
+
let byte;
|
|
146
|
+
do {
|
|
147
|
+
byte = object[at++];
|
|
148
|
+
result += (byte & 127) * 2 ** shift;
|
|
149
|
+
shift += 7;
|
|
150
|
+
} while (byte & 128);
|
|
151
|
+
return result;
|
|
152
|
+
};
|
|
153
|
+
const found = [];
|
|
154
|
+
while (at < object.length) {
|
|
155
|
+
const id = object[at++];
|
|
156
|
+
const size = leb();
|
|
157
|
+
const end = at + size;
|
|
158
|
+
if (id === 11) {
|
|
159
|
+
for (let count = leb(); count > 0; count--) {
|
|
160
|
+
if (leb() !== 0) throw new Error("swift-icu: unexpected data segment kind");
|
|
161
|
+
at++;
|
|
162
|
+
leb();
|
|
163
|
+
at++;
|
|
164
|
+
const length = leb();
|
|
165
|
+
const bytes = object.subarray(at, at + length);
|
|
166
|
+
if (bytes[2] === 218 && bytes[3] === 39) found.push(bytes);
|
|
167
|
+
at += length;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
at = end;
|
|
135
171
|
}
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return path6.split("/").includes("Resources") && RASTER_EXTENSIONS.has(extOf(path6));
|
|
172
|
+
if (found.length !== 1)
|
|
173
|
+
throw new Error(`swift-icu: expected one icu data segment, found ${found.length}`);
|
|
174
|
+
return found[0];
|
|
140
175
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
176
|
+
|
|
177
|
+
// src/swift-package.ts
|
|
178
|
+
function swiftManifestTargets(manifest) {
|
|
179
|
+
const code = manifest.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
|
|
180
|
+
const targets = [];
|
|
181
|
+
const pattern = /\.(executableTarget|target)\s*\(/g;
|
|
182
|
+
let match;
|
|
183
|
+
while ((match = pattern.exec(code)) !== null) {
|
|
184
|
+
const executable = match[1] === "executableTarget";
|
|
185
|
+
let depth = 1;
|
|
186
|
+
const start = pattern.lastIndex;
|
|
187
|
+
let i = start;
|
|
188
|
+
let inString = false;
|
|
189
|
+
let escaped = false;
|
|
190
|
+
let flat = "";
|
|
191
|
+
while (i < code.length && depth > 0) {
|
|
192
|
+
const ch = code[i];
|
|
193
|
+
if (inString) {
|
|
194
|
+
if (escaped) escaped = false;
|
|
195
|
+
else if (ch === "\\") escaped = true;
|
|
196
|
+
else if (ch === '"') inString = false;
|
|
197
|
+
if (depth === 1) flat += ch;
|
|
198
|
+
} else if (ch === '"') {
|
|
199
|
+
inString = true;
|
|
200
|
+
if (depth === 1) flat += ch;
|
|
201
|
+
} else if (ch === "(") {
|
|
202
|
+
depth++;
|
|
203
|
+
if (depth === 1) flat += ch;
|
|
204
|
+
} else if (ch === ")") {
|
|
205
|
+
depth--;
|
|
206
|
+
if (depth >= 1) flat += ch;
|
|
207
|
+
} else if (depth === 1) {
|
|
208
|
+
flat += ch;
|
|
209
|
+
}
|
|
210
|
+
i++;
|
|
155
211
|
}
|
|
156
|
-
const
|
|
157
|
-
if (!
|
|
158
|
-
const
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
212
|
+
const name = /\bname\s*:\s*"([^"]+)"/.exec(flat)?.[1];
|
|
213
|
+
if (!name) continue;
|
|
214
|
+
const rawPath = /\bpath\s*:\s*"([^"]*)"/.exec(flat)?.[1];
|
|
215
|
+
const targetPath = rawPath == null || rawPath === "" ? `Sources/${name}` : rawPath.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
216
|
+
const call = code.slice(start, i);
|
|
217
|
+
const languageMode = Number(
|
|
218
|
+
/\.swiftLanguageMode\(\s*\.v(\d+)\s*\)/.exec(call)?.[1] ?? "5"
|
|
219
|
+
);
|
|
220
|
+
const mainActorIsolation = /\.defaultIsolation\(\s*MainActor\.self\s*\)/.test(call);
|
|
221
|
+
const resources = /\bresources\s*:/.test(flat);
|
|
222
|
+
targets.push({
|
|
223
|
+
name,
|
|
224
|
+
path: targetPath,
|
|
225
|
+
executable,
|
|
226
|
+
languageMode,
|
|
227
|
+
mainActorIsolation,
|
|
228
|
+
resources
|
|
229
|
+
});
|
|
171
230
|
}
|
|
172
|
-
return
|
|
231
|
+
return targets;
|
|
173
232
|
}
|
|
174
|
-
function
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
233
|
+
function swiftPackagePartition(manifest) {
|
|
234
|
+
const targets = swiftManifestTargets(manifest);
|
|
235
|
+
return targets.length === 1 && targets[0].executable && targets[0].path === "." ? [] : targets;
|
|
178
236
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
function enumerateBundleColors(paths, readText) {
|
|
198
|
-
const table = {};
|
|
199
|
-
for (const contentsPath of paths.filter((path6) => baseOf(path6) === "Contents.json")) {
|
|
200
|
-
const name = catalogEntryName(contentsPath, ".colorset", readText);
|
|
201
|
-
if (name === null || name in table) continue;
|
|
202
|
-
let colors;
|
|
203
|
-
try {
|
|
204
|
-
const text = readText(contentsPath);
|
|
205
|
-
if (text === null) continue;
|
|
206
|
-
colors = Reflect.get(JSON.parse(text), "colors");
|
|
207
|
-
} catch {
|
|
208
|
-
continue;
|
|
237
|
+
|
|
238
|
+
// src/swift-compile.ts
|
|
239
|
+
var run2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
|
|
240
|
+
var WASM_TRIPLE = "wasm32-unknown-wasip1";
|
|
241
|
+
var cores = import_node_os.default.availableParallelism();
|
|
242
|
+
var BUILD_ENV = { ...process.env, BINARYEN_CORES: String(Math.min(4, cores)) };
|
|
243
|
+
var BUILD_JOBS = String(Math.max(1, Math.floor(cores / 2)));
|
|
244
|
+
function swiftModuleInputFiles(root) {
|
|
245
|
+
const files = [
|
|
246
|
+
"Package.swift",
|
|
247
|
+
"scripts/contrast-app-Package.swift",
|
|
248
|
+
"toolchain.json"
|
|
249
|
+
];
|
|
250
|
+
const walk = (dir) => {
|
|
251
|
+
for (const entry of (0, import_node_fs2.readdirSync)(import_node_path2.default.join(root, dir), { withFileTypes: true })) {
|
|
252
|
+
const relative = `${dir}/${entry.name}`;
|
|
253
|
+
if (entry.isDirectory()) walk(relative);
|
|
254
|
+
else if (/\.(swift|c|h)$/.test(entry.name)) files.push(relative);
|
|
209
255
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (value === null) continue;
|
|
226
|
-
if (isDark) dark = value;
|
|
227
|
-
else light = value;
|
|
256
|
+
};
|
|
257
|
+
walk("Sources");
|
|
258
|
+
return files.sort();
|
|
259
|
+
}
|
|
260
|
+
async function ensureMacroPlugins(moduleRoot, toolchainBin) {
|
|
261
|
+
const dir = import_node_path2.default.join(moduleRoot, ".build/host/RnxPreviewMacros");
|
|
262
|
+
const ext = process.platform === "darwin" ? "dylib" : "so";
|
|
263
|
+
const plugins = [
|
|
264
|
+
{
|
|
265
|
+
library: import_node_path2.default.join(dir, `libRnxPreviewMacros.${ext}`),
|
|
266
|
+
source: import_node_path2.default.join(moduleRoot, "Sources/RnxPreviewMacros/PreviewMacro.swift")
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
library: import_node_path2.default.join(dir, `libFoundationMacros.${ext}`),
|
|
270
|
+
source: import_node_path2.default.join(moduleRoot, "Sources/FoundationMacros/PredicateMacro.swift")
|
|
228
271
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
272
|
+
];
|
|
273
|
+
const stale = plugins.some(
|
|
274
|
+
({ library, source }) => !(0, import_node_fs2.existsSync)(library) || (0, import_node_fs2.statSync)(source).mtimeMs > (0, import_node_fs2.statSync)(library).mtimeMs
|
|
275
|
+
);
|
|
276
|
+
if (stale) {
|
|
277
|
+
await run2("sh", [
|
|
278
|
+
import_node_path2.default.join(moduleRoot, "scripts/build-preview-plugin.sh"),
|
|
279
|
+
toolchainBin,
|
|
280
|
+
plugins[0].library
|
|
281
|
+
]);
|
|
232
282
|
}
|
|
233
|
-
return
|
|
283
|
+
return plugins.map(({ library }) => library);
|
|
234
284
|
}
|
|
235
|
-
var
|
|
236
|
-
function
|
|
237
|
-
const
|
|
238
|
-
const
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
285
|
+
var linkedModuleDigests = /* @__PURE__ */ new Map();
|
|
286
|
+
function linkedModuleDigest(root) {
|
|
287
|
+
const files = swiftModuleInputFiles(root);
|
|
288
|
+
const stampHash = (0, import_node_crypto2.createHash)("sha256");
|
|
289
|
+
for (const file of files) {
|
|
290
|
+
const stat = (0, import_node_fs2.statSync)(import_node_path2.default.join(root, file), { bigint: true });
|
|
291
|
+
stampHash.update(file);
|
|
292
|
+
stampHash.update(
|
|
293
|
+
`${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}
|
|
294
|
+
`
|
|
295
|
+
);
|
|
245
296
|
}
|
|
246
|
-
const
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
})();
|
|
255
|
-
for (const t of roots.filter(within))
|
|
256
|
-
out.push(
|
|
257
|
-
(1 - t) ** 3 * a + 3 * (1 - t) ** 2 * t * b + 3 * (1 - t) * t ** 2 * c + t ** 3 * d
|
|
297
|
+
const stamp = stampHash.digest("hex");
|
|
298
|
+
const cached = linkedModuleDigests.get(root);
|
|
299
|
+
if (cached?.stamp === stamp) return cached.digest;
|
|
300
|
+
const hash = (0, import_node_crypto2.createHash)("sha256");
|
|
301
|
+
for (const file of files) {
|
|
302
|
+
hash.update((0, import_node_crypto2.createHash)("sha256").update(file).digest());
|
|
303
|
+
hash.update(
|
|
304
|
+
(0, import_node_crypto2.createHash)("sha256").update((0, import_node_fs2.readFileSync)(import_node_path2.default.join(root, file))).digest()
|
|
258
305
|
);
|
|
259
|
-
|
|
306
|
+
}
|
|
307
|
+
const digest = hash.digest();
|
|
308
|
+
linkedModuleDigests.set(root, { stamp, digest });
|
|
309
|
+
return digest;
|
|
260
310
|
}
|
|
261
|
-
function
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
else if (command === "V") ys.push(Number(args[0]));
|
|
272
|
-
else if (command === "Q" || command === "C") {
|
|
273
|
-
const n = args.map(Number);
|
|
274
|
-
xs.push(...axisExtremes([x, ...n.filter((_, i) => i % 2 === 0)]));
|
|
275
|
-
ys.push(...axisExtremes([y, ...n.filter((_, i) => i % 2 === 1)]));
|
|
276
|
-
}
|
|
277
|
-
});
|
|
311
|
+
function compileTargets(input) {
|
|
312
|
+
const manifest = input.files["Package.swift"];
|
|
313
|
+
return manifest === void 0 ? [] : swiftPackagePartition(manifest);
|
|
314
|
+
}
|
|
315
|
+
function withNativeSourceGlue(input, glue) {
|
|
316
|
+
const targets = compileTargets(input);
|
|
317
|
+
if (targets.length > 1) {
|
|
318
|
+
throw new Error("swift native modules need one SwiftPM target");
|
|
319
|
+
}
|
|
320
|
+
const targetPath = targets[0]?.path === "." ? "" : targets[0]?.path ?? "";
|
|
278
321
|
return {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
322
|
+
...input,
|
|
323
|
+
files: {
|
|
324
|
+
...input.files,
|
|
325
|
+
[import_node_path2.default.posix.join(targetPath, "OneNativeSource.generated.swift")]: glue
|
|
326
|
+
},
|
|
327
|
+
oneModule: true
|
|
283
328
|
};
|
|
284
329
|
}
|
|
285
|
-
function
|
|
286
|
-
const
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
} catch {
|
|
299
|
-
continue;
|
|
330
|
+
function swiftSiblingDependencies(files, targets) {
|
|
331
|
+
const names = new Set(targets.map((target) => target.name));
|
|
332
|
+
const siblings = /* @__PURE__ */ new Map();
|
|
333
|
+
for (const target of targets) {
|
|
334
|
+
const prefix = `${target.path}/`;
|
|
335
|
+
const deps = /* @__PURE__ */ new Set();
|
|
336
|
+
for (const [file, contents] of Object.entries(files)) {
|
|
337
|
+
if (file === "Package.swift" || !file.startsWith(prefix)) continue;
|
|
338
|
+
for (const match of contents.matchAll(
|
|
339
|
+
/^\s*(?:@\w+(?:\([^)]*\))?\s+)*import\s+(?:(?:typealias|struct|class|enum|protocol|let|var|func)\s+)?([A-Za-z_][A-Za-z0-9_]*)/gm
|
|
340
|
+
)) {
|
|
341
|
+
if (names.has(match[1]) && match[1] !== target.name) deps.add(match[1]);
|
|
342
|
+
}
|
|
300
343
|
}
|
|
301
|
-
|
|
302
|
-
if (typeof file !== "string") continue;
|
|
303
|
-
if (file.includes("/") || file.includes("\\")) continue;
|
|
304
|
-
const svg = readText(`${contentsPath.split("/").slice(0, -1).join("/")}/${file}`);
|
|
305
|
-
if (svg === null) continue;
|
|
306
|
-
const group = /<g id="Regular-M"[^>]*>([\s\S]*?)<\/g>/.exec(svg)?.[1];
|
|
307
|
-
const baseline = guide(svg, "Baseline-M", "y1");
|
|
308
|
-
const capline = guide(svg, "Capline-M", "y1");
|
|
309
|
-
const left = guide(svg, "left-margin-Regular-M", "x1") ?? guide(svg, "left-margin", "x1");
|
|
310
|
-
const right = guide(svg, "right-margin-Regular-M", "x1") ?? guide(svg, "right-margin", "x1");
|
|
311
|
-
if (group === void 0 || baseline === null || capline === null || left === null || right === null)
|
|
312
|
-
continue;
|
|
313
|
-
const d = [...group.matchAll(/ d="([^"]+)"/g)].map((match) => match[1] ?? "");
|
|
314
|
-
if (d.length === 0 || baseline <= capline) continue;
|
|
315
|
-
const scale = 24 * SYMBOL_CAP_HEIGHT_EM / (baseline - capline);
|
|
316
|
-
const box = pathBounds(d);
|
|
317
|
-
const translateX = 12 - (box.minX + box.maxX) * scale / 2;
|
|
318
|
-
const translateY = 12 - (box.minY + box.maxY) * scale / 2;
|
|
319
|
-
const advance = Math.round((right - left) * scale * 1e3) / 1e3;
|
|
320
|
-
const tall = (box.maxY - box.minY) * scale + 0.175 * 24;
|
|
321
|
-
table[name] = {
|
|
322
|
-
viewBox: "0 0 24 24",
|
|
323
|
-
advance,
|
|
324
|
-
box: [12 - advance / 2, 12 - tall / 2, advance, tall],
|
|
325
|
-
layers: d.map((path6) => ({
|
|
326
|
-
d: (0, import_svgpath.default)(path6).abs().scale(scale).translate(translateX, translateY).round(3).toString()
|
|
327
|
-
}))
|
|
328
|
-
};
|
|
344
|
+
siblings.set(target.name, [...deps].sort());
|
|
329
345
|
}
|
|
330
|
-
return
|
|
346
|
+
return siblings;
|
|
331
347
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
found.push({ base, file });
|
|
348
|
+
var ONE_PRODUCT = '.product(name: "One", package: "sootsim-swift")';
|
|
349
|
+
var OBJC_IMPLICIT_FLAGS = ', "-Xfrontend", "-import-module", "-Xfrontend", "PeachObjC"';
|
|
350
|
+
var ONE_IMPLICIT_FLAGS = ', "-Xfrontend", "-import-module", "-Xfrontend", "One"';
|
|
351
|
+
var MULTI_MANIFEST_VERSION = 6;
|
|
352
|
+
function swiftArtifactHash(input, release, moduleRoot) {
|
|
353
|
+
const hash = (0, import_node_crypto2.createHash)("sha256");
|
|
354
|
+
hash.update(`swift-compile/v6
|
|
355
|
+
${release}
|
|
356
|
+
`);
|
|
357
|
+
if (input.oneModule) hash.update("one-module\n");
|
|
358
|
+
hash.update(linkedModuleDigest(moduleRoot));
|
|
359
|
+
for (const file of Object.keys(input.files).sort()) {
|
|
360
|
+
hash.update((0, import_node_crypto2.createHash)("sha256").update(file).digest());
|
|
361
|
+
hash.update((0, import_node_crypto2.createHash)("sha256").update(input.files[file]).digest());
|
|
347
362
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
var import_node_path2 = require("node:path");
|
|
354
|
-
|
|
355
|
-
// src/home-paths.ts
|
|
356
|
-
var import_node_os = require("node:os");
|
|
357
|
-
var import_node_path = __toESM(require("node:path"), 1);
|
|
358
|
-
var PEACH_HOME_ENV = "PEACH_HOME";
|
|
359
|
-
function rnxHomeDir() {
|
|
360
|
-
const override = process.env[PEACH_HOME_ENV];
|
|
361
|
-
if (override && override.length > 0) return import_node_path.default.resolve(override);
|
|
362
|
-
return import_node_path.default.join((0, import_node_os.homedir)(), ".peach");
|
|
363
|
-
}
|
|
364
|
-
function electronDir() {
|
|
365
|
-
return import_node_path.default.join(rnxHomeDir(), "electron");
|
|
366
|
-
}
|
|
367
|
-
function electronUserDataDir() {
|
|
368
|
-
return import_node_path.default.join(electronDir(), "userData");
|
|
369
|
-
}
|
|
370
|
-
var DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
|
|
371
|
-
|
|
372
|
-
// src/auth/shared-session.ts
|
|
373
|
-
function sharedDesktopAuthAccounts(user) {
|
|
374
|
-
return [
|
|
375
|
-
...user?.personalAccountId ? [{ id: user.personalAccountId, name: "Personal" }] : [],
|
|
376
|
-
...(user?.teams ?? []).map((team) => ({ id: team.id, name: team.name }))
|
|
377
|
-
];
|
|
378
|
-
}
|
|
379
|
-
var SESSION_VERSION = 1;
|
|
380
|
-
var SESSION_FILE_ENV = "SOOTSIM_SHARED_AUTH_FILE";
|
|
381
|
-
var DEFAULT_ORIGIN = "https://contrast.dev";
|
|
382
|
-
function getBaseDir() {
|
|
383
|
-
const explicit = process.env[SESSION_FILE_ENV];
|
|
384
|
-
if (explicit?.trim()) {
|
|
385
|
-
return (0, import_node_path2.dirname)((0, import_node_path2.resolve)(explicit));
|
|
363
|
+
for (const base of Object.keys(input.resources ?? {}).sort()) {
|
|
364
|
+
hash.update((0, import_node_crypto2.createHash)("sha256").update(base).digest());
|
|
365
|
+
hash.update(
|
|
366
|
+
(0, import_node_crypto2.createHash)("sha256").update(input.resources?.[base] ?? "").digest()
|
|
367
|
+
);
|
|
386
368
|
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
369
|
+
for (const name of Object.keys(input.images ?? {}).sort()) {
|
|
370
|
+
const image = input.images?.[name];
|
|
371
|
+
if (!image) continue;
|
|
372
|
+
hash.update((0, import_node_crypto2.createHash)("sha256").update(name).digest());
|
|
373
|
+
hash.update((0, import_node_crypto2.createHash)("sha256").update(image.file).digest());
|
|
374
|
+
hash.update((0, import_node_crypto2.createHash)("sha256").update(image.data).digest());
|
|
375
|
+
}
|
|
376
|
+
const targets = compileTargets(input);
|
|
377
|
+
if (targets.length > 0) {
|
|
378
|
+
hash.update(`swift-multi/v${MULTI_MANIFEST_VERSION}
|
|
379
|
+
`);
|
|
380
|
+
hash.update(
|
|
381
|
+
JSON.stringify({
|
|
382
|
+
targets,
|
|
383
|
+
siblings: [...swiftSiblingDependencies(input.files, targets)].sort(
|
|
384
|
+
(a, b) => String(a) < String(b) ? -1 : String(a) > String(b) ? 1 : 0
|
|
385
|
+
)
|
|
386
|
+
})
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
return hash.digest("hex");
|
|
393
390
|
}
|
|
394
|
-
function
|
|
395
|
-
|
|
396
|
-
const
|
|
397
|
-
if (
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
}
|
|
391
|
+
function emitSwiftPackageManifest(args) {
|
|
392
|
+
const { targets, siblings, moduleRoot, oneModule } = args;
|
|
393
|
+
const executable = targets.find((target) => target.executable);
|
|
394
|
+
if (!executable) throw new Error("swift-compile: no executable target to emit");
|
|
395
|
+
const stanza = (target) => {
|
|
396
|
+
const isolation = target.mainActorIsolation ? " .defaultIsolation(MainActor.self)," : "";
|
|
397
|
+
const swiftSettings = `swiftSettings: [.swiftLanguageMode(.v${target.languageMode}),${isolation} .unsafeFlags(["-Osize"${OBJC_IMPLICIT_FLAGS}${oneModule ? ONE_IMPLICIT_FLAGS : ""}])]`;
|
|
398
|
+
const deps = [
|
|
399
|
+
'.product(name: "SwiftUI", package: "sootsim-swift")',
|
|
400
|
+
...oneModule ? [ONE_PRODUCT] : [],
|
|
401
|
+
...(siblings.get(target.name) ?? []).map((sibling) => `"${sibling}"`)
|
|
402
|
+
].join(", ");
|
|
403
|
+
const kind = target.executable ? ".executableTarget" : ".target";
|
|
404
|
+
const link = target.executable ? `,
|
|
405
|
+
linkerSettings: [
|
|
406
|
+
.unsafeFlags([
|
|
407
|
+
"-Xclang-linker", "-mexec-model=reactor",
|
|
408
|
+
"-Xlinker", "--export-if-defined=__main_argc_argv",
|
|
409
|
+
]),
|
|
410
|
+
.unsafeFlags(["-Xlinker", "--strip-all"], .when(configuration: .release)),
|
|
411
|
+
]` : "";
|
|
412
|
+
return [
|
|
413
|
+
` ${kind}(`,
|
|
414
|
+
` name: "${target.name}",`,
|
|
415
|
+
` dependencies: [${deps}],`,
|
|
416
|
+
` path: "${target.path}",`,
|
|
417
|
+
` ${swiftSettings}${link}`,
|
|
418
|
+
` ),`
|
|
419
|
+
].join("\n");
|
|
417
420
|
};
|
|
421
|
+
return [
|
|
422
|
+
"// swift-tools-version: 6.2",
|
|
423
|
+
"import PackageDescription",
|
|
424
|
+
"",
|
|
425
|
+
"// generated by swift-compile from the project package partition.",
|
|
426
|
+
"let package = Package(",
|
|
427
|
+
' name: "app",',
|
|
428
|
+
` products: [.executable(name: "${executable.name}", targets: ["${executable.name}"])],`,
|
|
429
|
+
` dependencies: [.package(path: "${moduleRoot}")],`,
|
|
430
|
+
" targets: [",
|
|
431
|
+
...targets.map(stanza),
|
|
432
|
+
" ]",
|
|
433
|
+
")",
|
|
434
|
+
""
|
|
435
|
+
].join("\n");
|
|
418
436
|
}
|
|
419
|
-
function
|
|
420
|
-
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const accountId = typeof value.accountId === "string" && value.accountId.trim() ? value.accountId.trim() : void 0;
|
|
429
|
-
return {
|
|
430
|
-
version: SESSION_VERSION,
|
|
431
|
-
token: value.token.trim(),
|
|
432
|
-
user: normalizeUser(value.user),
|
|
433
|
-
origin,
|
|
434
|
-
source,
|
|
435
|
-
updatedAt,
|
|
436
|
-
validatedAt,
|
|
437
|
-
accountId
|
|
437
|
+
function syncSwiftTree(base, files) {
|
|
438
|
+
(0, import_node_fs2.mkdirSync)(base, { recursive: true });
|
|
439
|
+
const walk = (dir) => {
|
|
440
|
+
for (const entry of (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true })) {
|
|
441
|
+
const full = import_node_path2.default.join(dir, entry.name);
|
|
442
|
+
if (dir === base && entry.name === ".build") continue;
|
|
443
|
+
if (entry.isDirectory()) walk(full);
|
|
444
|
+
else if (!files.has(full)) (0, import_node_fs2.rmSync)(full, { force: true });
|
|
445
|
+
}
|
|
438
446
|
};
|
|
447
|
+
walk(base);
|
|
448
|
+
for (const [full, contents] of files) {
|
|
449
|
+
if ((0, import_node_fs2.existsSync)(full) && (0, import_node_fs2.readFileSync)(full, "utf8") === contents) continue;
|
|
450
|
+
(0, import_node_fs2.mkdirSync)(import_node_path2.default.dirname(full), { recursive: true });
|
|
451
|
+
(0, import_node_fs2.writeFileSync)(full, contents, "utf8");
|
|
452
|
+
}
|
|
439
453
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
454
|
+
var DIRECTIVE = /^[ \t]*#(?:if|elseif)\b/;
|
|
455
|
+
var OS_IOS = /\bos\(\s*iOS\s*\)/g;
|
|
456
|
+
var OBJC_ATTRIBUTE = /^@(?:objcMembers\b|objc\b(?:(\s*)\(([^()]*)\))?|IBAction\b)/;
|
|
457
|
+
var SELECTOR = /^#selector\b/;
|
|
458
|
+
var DELEGATE_CLASS = /^class\s+[A-Za-z_]\w*\s*(?:<[^>{]*>)?\s*:[^{]*\b(?:UIApplicationDelegate|UISceneDelegate|UIWindowSceneDelegate)\b[^{]*\{/;
|
|
459
|
+
function swiftSourceAsIOS(source) {
|
|
460
|
+
const { lineStarts, tokens } = swiftCodeScan(source);
|
|
461
|
+
let offset = 0;
|
|
462
|
+
const conditioned = source.split("\n").map((line) => {
|
|
463
|
+
const start = offset;
|
|
464
|
+
offset += line.length + 1;
|
|
465
|
+
if (!lineStarts.has(start) || !DIRECTIVE.test(line)) return line;
|
|
466
|
+
return line.replace(OS_IOS, (match) => "true".padEnd(match.length));
|
|
467
|
+
}).join("\n");
|
|
468
|
+
let out = "";
|
|
469
|
+
let copied = 0;
|
|
470
|
+
for (const at of tokens) {
|
|
471
|
+
const rest = conditioned.slice(at, at + 400);
|
|
472
|
+
if (rest.startsWith("class")) {
|
|
473
|
+
const modifiers = conditioned.slice(conditioned.lastIndexOf("\n", at - 1) + 1, at);
|
|
474
|
+
if (DELEGATE_CLASS.test(rest) && !/\b(?:final|open)\b/.test(modifiers)) {
|
|
475
|
+
out += `${conditioned.slice(copied, at)}final `;
|
|
476
|
+
copied = at;
|
|
477
|
+
}
|
|
478
|
+
continue;
|
|
449
479
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
(
|
|
453
|
-
|
|
480
|
+
const selector = SELECTOR.exec(rest);
|
|
481
|
+
const match = selector ?? OBJC_ATTRIBUTE.exec(rest);
|
|
482
|
+
if (!match) continue;
|
|
483
|
+
let replacement = "@ObjC";
|
|
484
|
+
if (selector) replacement = "#Selector";
|
|
485
|
+
else if (match[0] === "@objcMembers") replacement = "@ObjCMembers";
|
|
486
|
+
else if (match[0] === "@IBAction") replacement = "@ObjC".padEnd(match[0].length);
|
|
487
|
+
else if (match[2] !== void 0)
|
|
488
|
+
replacement = `@ObjC${match[1]}("${match[2].trim()}")`;
|
|
489
|
+
out += conditioned.slice(copied, at) + replacement;
|
|
490
|
+
copied = at + match[0].length;
|
|
454
491
|
}
|
|
492
|
+
return out + conditioned.slice(copied);
|
|
455
493
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
return Boolean(
|
|
465
|
-
token && token.length >= 20 && GITHUB_TOKEN_PREFIXES.some((prefix) => token.startsWith(prefix))
|
|
466
|
-
);
|
|
467
|
-
}
|
|
468
|
-
function resolveGitHubActionsAuth() {
|
|
469
|
-
const contrastRunnerToken = process.env.CONTRAST_INSTALLATION_TOKEN?.trim();
|
|
470
|
-
const githubActionsToken = process.env.GITHUB_TOKEN?.trim();
|
|
471
|
-
const token = contrastRunnerToken || githubActionsToken;
|
|
472
|
-
if (!looksLikeGitHubToken(token)) return null;
|
|
473
|
-
const repoSlug = (process.env.CONTRAST_REPO || process.env.GITHUB_REPOSITORY || "").trim();
|
|
474
|
-
if (!repoSlug) return null;
|
|
475
|
-
const [owner, repo] = repoSlug.includes("/") ? repoSlug.split("/", 2) : [null, null];
|
|
476
|
-
const repositoryId = (process.env.CONTRAST_REPO_ID || process.env.GITHUB_REPOSITORY_ID || "").trim();
|
|
477
|
-
const installationId = (process.env.CONTRAST_INSTALLATION_ID || process.env.GITHUB_APP_INSTALLATION_ID || "").trim();
|
|
478
|
-
return {
|
|
479
|
-
kind: "github",
|
|
480
|
-
token,
|
|
481
|
-
repoId: repoSlug,
|
|
482
|
-
repositoryId: repositoryId || null,
|
|
483
|
-
owner: owner || null,
|
|
484
|
-
repo: repo || null,
|
|
485
|
-
installationId: installationId || null,
|
|
486
|
-
source: contrastRunnerToken ? "contrast-runner" : "github-actions"
|
|
494
|
+
function swiftCodeScan(source) {
|
|
495
|
+
const starts = /* @__PURE__ */ new Set();
|
|
496
|
+
const tokens = [];
|
|
497
|
+
const stack = [{ kind: "code", parens: 0 }];
|
|
498
|
+
const hashesAt = (at) => {
|
|
499
|
+
let end = at;
|
|
500
|
+
while (source[end] === "#") end++;
|
|
501
|
+
return end - at;
|
|
487
502
|
};
|
|
503
|
+
const closes = (at, hashes) => source.startsWith("#".repeat(hashes), at);
|
|
504
|
+
let i = 0;
|
|
505
|
+
while (i < source.length) {
|
|
506
|
+
const top = stack[stack.length - 1];
|
|
507
|
+
if ((i === 0 || source[i - 1] === "\n") && top.kind === "code" && stack.length === 1)
|
|
508
|
+
starts.add(i);
|
|
509
|
+
const char = source[i];
|
|
510
|
+
if (top.kind === "block") {
|
|
511
|
+
if (source.startsWith("/*", i)) {
|
|
512
|
+
top.depth++;
|
|
513
|
+
i += 2;
|
|
514
|
+
} else if (source.startsWith("*/", i)) {
|
|
515
|
+
if (--top.depth === 0) stack.pop();
|
|
516
|
+
i += 2;
|
|
517
|
+
} else i++;
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
if (top.kind === "string") {
|
|
521
|
+
if (char === "\\" && closes(i + 1, top.hashes)) {
|
|
522
|
+
const after = i + 1 + top.hashes;
|
|
523
|
+
if (source[after] === "(") {
|
|
524
|
+
stack.push({ kind: "code", parens: 0 });
|
|
525
|
+
i = after + 1;
|
|
526
|
+
} else i = after + 1;
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
const quote = top.multiline ? '"""' : '"';
|
|
530
|
+
if (source.startsWith(quote, i) && closes(i + quote.length, top.hashes)) {
|
|
531
|
+
stack.pop();
|
|
532
|
+
i += quote.length + top.hashes;
|
|
533
|
+
} else i++;
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
if (top.kind === "regex") {
|
|
537
|
+
if (char === "/" && closes(i + 1, top.hashes)) {
|
|
538
|
+
stack.pop();
|
|
539
|
+
i += 1 + top.hashes;
|
|
540
|
+
} else i++;
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
if (source.startsWith("//", i)) {
|
|
544
|
+
const end = source.indexOf("\n", i);
|
|
545
|
+
i = end === -1 ? source.length : end;
|
|
546
|
+
} else if (source.startsWith("/*", i)) {
|
|
547
|
+
stack.push({ kind: "block", depth: 1 });
|
|
548
|
+
i += 2;
|
|
549
|
+
} else if (char === '"' || char === "#") {
|
|
550
|
+
const hashes = hashesAt(i);
|
|
551
|
+
const at = i + hashes;
|
|
552
|
+
if (source.startsWith('"""', at)) {
|
|
553
|
+
stack.push({ kind: "string", hashes, multiline: true });
|
|
554
|
+
i = at + 3;
|
|
555
|
+
} else if (source[at] === '"') {
|
|
556
|
+
stack.push({ kind: "string", hashes, multiline: false });
|
|
557
|
+
i = at + 1;
|
|
558
|
+
} else if (hashes > 0 && source[at] === "/") {
|
|
559
|
+
stack.push({ kind: "regex", hashes });
|
|
560
|
+
i = at + 1;
|
|
561
|
+
} else {
|
|
562
|
+
if (hashes > 0) tokens.push(at - 1);
|
|
563
|
+
i = Math.max(at, i + 1);
|
|
564
|
+
}
|
|
565
|
+
} else if (char === "(") {
|
|
566
|
+
top.parens++;
|
|
567
|
+
i++;
|
|
568
|
+
} else if (char === ")") {
|
|
569
|
+
if (top.parens === 0 && stack.length > 1) stack.pop();
|
|
570
|
+
else top.parens--;
|
|
571
|
+
i++;
|
|
572
|
+
} else if (source.startsWith("class", i) && !/[\w$]/.test(source[i - 1] ?? "") && !/[\w$]/.test(source[i + 5] ?? "")) {
|
|
573
|
+
tokens.push(i);
|
|
574
|
+
i += 5;
|
|
575
|
+
} else {
|
|
576
|
+
if (char === "@") tokens.push(i);
|
|
577
|
+
i++;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return { lineStarts: starts, tokens };
|
|
488
581
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
function resolveCliAuth() {
|
|
498
|
-
const envKey = readApiKeyFromEnv();
|
|
499
|
-
if (envKey) {
|
|
500
|
-
return {
|
|
501
|
-
kind: "api-key",
|
|
502
|
-
secret: envKey.secret,
|
|
503
|
-
source: "env",
|
|
504
|
-
envName: envKey.envName
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
const githubAuth = resolveGitHubActionsAuth();
|
|
508
|
-
if (githubAuth) return githubAuth;
|
|
509
|
-
const session = readSharedDesktopAuthSession();
|
|
510
|
-
if (session?.token) {
|
|
511
|
-
const accounts = sharedDesktopAuthAccounts(session.user);
|
|
512
|
-
return {
|
|
513
|
-
kind: "session",
|
|
514
|
-
token: session.token,
|
|
515
|
-
origin: session.origin,
|
|
516
|
-
accountId: session.accountId ?? (accounts.length === 1 ? accounts[0]?.id ?? null : null)
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
return null;
|
|
520
|
-
}
|
|
521
|
-
function authHeaderValue(auth) {
|
|
522
|
-
return auth.kind === "api-key" ? `Bearer ${auth.secret}` : `Bearer ${auth.token}`;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
// src/backend-origin.ts
|
|
526
|
-
var DEFAULT_CONTRAST_BACKEND_ORIGIN = "https://contrast.dev";
|
|
527
|
-
function normalizeHostname(hostname) {
|
|
528
|
-
return hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
529
|
-
}
|
|
530
|
-
function isLoopbackHost(hostname) {
|
|
531
|
-
const normalized = normalizeHostname(hostname);
|
|
532
|
-
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
533
|
-
}
|
|
534
|
-
function isContrastBackendHost(hostname) {
|
|
535
|
-
const normalized = normalizeHostname(hostname);
|
|
536
|
-
return isLoopbackHost(normalized) || normalized === "contrast.dev" || normalized.endsWith(".contrast.dev");
|
|
537
|
-
}
|
|
538
|
-
function resolveContrastBackendOrigin(currentOrigin) {
|
|
539
|
-
const origin = currentOrigin?.trim();
|
|
540
|
-
if (!origin) return DEFAULT_CONTRAST_BACKEND_ORIGIN;
|
|
541
|
-
try {
|
|
542
|
-
const parsed = new URL(origin);
|
|
543
|
-
if (isLoopbackHost(parsed.hostname) || isContrastBackendHost(parsed.hostname)) {
|
|
544
|
-
return parsed.origin;
|
|
582
|
+
var compiledSource = (file, contents) => file.endsWith(".swift") ? swiftSourceAsIOS(contents) : contents;
|
|
583
|
+
function writeSwiftProject(layout, input, moduleRoot) {
|
|
584
|
+
const targets = compileTargets(input);
|
|
585
|
+
const files = /* @__PURE__ */ new Map();
|
|
586
|
+
if (targets.length === 0) {
|
|
587
|
+
for (const [file, contents] of Object.entries(input.files)) {
|
|
588
|
+
if (file === "Package.swift") continue;
|
|
589
|
+
files.set(import_node_path2.default.join(layout.sources, file), compiledSource(file, contents));
|
|
545
590
|
}
|
|
546
|
-
|
|
591
|
+
let manifest = (0, import_node_fs2.readFileSync)(
|
|
592
|
+
import_node_path2.default.join(moduleRoot, "scripts/contrast-app-Package.swift"),
|
|
593
|
+
"utf8"
|
|
594
|
+
).replaceAll("__SOOTSIM_SWIFT_PACKAGE__", moduleRoot);
|
|
595
|
+
if (input.oneModule) {
|
|
596
|
+
const product = '.product(name: "CoreLocation", package: "sootsim-swift"),';
|
|
597
|
+
const flags = `"-Osize"${OBJC_IMPLICIT_FLAGS}`;
|
|
598
|
+
if (!manifest.includes(product) || !manifest.includes(flags)) {
|
|
599
|
+
throw new Error(
|
|
600
|
+
"scripts/contrast-app-Package.swift lost the lines the One module links at"
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
manifest = manifest.replace(product, `${product}
|
|
604
|
+
${ONE_PRODUCT},`).replace(flags, `${flags}${ONE_IMPLICIT_FLAGS}`);
|
|
605
|
+
}
|
|
606
|
+
files.set(import_node_path2.default.join(layout.root, "Package.swift"), manifest);
|
|
607
|
+
} else {
|
|
608
|
+
for (const [file, contents] of Object.entries(input.files)) {
|
|
609
|
+
if (file === "Package.swift") continue;
|
|
610
|
+
files.set(import_node_path2.default.join(layout.root, file), compiledSource(file, contents));
|
|
611
|
+
}
|
|
612
|
+
for (const target of targets) {
|
|
613
|
+
if (!target.resources) continue;
|
|
614
|
+
files.set(
|
|
615
|
+
import_node_path2.default.join(layout.root, target.path, "ResourceBundleAccessor.generated.swift"),
|
|
616
|
+
[
|
|
617
|
+
"import Foundation",
|
|
618
|
+
"",
|
|
619
|
+
"extension Foundation.Bundle {",
|
|
620
|
+
" static let module: Bundle = Bundle.main",
|
|
621
|
+
"}",
|
|
622
|
+
""
|
|
623
|
+
].join("\n")
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
files.set(
|
|
627
|
+
import_node_path2.default.join(layout.root, "Package.swift"),
|
|
628
|
+
emitSwiftPackageManifest({
|
|
629
|
+
targets,
|
|
630
|
+
siblings: swiftSiblingDependencies(input.files, targets),
|
|
631
|
+
moduleRoot,
|
|
632
|
+
oneModule: input.oneModule
|
|
633
|
+
})
|
|
634
|
+
);
|
|
547
635
|
}
|
|
548
|
-
|
|
636
|
+
syncSwiftTree(layout.root, files);
|
|
549
637
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
var import_node_fs2 = require("node:fs");
|
|
563
|
-
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
564
|
-
var import_node_util = require("node:util");
|
|
565
|
-
var import_node_zlib = require("node:zlib");
|
|
566
|
-
var run = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
567
|
-
var deflate = (0, import_node_util.promisify)(import_node_zlib.gzip);
|
|
568
|
-
var ARCHIVE = "wasi/lib_FoundationICU.a";
|
|
569
|
-
var MEMBER = "icu_packaged_data.cpp.obj";
|
|
570
|
-
var raw = /* @__PURE__ */ new Map();
|
|
571
|
-
var assets = /* @__PURE__ */ new Map();
|
|
572
|
-
function memo(cache, key, load2) {
|
|
573
|
-
let pending = cache.get(key);
|
|
574
|
-
if (!pending) {
|
|
575
|
-
pending = load2();
|
|
576
|
-
pending.catch(() => cache.delete(key));
|
|
577
|
-
cache.set(key, pending);
|
|
638
|
+
function streamText(value) {
|
|
639
|
+
if (typeof value === "string") return value.trim();
|
|
640
|
+
if (Buffer.isBuffer(value)) return value.toString("utf8").trim();
|
|
641
|
+
return "";
|
|
642
|
+
}
|
|
643
|
+
function outputOf(error) {
|
|
644
|
+
if (error && typeof error === "object") {
|
|
645
|
+
const streams = [
|
|
646
|
+
streamText(Reflect.get(error, "stdout")),
|
|
647
|
+
streamText(Reflect.get(error, "stderr"))
|
|
648
|
+
].filter(Boolean);
|
|
649
|
+
if (streams.length > 0) return streams.join("\n");
|
|
578
650
|
}
|
|
579
|
-
return
|
|
651
|
+
return error instanceof Error ? error.message : String(error);
|
|
580
652
|
}
|
|
581
|
-
function
|
|
582
|
-
|
|
653
|
+
function builtArtifact(layout) {
|
|
654
|
+
const binDir = import_node_path2.default.join(layout.root, ".build", WASM_TRIPLE, "release");
|
|
655
|
+
const manifest = (0, import_node_fs2.readFileSync)(import_node_path2.default.join(layout.root, "Package.swift"), "utf8");
|
|
656
|
+
const executable = swiftManifestTargets(manifest).find((target) => target.executable);
|
|
657
|
+
if (executable === void 0) {
|
|
658
|
+
throw new Error("swift-compile: the written manifest names no executable target");
|
|
659
|
+
}
|
|
660
|
+
const file = import_node_path2.default.join(binDir, `${executable.name}.wasm`);
|
|
661
|
+
if (!(0, import_node_fs2.existsSync)(file)) {
|
|
662
|
+
const found = (0, import_node_fs2.existsSync)(binDir) ? (0, import_node_fs2.readdirSync)(binDir).filter((name) => name.endsWith(".wasm")).sort() : [];
|
|
663
|
+
throw new Error(
|
|
664
|
+
`swift-compile: the build produced no ${executable.name}.wasm (found: ${found.join(", ") || "none"})`
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
return file;
|
|
583
668
|
}
|
|
584
|
-
function
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
});
|
|
669
|
+
function projectDiagnostic(output, layout) {
|
|
670
|
+
const base = layout.multi ? layout.root : layout.sources;
|
|
671
|
+
const prefix = `${base}${import_node_path2.default.sep}`;
|
|
672
|
+
return output.split("\n").map((line) => line.startsWith(prefix) ? line.slice(prefix.length) : line).join("\n").trim();
|
|
589
673
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
return Buffer.from(
|
|
601
|
-
icuSegment(archiveMember((0, import_node_fs2.readFileSync)(import_node_path3.default.join(resources, ARCHIVE)), MEMBER))
|
|
674
|
+
var ROOT_LOCKS = Symbol.for("peachsim.swiftCompile.rootLocks");
|
|
675
|
+
var host = globalThis;
|
|
676
|
+
var rootLocks = host[ROOT_LOCKS] ??= /* @__PURE__ */ new Map();
|
|
677
|
+
function serialize(root, work) {
|
|
678
|
+
const current = rootLocks.get(root) ?? Promise.resolve();
|
|
679
|
+
const next = current.then(work, work);
|
|
680
|
+
rootLocks.set(
|
|
681
|
+
root,
|
|
682
|
+
next.catch(() => {
|
|
683
|
+
})
|
|
602
684
|
);
|
|
685
|
+
return next;
|
|
603
686
|
}
|
|
604
|
-
function
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
if (raw2 === "//") names = body.toString("latin1");
|
|
613
|
-
const member = /^\/\d+$/.test(raw2) ? names.slice(Number(raw2.slice(1)), names.indexOf("/\n", Number(raw2.slice(1)))) : raw2.replace(/\/$/, "");
|
|
614
|
-
if (member === name) return body;
|
|
615
|
-
at += 60 + size + size % 2;
|
|
616
|
-
}
|
|
617
|
-
throw new Error(`swift-icu: ${name} is not in the sdk's icu archive`);
|
|
618
|
-
}
|
|
619
|
-
function icuSegment(object) {
|
|
620
|
-
let at = 8;
|
|
621
|
-
const leb = () => {
|
|
622
|
-
let result = 0;
|
|
623
|
-
let shift = 0;
|
|
624
|
-
let byte;
|
|
625
|
-
do {
|
|
626
|
-
byte = object[at++];
|
|
627
|
-
result += (byte & 127) * 2 ** shift;
|
|
628
|
-
shift += 7;
|
|
629
|
-
} while (byte & 128);
|
|
630
|
-
return result;
|
|
687
|
+
function compileSwiftProjectUnit(input, options) {
|
|
688
|
+
(0, import_node_fs2.mkdirSync)(options.buildRoot, { recursive: true });
|
|
689
|
+
const root = (0, import_node_fs2.realpathSync)(options.buildRoot);
|
|
690
|
+
const moduleRoot = import_node_path2.default.resolve(options.moduleRoot);
|
|
691
|
+
const layout = {
|
|
692
|
+
root,
|
|
693
|
+
sources: import_node_path2.default.join(root, "Sources", "App"),
|
|
694
|
+
multi: compileTargets(input).length > 0
|
|
631
695
|
};
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
const
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
at++;
|
|
641
|
-
leb();
|
|
642
|
-
at++;
|
|
643
|
-
const length = leb();
|
|
644
|
-
const bytes = object.subarray(at, at + length);
|
|
645
|
-
if (bytes[2] === 218 && bytes[3] === 39) found.push(bytes);
|
|
646
|
-
at += length;
|
|
647
|
-
}
|
|
696
|
+
const hash = swiftArtifactHash(input, options.release, moduleRoot);
|
|
697
|
+
return serialize(root, async () => {
|
|
698
|
+
writeSwiftProject(layout, input, moduleRoot);
|
|
699
|
+
const swift = import_node_path2.default.join(options.toolchainBin, "swift");
|
|
700
|
+
if (!(0, import_node_fs2.existsSync)(swift)) {
|
|
701
|
+
throw new Error(
|
|
702
|
+
`swift-compile: no swift.org toolchain at ${options.toolchainBin}; install ${options.release} and its matching wasm sdk`
|
|
703
|
+
);
|
|
648
704
|
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
705
|
+
const macroPlugins = await ensureMacroPlugins(moduleRoot, options.toolchainBin);
|
|
706
|
+
const icu = swiftIcuAsset(options.toolchainBin, options.release);
|
|
707
|
+
try {
|
|
708
|
+
await run2(
|
|
709
|
+
swift,
|
|
710
|
+
[
|
|
711
|
+
"build",
|
|
712
|
+
"-j",
|
|
713
|
+
BUILD_JOBS,
|
|
714
|
+
"--package-path",
|
|
715
|
+
root,
|
|
716
|
+
"--swift-sdk",
|
|
717
|
+
`${options.release}_wasm`,
|
|
718
|
+
"-c",
|
|
719
|
+
"release",
|
|
720
|
+
"-Xswiftc",
|
|
721
|
+
"-Osize",
|
|
722
|
+
...macroPlugins.flatMap((plugin) => [
|
|
723
|
+
"-Xswiftc",
|
|
724
|
+
"-load-plugin-library",
|
|
725
|
+
"-Xswiftc",
|
|
726
|
+
plugin
|
|
727
|
+
])
|
|
728
|
+
],
|
|
729
|
+
{ env: BUILD_ENV, maxBuffer: 64 * 1024 * 1024, timeout: options.timeoutMs }
|
|
730
|
+
);
|
|
731
|
+
} catch (error) {
|
|
732
|
+
throw new Error(projectDiagnostic(outputOf(error), layout), { cause: error });
|
|
733
|
+
}
|
|
734
|
+
return {
|
|
735
|
+
hash,
|
|
736
|
+
bytes: (0, import_node_fs2.readFileSync)(builtArtifact(layout)),
|
|
737
|
+
icu: await icu
|
|
738
|
+
};
|
|
739
|
+
});
|
|
654
740
|
}
|
|
655
741
|
|
|
656
|
-
// src/swift-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
} else if (ch === '"') {
|
|
678
|
-
inString = true;
|
|
679
|
-
if (depth === 1) flat += ch;
|
|
680
|
-
} else if (ch === "(") {
|
|
681
|
-
depth++;
|
|
682
|
-
if (depth === 1) flat += ch;
|
|
683
|
-
} else if (ch === ")") {
|
|
684
|
-
depth--;
|
|
685
|
-
if (depth >= 1) flat += ch;
|
|
686
|
-
} else if (depth === 1) {
|
|
687
|
-
flat += ch;
|
|
688
|
-
}
|
|
689
|
-
i++;
|
|
690
|
-
}
|
|
691
|
-
const name = /\bname\s*:\s*"([^"]+)"/.exec(flat)?.[1];
|
|
692
|
-
if (!name) continue;
|
|
693
|
-
const rawPath = /\bpath\s*:\s*"([^"]*)"/.exec(flat)?.[1];
|
|
694
|
-
const targetPath = rawPath == null || rawPath === "" ? `Sources/${name}` : rawPath.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
695
|
-
const call = code.slice(start, i);
|
|
696
|
-
const languageMode = Number(
|
|
697
|
-
/\.swiftLanguageMode\(\s*\.v(\d+)\s*\)/.exec(call)?.[1] ?? "5"
|
|
698
|
-
);
|
|
699
|
-
const mainActorIsolation = /\.defaultIsolation\(\s*MainActor\.self\s*\)/.test(call);
|
|
700
|
-
const resources = /\bresources\s*:/.test(flat);
|
|
701
|
-
targets.push({
|
|
702
|
-
name,
|
|
703
|
-
path: targetPath,
|
|
704
|
-
executable,
|
|
705
|
-
languageMode,
|
|
706
|
-
mainActorIsolation,
|
|
707
|
-
resources
|
|
708
|
-
});
|
|
709
|
-
}
|
|
710
|
-
return targets;
|
|
742
|
+
// src/swift-host.ts
|
|
743
|
+
var import_node_crypto3 = require("node:crypto");
|
|
744
|
+
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
|
745
|
+
var import_node_os3 = __toESM(require("node:os"), 1);
|
|
746
|
+
var import_node_path5 = __toESM(require("node:path"), 1);
|
|
747
|
+
|
|
748
|
+
// ../sootsim-swift/src/bundleAssets.ts
|
|
749
|
+
var import_svgpath = __toESM(require("svgpath"), 1);
|
|
750
|
+
var RASTER_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
751
|
+
".avif",
|
|
752
|
+
".bmp",
|
|
753
|
+
".gif",
|
|
754
|
+
".ico",
|
|
755
|
+
".jpeg",
|
|
756
|
+
".jpg",
|
|
757
|
+
".png",
|
|
758
|
+
".webp"
|
|
759
|
+
]);
|
|
760
|
+
function extOf(file) {
|
|
761
|
+
const dot = file.lastIndexOf(".");
|
|
762
|
+
return dot < 0 ? "" : file.slice(dot).toLowerCase();
|
|
711
763
|
}
|
|
712
|
-
function
|
|
713
|
-
const
|
|
714
|
-
return
|
|
764
|
+
function baseOf(file) {
|
|
765
|
+
const slash = file.lastIndexOf("/");
|
|
766
|
+
return slash < 0 ? file : file.slice(slash + 1);
|
|
715
767
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
"
|
|
726
|
-
"scripts/contrast-app-Package.swift",
|
|
727
|
-
"toolchain.json"
|
|
728
|
-
];
|
|
729
|
-
const walk = (dir) => {
|
|
730
|
-
for (const entry of (0, import_node_fs3.readdirSync)(import_node_path4.default.join(root, dir), { withFileTypes: true })) {
|
|
731
|
-
const relative = `${dir}/${entry.name}`;
|
|
732
|
-
if (entry.isDirectory()) walk(relative);
|
|
733
|
-
else if (/\.(swift|c|h)$/.test(entry.name)) files.push(relative);
|
|
734
|
-
}
|
|
768
|
+
function pickImagesetFile(images) {
|
|
769
|
+
const rasters = images.filter(
|
|
770
|
+
(image) => typeof image.filename === "string" && RASTER_EXTENSIONS.has(extOf(image.filename))
|
|
771
|
+
);
|
|
772
|
+
if (rasters.length === 0) return null;
|
|
773
|
+
const rank = (scale) => scale === "2x" ? 0 : scale === "3x" ? 1 : scale === "1x" ? 2 : 3;
|
|
774
|
+
const pick = [...rasters].sort((a, b) => rank(a.scale) - rank(b.scale))[0];
|
|
775
|
+
return {
|
|
776
|
+
filename: pick.filename,
|
|
777
|
+
scale: pick.scale === "2x" ? 2 : pick.scale === "3x" ? 3 : 1
|
|
735
778
|
};
|
|
736
|
-
walk("Sources");
|
|
737
|
-
return files.sort();
|
|
738
779
|
}
|
|
739
|
-
|
|
740
|
-
const
|
|
741
|
-
|
|
742
|
-
const plugins = [
|
|
743
|
-
{
|
|
744
|
-
library: import_node_path4.default.join(dir, `libRnxPreviewMacros.${ext}`),
|
|
745
|
-
source: import_node_path4.default.join(moduleRoot, "Sources/RnxPreviewMacros/PreviewMacro.swift")
|
|
746
|
-
},
|
|
747
|
-
{
|
|
748
|
-
library: import_node_path4.default.join(dir, `libFoundationMacros.${ext}`),
|
|
749
|
-
source: import_node_path4.default.join(moduleRoot, "Sources/FoundationMacros/PredicateMacro.swift")
|
|
750
|
-
}
|
|
751
|
-
];
|
|
752
|
-
const stale = plugins.some(
|
|
753
|
-
({ library, source }) => !(0, import_node_fs3.existsSync)(library) || (0, import_node_fs3.statSync)(source).mtimeMs > (0, import_node_fs3.statSync)(library).mtimeMs
|
|
754
|
-
);
|
|
755
|
-
if (stale) {
|
|
756
|
-
await run2("sh", [
|
|
757
|
-
import_node_path4.default.join(moduleRoot, "scripts/build-preview-plugin.sh"),
|
|
758
|
-
toolchainBin,
|
|
759
|
-
plugins[0].library
|
|
760
|
-
]);
|
|
761
|
-
}
|
|
762
|
-
return plugins.map(({ library }) => library);
|
|
780
|
+
function flatScale(path6) {
|
|
781
|
+
const match = /@([23])x\.[^./]+$/.exec(path6);
|
|
782
|
+
return match ? Number(match[1]) : 1;
|
|
763
783
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
stampHash.update(
|
|
772
|
-
`${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}
|
|
773
|
-
`
|
|
774
|
-
);
|
|
775
|
-
}
|
|
776
|
-
const stamp = stampHash.digest("hex");
|
|
777
|
-
const cached = linkedModuleDigests.get(root);
|
|
778
|
-
if (cached?.stamp === stamp) return cached.digest;
|
|
779
|
-
const hash = (0, import_node_crypto2.createHash)("sha256");
|
|
780
|
-
for (const file of files) {
|
|
781
|
-
hash.update((0, import_node_crypto2.createHash)("sha256").update(file).digest());
|
|
782
|
-
hash.update(
|
|
783
|
-
(0, import_node_crypto2.createHash)("sha256").update((0, import_node_fs3.readFileSync)(import_node_path4.default.join(root, file))).digest()
|
|
784
|
-
);
|
|
784
|
+
function providesNamespace(text) {
|
|
785
|
+
if (text === null) return false;
|
|
786
|
+
try {
|
|
787
|
+
const parsed = JSON.parse(text);
|
|
788
|
+
return parsed?.properties?.["provides-namespace"] === true;
|
|
789
|
+
} catch {
|
|
790
|
+
return false;
|
|
785
791
|
}
|
|
786
|
-
const digest = hash.digest();
|
|
787
|
-
linkedModuleDigests.set(root, { stamp, digest });
|
|
788
|
-
return digest;
|
|
789
|
-
}
|
|
790
|
-
function compileTargets(input) {
|
|
791
|
-
const manifest = input.files["Package.swift"];
|
|
792
|
-
return manifest === void 0 ? [] : swiftPackagePartition(manifest);
|
|
793
792
|
}
|
|
794
|
-
function
|
|
795
|
-
const
|
|
796
|
-
|
|
797
|
-
|
|
793
|
+
function catalogEntryName(contentsPath, kind, readText) {
|
|
794
|
+
const parts = contentsPath.split("/");
|
|
795
|
+
const leaf = parts[parts.length - 2] ?? "";
|
|
796
|
+
if (!leaf.endsWith(kind)) return null;
|
|
797
|
+
const short = leaf.slice(0, -kind.length) || null;
|
|
798
|
+
if (short === null) return null;
|
|
799
|
+
const segments = [short];
|
|
800
|
+
for (let depth = parts.length - 3; depth >= 0; depth -= 1) {
|
|
801
|
+
const dir = parts[depth] ?? "";
|
|
802
|
+
if (dir.endsWith(".xcassets") || dir === "" || dir === "." || dir === "..") break;
|
|
803
|
+
const folderContents = [...parts.slice(0, depth + 1), "Contents.json"].join("/");
|
|
804
|
+
if (providesNamespace(readText(folderContents))) segments.unshift(dir);
|
|
798
805
|
}
|
|
799
|
-
|
|
800
|
-
return {
|
|
801
|
-
...input,
|
|
802
|
-
files: {
|
|
803
|
-
...input.files,
|
|
804
|
-
[import_node_path4.default.posix.join(targetPath, "OneNativeSource.generated.swift")]: glue
|
|
805
|
-
},
|
|
806
|
-
oneModule: true
|
|
807
|
-
};
|
|
806
|
+
return segments.join("/");
|
|
808
807
|
}
|
|
809
|
-
function
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
808
|
+
function isFlatResourceImage(path6) {
|
|
809
|
+
return path6.split("/").includes("Resources") && RASTER_EXTENSIONS.has(extOf(path6));
|
|
810
|
+
}
|
|
811
|
+
function enumerateBundleImages(paths, readText) {
|
|
812
|
+
const table = [];
|
|
813
|
+
const seen = /* @__PURE__ */ new Set();
|
|
814
|
+
const catalogs = paths.filter((path6) => baseOf(path6) === "Contents.json");
|
|
815
|
+
for (const contentsPath of catalogs) {
|
|
816
|
+
const name = catalogEntryName(contentsPath, ".imageset", readText);
|
|
817
|
+
if (name === null || seen.has(name)) continue;
|
|
818
|
+
let parsed;
|
|
819
|
+
try {
|
|
820
|
+
const text = readText(contentsPath);
|
|
821
|
+
if (text === null) continue;
|
|
822
|
+
parsed = JSON.parse(text);
|
|
823
|
+
} catch {
|
|
824
|
+
continue;
|
|
822
825
|
}
|
|
823
|
-
|
|
826
|
+
const images = parsed?.images;
|
|
827
|
+
if (!Array.isArray(images)) continue;
|
|
828
|
+
const dir = contentsPath.split("/").slice(0, -1).join("/");
|
|
829
|
+
const pick = pickImagesetFile(images);
|
|
830
|
+
if (pick === null || pick.filename.includes("/") || pick.filename.includes("\\"))
|
|
831
|
+
continue;
|
|
832
|
+
seen.add(name);
|
|
833
|
+
table.push({ name, file: `${dir}/${pick.filename}`, scale: pick.scale });
|
|
824
834
|
}
|
|
825
|
-
|
|
835
|
+
for (const path6 of paths) {
|
|
836
|
+
if (!isFlatResourceImage(path6)) continue;
|
|
837
|
+
const name = baseOf(path6).slice(0, -extOf(path6).length);
|
|
838
|
+
if (name === "" || seen.has(name)) continue;
|
|
839
|
+
seen.add(name);
|
|
840
|
+
table.push({ name, file: path6, scale: flatScale(path6) });
|
|
841
|
+
}
|
|
842
|
+
return table;
|
|
826
843
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
hash.update(linkedModuleDigest(moduleRoot));
|
|
838
|
-
for (const file of Object.keys(input.files).sort()) {
|
|
839
|
-
hash.update((0, import_node_crypto2.createHash)("sha256").update(file).digest());
|
|
840
|
-
hash.update((0, import_node_crypto2.createHash)("sha256").update(input.files[file]).digest());
|
|
844
|
+
function colorComponent(value) {
|
|
845
|
+
if (typeof value !== "string") return null;
|
|
846
|
+
const parsed = value.startsWith("0x") ? Number.parseInt(value.slice(2), 16) / 255 : value.includes(".") ? Number.parseFloat(value) : Number.parseInt(value, 10) / 255;
|
|
847
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
848
|
+
}
|
|
849
|
+
function colorsetValue(color) {
|
|
850
|
+
if (typeof color !== "object" || color === null) return null;
|
|
851
|
+
const reference = Reflect.get(color, "reference");
|
|
852
|
+
if (typeof reference === "string") {
|
|
853
|
+
return { system: reference.replace(/Color$/, "") };
|
|
841
854
|
}
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
855
|
+
const space = Reflect.get(color, "color-space");
|
|
856
|
+
if (space !== "srgb" && space !== "extended-srgb") return null;
|
|
857
|
+
const components = Reflect.get(color, "components");
|
|
858
|
+
if (typeof components !== "object" || components === null) return null;
|
|
859
|
+
const [red, green, blue, alpha] = ["red", "green", "blue", "alpha"].map(
|
|
860
|
+
(key) => colorComponent(Reflect.get(components, key))
|
|
861
|
+
);
|
|
862
|
+
if (red === null || green === null || blue === null || alpha === null) return null;
|
|
863
|
+
if (![red, green, blue].every((value) => value >= 0 && value <= 1)) return null;
|
|
864
|
+
const byte = (value) => Math.round(value * 255);
|
|
865
|
+
return `rgba(${byte(red)}, ${byte(green)}, ${byte(blue)}, ${alpha})`;
|
|
866
|
+
}
|
|
867
|
+
function enumerateBundleColors(paths, readText) {
|
|
868
|
+
const table = {};
|
|
869
|
+
for (const contentsPath of paths.filter((path6) => baseOf(path6) === "Contents.json")) {
|
|
870
|
+
const name = catalogEntryName(contentsPath, ".colorset", readText);
|
|
871
|
+
if (name === null || name in table) continue;
|
|
872
|
+
let colors;
|
|
873
|
+
try {
|
|
874
|
+
const text = readText(contentsPath);
|
|
875
|
+
if (text === null) continue;
|
|
876
|
+
colors = Reflect.get(JSON.parse(text), "colors");
|
|
877
|
+
} catch {
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
880
|
+
if (!Array.isArray(colors)) continue;
|
|
881
|
+
let light = null;
|
|
882
|
+
let dark = null;
|
|
883
|
+
for (const entry of colors) {
|
|
884
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
885
|
+
const idiom = Reflect.get(entry, "idiom");
|
|
886
|
+
if (idiom !== "universal" && idiom !== "iphone") continue;
|
|
887
|
+
const appearances = Reflect.get(entry, "appearances");
|
|
888
|
+
const list = Array.isArray(appearances) ? appearances : [];
|
|
889
|
+
if (list.some((item) => Reflect.get(item, "appearance") === "contrast")) continue;
|
|
890
|
+
const isDark = list.some(
|
|
891
|
+
(item) => Reflect.get(item, "appearance") === "luminosity" && Reflect.get(item, "value") === "dark"
|
|
892
|
+
);
|
|
893
|
+
if (list.length > 0 && !isDark) continue;
|
|
894
|
+
const value = colorsetValue(Reflect.get(entry, "color"));
|
|
895
|
+
if (value === null) continue;
|
|
896
|
+
if (isDark) dark = value;
|
|
897
|
+
else light = value;
|
|
898
|
+
}
|
|
899
|
+
if (light === null) continue;
|
|
900
|
+
if (typeof light === "object") table[name] = light;
|
|
901
|
+
else table[name] = { light, dark: typeof dark === "string" ? dark : light };
|
|
847
902
|
}
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
903
|
+
return table;
|
|
904
|
+
}
|
|
905
|
+
var SYMBOL_CAP_HEIGHT_EM = 1443 / 2048;
|
|
906
|
+
function axisExtremes(points) {
|
|
907
|
+
const [a = 0, b = 0, c = 0, d] = points;
|
|
908
|
+
const out = [a, d ?? c];
|
|
909
|
+
const within = (t) => t > 0 && t < 1;
|
|
910
|
+
if (d === void 0) {
|
|
911
|
+
const denom = a - 2 * b + c;
|
|
912
|
+
const t = denom === 0 ? -1 : (a - b) / denom;
|
|
913
|
+
if (within(t)) out.push((1 - t) ** 2 * a + 2 * (1 - t) * t * b + t ** 2 * c);
|
|
914
|
+
return out;
|
|
854
915
|
}
|
|
855
|
-
const
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
916
|
+
const qa = 3 * (-a + 3 * b - 3 * c + d);
|
|
917
|
+
const qb = 6 * (a - 2 * b + c);
|
|
918
|
+
const qc = 3 * (b - a);
|
|
919
|
+
const roots = Math.abs(qa) < 1e-12 ? qb === 0 ? [] : [-qc / qb] : (() => {
|
|
920
|
+
const disc = qb * qb - 4 * qa * qc;
|
|
921
|
+
if (disc < 0) return [];
|
|
922
|
+
const root = Math.sqrt(disc);
|
|
923
|
+
return [(-qb + root) / (2 * qa), (-qb - root) / (2 * qa)];
|
|
924
|
+
})();
|
|
925
|
+
for (const t of roots.filter(within))
|
|
926
|
+
out.push(
|
|
927
|
+
(1 - t) ** 3 * a + 3 * (1 - t) ** 2 * t * b + 3 * (1 - t) * t ** 2 * c + t ** 3 * d
|
|
866
928
|
);
|
|
867
|
-
|
|
868
|
-
return hash.digest("hex");
|
|
929
|
+
return out;
|
|
869
930
|
}
|
|
870
|
-
function
|
|
871
|
-
const
|
|
872
|
-
const
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
` ${kind}(`,
|
|
893
|
-
` name: "${target.name}",`,
|
|
894
|
-
` dependencies: [${deps}],`,
|
|
895
|
-
` path: "${target.path}",`,
|
|
896
|
-
` ${swiftSettings}${link}`,
|
|
897
|
-
` ),`
|
|
898
|
-
].join("\n");
|
|
931
|
+
function pathBounds(d) {
|
|
932
|
+
const xs = [];
|
|
933
|
+
const ys = [];
|
|
934
|
+
for (const path6 of d)
|
|
935
|
+
(0, import_svgpath.default)(path6).abs().unshort().unarc().iterate((segment, _index, x, y) => {
|
|
936
|
+
const [command, ...args] = segment;
|
|
937
|
+
if (command === "M" || command === "L") {
|
|
938
|
+
xs.push(Number(args[0]));
|
|
939
|
+
ys.push(Number(args[1]));
|
|
940
|
+
} else if (command === "H") xs.push(Number(args[0]));
|
|
941
|
+
else if (command === "V") ys.push(Number(args[0]));
|
|
942
|
+
else if (command === "Q" || command === "C") {
|
|
943
|
+
const n = args.map(Number);
|
|
944
|
+
xs.push(...axisExtremes([x, ...n.filter((_, i) => i % 2 === 0)]));
|
|
945
|
+
ys.push(...axisExtremes([y, ...n.filter((_, i) => i % 2 === 1)]));
|
|
946
|
+
}
|
|
947
|
+
});
|
|
948
|
+
return {
|
|
949
|
+
minX: Math.min(...xs),
|
|
950
|
+
maxX: Math.max(...xs),
|
|
951
|
+
minY: Math.min(...ys),
|
|
952
|
+
maxY: Math.max(...ys)
|
|
899
953
|
};
|
|
900
|
-
return [
|
|
901
|
-
"// swift-tools-version: 6.2",
|
|
902
|
-
"import PackageDescription",
|
|
903
|
-
"",
|
|
904
|
-
"// generated by swift-compile from the project package partition.",
|
|
905
|
-
"let package = Package(",
|
|
906
|
-
' name: "app",',
|
|
907
|
-
` products: [.executable(name: "${executable.name}", targets: ["${executable.name}"])],`,
|
|
908
|
-
` dependencies: [.package(path: "${moduleRoot}")],`,
|
|
909
|
-
" targets: [",
|
|
910
|
-
...targets.map(stanza),
|
|
911
|
-
" ]",
|
|
912
|
-
")",
|
|
913
|
-
""
|
|
914
|
-
].join("\n");
|
|
915
954
|
}
|
|
916
|
-
function
|
|
917
|
-
|
|
918
|
-
const
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
955
|
+
function guide(svg, id, axis) {
|
|
956
|
+
const line = new RegExp(`<line[^>]*id="${id}"[^>]*>`).exec(svg)?.[0];
|
|
957
|
+
const value = line === void 0 ? void 0 : new RegExp(`${axis}="([-0-9.]+)"`).exec(line)?.[1];
|
|
958
|
+
return value === void 0 ? null : Number(value);
|
|
959
|
+
}
|
|
960
|
+
function enumerateBundleSymbols(paths, readText) {
|
|
961
|
+
const table = {};
|
|
962
|
+
for (const contentsPath of paths.filter((path6) => baseOf(path6) === "Contents.json")) {
|
|
963
|
+
const name = catalogEntryName(contentsPath, ".symbolset", readText);
|
|
964
|
+
if (name === null || name in table) continue;
|
|
965
|
+
let symbols;
|
|
966
|
+
try {
|
|
967
|
+
symbols = Reflect.get(JSON.parse(readText(contentsPath) ?? "null") ?? {}, "symbols");
|
|
968
|
+
} catch {
|
|
969
|
+
continue;
|
|
924
970
|
}
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
971
|
+
const file = Array.isArray(symbols) ? symbols.map((entry) => Reflect.get(entry ?? {}, "filename")).find((f) => typeof f === "string") : void 0;
|
|
972
|
+
if (typeof file !== "string") continue;
|
|
973
|
+
if (file.includes("/") || file.includes("\\")) continue;
|
|
974
|
+
const svg = readText(`${contentsPath.split("/").slice(0, -1).join("/")}/${file}`);
|
|
975
|
+
if (svg === null) continue;
|
|
976
|
+
const group = /<g id="Regular-M"[^>]*>([\s\S]*?)<\/g>/.exec(svg)?.[1];
|
|
977
|
+
const baseline = guide(svg, "Baseline-M", "y1");
|
|
978
|
+
const capline = guide(svg, "Capline-M", "y1");
|
|
979
|
+
const left = guide(svg, "left-margin-Regular-M", "x1") ?? guide(svg, "left-margin", "x1");
|
|
980
|
+
const right = guide(svg, "right-margin-Regular-M", "x1") ?? guide(svg, "right-margin", "x1");
|
|
981
|
+
if (group === void 0 || baseline === null || capline === null || left === null || right === null)
|
|
982
|
+
continue;
|
|
983
|
+
const d = [...group.matchAll(/ d="([^"]+)"/g)].map((match) => match[1] ?? "");
|
|
984
|
+
if (d.length === 0 || baseline <= capline) continue;
|
|
985
|
+
const scale = 24 * SYMBOL_CAP_HEIGHT_EM / (baseline - capline);
|
|
986
|
+
const box = pathBounds(d);
|
|
987
|
+
const translateX = 12 - (box.minX + box.maxX) * scale / 2;
|
|
988
|
+
const translateY = 12 - (box.minY + box.maxY) * scale / 2;
|
|
989
|
+
const advance = Math.round((right - left) * scale * 1e3) / 1e3;
|
|
990
|
+
const tall = (box.maxY - box.minY) * scale + 0.175 * 24;
|
|
991
|
+
table[name] = {
|
|
992
|
+
viewBox: "0 0 24 24",
|
|
993
|
+
advance,
|
|
994
|
+
box: [12 - advance / 2, 12 - tall / 2, advance, tall],
|
|
995
|
+
layers: d.map((path6) => ({
|
|
996
|
+
d: (0, import_svgpath.default)(path6).abs().scale(scale).translate(translateX, translateY).round(3).toString()
|
|
997
|
+
}))
|
|
998
|
+
};
|
|
931
999
|
}
|
|
1000
|
+
return table;
|
|
932
1001
|
}
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
for (const at of tokens) {
|
|
949
|
-
const rest = conditioned.slice(at, at + 200);
|
|
950
|
-
const selector = SELECTOR.exec(rest);
|
|
951
|
-
const match = selector ?? OBJC_ATTRIBUTE.exec(rest);
|
|
952
|
-
if (!match) continue;
|
|
953
|
-
let replacement = "@ObjC";
|
|
954
|
-
if (selector) replacement = "#Selector";
|
|
955
|
-
else if (match[0] === "@objcMembers") replacement = "@ObjCMembers";
|
|
956
|
-
else if (match[0] === "@IBAction") replacement = "@ObjC".padEnd(match[0].length);
|
|
957
|
-
else if (match[2] !== void 0)
|
|
958
|
-
replacement = `@ObjC${match[1]}("${match[2].trim()}")`;
|
|
959
|
-
out += conditioned.slice(copied, at) + replacement;
|
|
960
|
-
copied = at + match[0].length;
|
|
1002
|
+
function enumerateBundleJson(paths) {
|
|
1003
|
+
const found = [];
|
|
1004
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1005
|
+
const ordered = [...paths].filter(
|
|
1006
|
+
(path6) => path6.split("/").includes("Resources") && path6.split("/").every((segment) => segment !== "" && segment !== "..") && (extOf(path6) === ".json" || extOf(path6) === ".xcstrings")
|
|
1007
|
+
).sort((a, b) => {
|
|
1008
|
+
const aDepth = a.split("/").length;
|
|
1009
|
+
const bDepth = b.split("/").length;
|
|
1010
|
+
return aDepth - bDepth || (a < b ? -1 : a > b ? 1 : 0);
|
|
1011
|
+
});
|
|
1012
|
+
for (const file of ordered) {
|
|
1013
|
+
const base = baseOf(file);
|
|
1014
|
+
if (seen.has(base)) continue;
|
|
1015
|
+
seen.add(base);
|
|
1016
|
+
found.push({ base, file });
|
|
961
1017
|
}
|
|
962
|
-
return
|
|
1018
|
+
return found;
|
|
963
1019
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
if (source.startsWith(quote, i) && closes(i + quote.length, top.hashes)) {
|
|
1001
|
-
stack.pop();
|
|
1002
|
-
i += quote.length + top.hashes;
|
|
1003
|
-
} else i++;
|
|
1004
|
-
continue;
|
|
1005
|
-
}
|
|
1006
|
-
if (top.kind === "regex") {
|
|
1007
|
-
if (char === "/" && closes(i + 1, top.hashes)) {
|
|
1008
|
-
stack.pop();
|
|
1009
|
-
i += 1 + top.hashes;
|
|
1010
|
-
} else i++;
|
|
1011
|
-
continue;
|
|
1012
|
-
}
|
|
1013
|
-
if (source.startsWith("//", i)) {
|
|
1014
|
-
const end = source.indexOf("\n", i);
|
|
1015
|
-
i = end === -1 ? source.length : end;
|
|
1016
|
-
} else if (source.startsWith("/*", i)) {
|
|
1017
|
-
stack.push({ kind: "block", depth: 1 });
|
|
1018
|
-
i += 2;
|
|
1019
|
-
} else if (char === '"' || char === "#") {
|
|
1020
|
-
const hashes = hashesAt(i);
|
|
1021
|
-
const at = i + hashes;
|
|
1022
|
-
if (source.startsWith('"""', at)) {
|
|
1023
|
-
stack.push({ kind: "string", hashes, multiline: true });
|
|
1024
|
-
i = at + 3;
|
|
1025
|
-
} else if (source[at] === '"') {
|
|
1026
|
-
stack.push({ kind: "string", hashes, multiline: false });
|
|
1027
|
-
i = at + 1;
|
|
1028
|
-
} else if (hashes > 0 && source[at] === "/") {
|
|
1029
|
-
stack.push({ kind: "regex", hashes });
|
|
1030
|
-
i = at + 1;
|
|
1031
|
-
} else {
|
|
1032
|
-
if (hashes > 0) tokens.push(at - 1);
|
|
1033
|
-
i = Math.max(at, i + 1);
|
|
1034
|
-
}
|
|
1035
|
-
} else if (char === "(") {
|
|
1036
|
-
top.parens++;
|
|
1037
|
-
i++;
|
|
1038
|
-
} else if (char === ")") {
|
|
1039
|
-
if (top.parens === 0 && stack.length > 1) stack.pop();
|
|
1040
|
-
else top.parens--;
|
|
1041
|
-
i++;
|
|
1042
|
-
} else {
|
|
1043
|
-
if (char === "@") tokens.push(i);
|
|
1044
|
-
i++;
|
|
1045
|
-
}
|
|
1020
|
+
|
|
1021
|
+
// src/auth/shared-session.ts
|
|
1022
|
+
var import_node_fs3 = require("node:fs");
|
|
1023
|
+
var import_node_path4 = require("node:path");
|
|
1024
|
+
|
|
1025
|
+
// src/home-paths.ts
|
|
1026
|
+
var import_node_os2 = require("node:os");
|
|
1027
|
+
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
1028
|
+
var PEACH_HOME_ENV = "PEACH_HOME";
|
|
1029
|
+
function rnxHomeDir() {
|
|
1030
|
+
const override = process.env[PEACH_HOME_ENV];
|
|
1031
|
+
if (override && override.length > 0) return import_node_path3.default.resolve(override);
|
|
1032
|
+
return import_node_path3.default.join((0, import_node_os2.homedir)(), ".peach");
|
|
1033
|
+
}
|
|
1034
|
+
function electronDir() {
|
|
1035
|
+
return import_node_path3.default.join(rnxHomeDir(), "electron");
|
|
1036
|
+
}
|
|
1037
|
+
function electronUserDataDir() {
|
|
1038
|
+
return import_node_path3.default.join(electronDir(), "userData");
|
|
1039
|
+
}
|
|
1040
|
+
var DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
|
|
1041
|
+
|
|
1042
|
+
// src/auth/shared-session.ts
|
|
1043
|
+
function sharedDesktopAuthAccounts(user) {
|
|
1044
|
+
return [
|
|
1045
|
+
...user?.personalAccountId ? [{ id: user.personalAccountId, name: "Personal" }] : [],
|
|
1046
|
+
...(user?.teams ?? []).map((team) => ({ id: team.id, name: team.name }))
|
|
1047
|
+
];
|
|
1048
|
+
}
|
|
1049
|
+
var SESSION_VERSION = 1;
|
|
1050
|
+
var SESSION_FILE_ENV = "SOOTSIM_SHARED_AUTH_FILE";
|
|
1051
|
+
var DEFAULT_ORIGIN = "https://contrast.dev";
|
|
1052
|
+
function getBaseDir() {
|
|
1053
|
+
const explicit = process.env[SESSION_FILE_ENV];
|
|
1054
|
+
if (explicit?.trim()) {
|
|
1055
|
+
return (0, import_node_path4.dirname)((0, import_node_path4.resolve)(explicit));
|
|
1046
1056
|
}
|
|
1047
|
-
return
|
|
1057
|
+
return electronUserDataDir();
|
|
1058
|
+
}
|
|
1059
|
+
function getSharedDesktopAuthFilePath() {
|
|
1060
|
+
const explicit = process.env[SESSION_FILE_ENV];
|
|
1061
|
+
if (explicit?.trim()) return (0, import_node_path4.resolve)(explicit);
|
|
1062
|
+
return (0, import_node_path4.join)(getBaseDir(), "desktop-auth.json");
|
|
1063
|
+
}
|
|
1064
|
+
function normalizeUser(input) {
|
|
1065
|
+
if (!input || typeof input !== "object") return null;
|
|
1066
|
+
const value = input;
|
|
1067
|
+
if (typeof value.id !== "string" || !value.id.trim()) return null;
|
|
1068
|
+
return {
|
|
1069
|
+
id: value.id.trim(),
|
|
1070
|
+
name: typeof value.name === "string" ? value.name : void 0,
|
|
1071
|
+
email: typeof value.email === "string" ? value.email : void 0,
|
|
1072
|
+
image: typeof value.image === "string" ? value.image : void 0,
|
|
1073
|
+
githubUsername: typeof value.githubUsername === "string" ? value.githubUsername : void 0,
|
|
1074
|
+
personalAccountId: typeof value.personalAccountId === "string" && value.personalAccountId.trim() ? value.personalAccountId.trim() : void 0,
|
|
1075
|
+
isAdmin: value.isAdmin === true,
|
|
1076
|
+
teams: Array.isArray(value.teams) ? value.teams.map((team) => {
|
|
1077
|
+
if (!team || typeof team !== "object") return null;
|
|
1078
|
+
const t = team;
|
|
1079
|
+
if (typeof t.id !== "string" || typeof t.name !== "string") return null;
|
|
1080
|
+
return {
|
|
1081
|
+
id: t.id,
|
|
1082
|
+
name: t.name,
|
|
1083
|
+
role: t.role === "owner" ? "owner" : "member",
|
|
1084
|
+
githubOrg: typeof t.githubOrg === "string" ? t.githubOrg : null
|
|
1085
|
+
};
|
|
1086
|
+
}).filter((team) => !!team) : void 0
|
|
1087
|
+
};
|
|
1048
1088
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
const
|
|
1052
|
-
|
|
1053
|
-
if (
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
for (const target of targets) {
|
|
1080
|
-
if (!target.resources) continue;
|
|
1081
|
-
files.set(
|
|
1082
|
-
import_node_path4.default.join(layout.root, target.path, "ResourceBundleAccessor.generated.swift"),
|
|
1083
|
-
[
|
|
1084
|
-
"import Foundation",
|
|
1085
|
-
"",
|
|
1086
|
-
"extension Foundation.Bundle {",
|
|
1087
|
-
" static let module: Bundle = Bundle.main",
|
|
1088
|
-
"}",
|
|
1089
|
-
""
|
|
1090
|
-
].join("\n")
|
|
1091
|
-
);
|
|
1089
|
+
function normalizeSession(input) {
|
|
1090
|
+
if (!input || typeof input !== "object") return null;
|
|
1091
|
+
const value = input;
|
|
1092
|
+
if (value.version !== SESSION_VERSION) return null;
|
|
1093
|
+
if (typeof value.token !== "string" || !value.token.trim()) return null;
|
|
1094
|
+
const origin = typeof value.origin === "string" && value.origin.trim() ? value.origin.trim() : DEFAULT_ORIGIN;
|
|
1095
|
+
const source = value.source === "cli" || value.source === "electron" || value.source === "browser" || value.source === "unknown" ? value.source : "unknown";
|
|
1096
|
+
const updatedAt = typeof value.updatedAt === "string" && value.updatedAt ? value.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
1097
|
+
const validatedAt = typeof value.validatedAt === "string" && value.validatedAt ? value.validatedAt : void 0;
|
|
1098
|
+
const accountId = typeof value.accountId === "string" && value.accountId.trim() ? value.accountId.trim() : void 0;
|
|
1099
|
+
return {
|
|
1100
|
+
version: SESSION_VERSION,
|
|
1101
|
+
token: value.token.trim(),
|
|
1102
|
+
user: normalizeUser(value.user),
|
|
1103
|
+
origin,
|
|
1104
|
+
source,
|
|
1105
|
+
updatedAt,
|
|
1106
|
+
validatedAt,
|
|
1107
|
+
accountId
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
function readSharedDesktopAuthSession() {
|
|
1111
|
+
const filepath = getSharedDesktopAuthFilePath();
|
|
1112
|
+
if (!(0, import_node_fs3.existsSync)(filepath)) return null;
|
|
1113
|
+
try {
|
|
1114
|
+
const parsed = JSON.parse((0, import_node_fs3.readFileSync)(filepath, "utf8"));
|
|
1115
|
+
const normalized = normalizeSession(parsed);
|
|
1116
|
+
if (!normalized) {
|
|
1117
|
+
(0, import_node_fs3.rmSync)(filepath, { force: true });
|
|
1118
|
+
return null;
|
|
1092
1119
|
}
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
siblings: swiftSiblingDependencies(input.files, targets),
|
|
1098
|
-
moduleRoot,
|
|
1099
|
-
oneModule: input.oneModule
|
|
1100
|
-
})
|
|
1101
|
-
);
|
|
1120
|
+
return normalized;
|
|
1121
|
+
} catch {
|
|
1122
|
+
(0, import_node_fs3.rmSync)(filepath, { force: true });
|
|
1123
|
+
return null;
|
|
1102
1124
|
}
|
|
1103
|
-
syncSwiftTree(layout.root, files);
|
|
1104
1125
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1126
|
+
|
|
1127
|
+
// cli/run-rnx.ts
|
|
1128
|
+
var import_node_async_hooks = require("node:async_hooks");
|
|
1129
|
+
var sinks = new import_node_async_hooks.AsyncLocalStorage();
|
|
1130
|
+
|
|
1131
|
+
// cli/auth.ts
|
|
1132
|
+
var GITHUB_TOKEN_PREFIXES = ["ghs_", "ghp_", "gho_", "ghu_", "github_pat_"];
|
|
1133
|
+
function looksLikeGitHubToken(token) {
|
|
1134
|
+
return Boolean(
|
|
1135
|
+
token && token.length >= 20 && GITHUB_TOKEN_PREFIXES.some((prefix) => token.startsWith(prefix))
|
|
1136
|
+
);
|
|
1109
1137
|
}
|
|
1110
|
-
function
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1138
|
+
function resolveGitHubActionsAuth() {
|
|
1139
|
+
const contrastRunnerToken = process.env.CONTRAST_INSTALLATION_TOKEN?.trim();
|
|
1140
|
+
const githubActionsToken = process.env.GITHUB_TOKEN?.trim();
|
|
1141
|
+
const token = contrastRunnerToken || githubActionsToken;
|
|
1142
|
+
if (!looksLikeGitHubToken(token)) return null;
|
|
1143
|
+
const repoSlug = (process.env.CONTRAST_REPO || process.env.GITHUB_REPOSITORY || "").trim();
|
|
1144
|
+
if (!repoSlug) return null;
|
|
1145
|
+
const [owner, repo] = repoSlug.includes("/") ? repoSlug.split("/", 2) : [null, null];
|
|
1146
|
+
const repositoryId = (process.env.CONTRAST_REPO_ID || process.env.GITHUB_REPOSITORY_ID || "").trim();
|
|
1147
|
+
const installationId = (process.env.CONTRAST_INSTALLATION_ID || process.env.GITHUB_APP_INSTALLATION_ID || "").trim();
|
|
1148
|
+
return {
|
|
1149
|
+
kind: "github",
|
|
1150
|
+
token,
|
|
1151
|
+
repoId: repoSlug,
|
|
1152
|
+
repositoryId: repositoryId || null,
|
|
1153
|
+
owner: owner || null,
|
|
1154
|
+
repo: repo || null,
|
|
1155
|
+
installationId: installationId || null,
|
|
1156
|
+
source: contrastRunnerToken ? "contrast-runner" : "github-actions"
|
|
1157
|
+
};
|
|
1119
1158
|
}
|
|
1120
|
-
function
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1159
|
+
function isCliApiKeySecret(secret) {
|
|
1160
|
+
return secret.startsWith("sk_rnx_");
|
|
1161
|
+
}
|
|
1162
|
+
function readApiKeyFromEnv() {
|
|
1163
|
+
const envName = "PEACH_API_KEY";
|
|
1164
|
+
const secret = process.env[envName]?.trim();
|
|
1165
|
+
return secret && isCliApiKeySecret(secret) ? { secret, envName } : null;
|
|
1166
|
+
}
|
|
1167
|
+
function resolveCliAuth() {
|
|
1168
|
+
const envKey = readApiKeyFromEnv();
|
|
1169
|
+
if (envKey) {
|
|
1170
|
+
return {
|
|
1171
|
+
kind: "api-key",
|
|
1172
|
+
secret: envKey.secret,
|
|
1173
|
+
source: "env",
|
|
1174
|
+
envName: envKey.envName
|
|
1175
|
+
};
|
|
1126
1176
|
}
|
|
1127
|
-
const
|
|
1128
|
-
if (
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1177
|
+
const githubAuth = resolveGitHubActionsAuth();
|
|
1178
|
+
if (githubAuth) return githubAuth;
|
|
1179
|
+
const session = readSharedDesktopAuthSession();
|
|
1180
|
+
if (session?.token) {
|
|
1181
|
+
const accounts = sharedDesktopAuthAccounts(session.user);
|
|
1182
|
+
return {
|
|
1183
|
+
kind: "session",
|
|
1184
|
+
token: session.token,
|
|
1185
|
+
origin: session.origin,
|
|
1186
|
+
accountId: session.accountId ?? (accounts.length === 1 ? accounts[0]?.id ?? null : null)
|
|
1187
|
+
};
|
|
1133
1188
|
}
|
|
1134
|
-
return
|
|
1189
|
+
return null;
|
|
1135
1190
|
}
|
|
1136
|
-
function
|
|
1137
|
-
|
|
1138
|
-
const prefix = `${base}${import_node_path4.default.sep}`;
|
|
1139
|
-
return output.split("\n").map((line) => line.startsWith(prefix) ? line.slice(prefix.length) : line).join("\n").trim();
|
|
1191
|
+
function authHeaderValue(auth) {
|
|
1192
|
+
return auth.kind === "api-key" ? `Bearer ${auth.secret}` : `Bearer ${auth.token}`;
|
|
1140
1193
|
}
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
var
|
|
1144
|
-
function
|
|
1145
|
-
|
|
1146
|
-
const next = current.then(work, work);
|
|
1147
|
-
rootLocks.set(
|
|
1148
|
-
root,
|
|
1149
|
-
next.catch(() => {
|
|
1150
|
-
})
|
|
1151
|
-
);
|
|
1152
|
-
return next;
|
|
1194
|
+
|
|
1195
|
+
// src/backend-origin.ts
|
|
1196
|
+
var DEFAULT_CONTRAST_BACKEND_ORIGIN = "https://contrast.dev";
|
|
1197
|
+
function normalizeHostname(hostname) {
|
|
1198
|
+
return hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
1153
1199
|
}
|
|
1154
|
-
function
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
const
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
const
|
|
1167
|
-
if (
|
|
1168
|
-
|
|
1169
|
-
`swift-compile: no swift.org toolchain at ${options.toolchainBin}; install ${options.release} and its matching wasm sdk`
|
|
1170
|
-
);
|
|
1171
|
-
}
|
|
1172
|
-
const macroPlugins = await ensureMacroPlugins(moduleRoot, options.toolchainBin);
|
|
1173
|
-
const icu = swiftIcuAsset(options.toolchainBin, options.release);
|
|
1174
|
-
try {
|
|
1175
|
-
await run2(
|
|
1176
|
-
swift,
|
|
1177
|
-
[
|
|
1178
|
-
"build",
|
|
1179
|
-
"-j",
|
|
1180
|
-
BUILD_JOBS,
|
|
1181
|
-
"--package-path",
|
|
1182
|
-
root,
|
|
1183
|
-
"--swift-sdk",
|
|
1184
|
-
`${options.release}_wasm`,
|
|
1185
|
-
"-c",
|
|
1186
|
-
"release",
|
|
1187
|
-
"-Xswiftc",
|
|
1188
|
-
"-Osize",
|
|
1189
|
-
...macroPlugins.flatMap((plugin) => [
|
|
1190
|
-
"-Xswiftc",
|
|
1191
|
-
"-load-plugin-library",
|
|
1192
|
-
"-Xswiftc",
|
|
1193
|
-
plugin
|
|
1194
|
-
])
|
|
1195
|
-
],
|
|
1196
|
-
{ env: BUILD_ENV, maxBuffer: 64 * 1024 * 1024, timeout: options.timeoutMs }
|
|
1197
|
-
);
|
|
1198
|
-
} catch (error) {
|
|
1199
|
-
throw new Error(projectDiagnostic(outputOf(error), layout), { cause: error });
|
|
1200
|
+
function isLoopbackHost(hostname) {
|
|
1201
|
+
const normalized = normalizeHostname(hostname);
|
|
1202
|
+
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "0.0.0.0" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
1203
|
+
}
|
|
1204
|
+
function isContrastBackendHost(hostname) {
|
|
1205
|
+
const normalized = normalizeHostname(hostname);
|
|
1206
|
+
return isLoopbackHost(normalized) || normalized === "contrast.dev" || normalized.endsWith(".contrast.dev");
|
|
1207
|
+
}
|
|
1208
|
+
function resolveContrastBackendOrigin(currentOrigin) {
|
|
1209
|
+
const origin = currentOrigin?.trim();
|
|
1210
|
+
if (!origin) return DEFAULT_CONTRAST_BACKEND_ORIGIN;
|
|
1211
|
+
try {
|
|
1212
|
+
const parsed = new URL(origin);
|
|
1213
|
+
if (isLoopbackHost(parsed.hostname) || isContrastBackendHost(parsed.hostname)) {
|
|
1214
|
+
return parsed.origin;
|
|
1200
1215
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
icu: await icu
|
|
1205
|
-
};
|
|
1206
|
-
});
|
|
1216
|
+
} catch {
|
|
1217
|
+
}
|
|
1218
|
+
return DEFAULT_CONTRAST_BACKEND_ORIGIN;
|
|
1207
1219
|
}
|
|
1208
1220
|
|
|
1209
1221
|
// src/swift-submit.ts
|
|
@@ -1216,7 +1228,7 @@ var MAX_SWIFT_COMPILE_RESOURCE_TOTAL_BYTES = 8 * 1024 * 1024;
|
|
|
1216
1228
|
var MAX_SWIFT_COMPILE_IMAGES = 128;
|
|
1217
1229
|
var MAX_SWIFT_COMPILE_IMAGE_BYTES = 4 * 1024 * 1024;
|
|
1218
1230
|
var MAX_SWIFT_COMPILE_IMAGE_TOTAL_BYTES = 16 * 1024 * 1024;
|
|
1219
|
-
var SWIFT_HOST_ABI =
|
|
1231
|
+
var SWIFT_HOST_ABI = 3;
|
|
1220
1232
|
var POLL_INTERVAL_MS = 1500;
|
|
1221
1233
|
function swiftNativeEntry(native, file) {
|
|
1222
1234
|
return {
|
|
@@ -1996,9 +2008,12 @@ function swiftPlugin(options = {}) {
|
|
|
1996
2008
|
])
|
|
1997
2009
|
this.addWatchFile(source);
|
|
1998
2010
|
this.addWatchFile(import_node_path6.default.join(packagePath, "Package.swift"));
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2011
|
+
const moduleRoot = linkedModuleRoots(packagePath).find(
|
|
2012
|
+
(root) => import_node_fs5.default.existsSync(import_node_path6.default.join(root, "toolchain.json"))
|
|
2013
|
+
);
|
|
2014
|
+
if (moduleRoot)
|
|
2015
|
+
for (const relative of swiftModuleInputFiles(moduleRoot))
|
|
2016
|
+
this.addWatchFile(import_node_path6.default.join(moduleRoot, relative));
|
|
2002
2017
|
let artifact;
|
|
2003
2018
|
try {
|
|
2004
2019
|
artifact = await artifactFor(project, entry);
|