@invarn/cibuild 2.7.9 → 2.8.1

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.
Files changed (33) hide show
  1. package/dist/cli.cjs +143 -10
  2. package/dist/src/commands/a-properties-stand-in-declares-the-keys-the-build-reads.test.d.ts +2 -0
  3. package/dist/src/commands/a-properties-stand-in-declares-the-keys-the-build-reads.test.d.ts.map +1 -0
  4. package/dist/src/commands/a-properties-stand-in-declares-the-keys-the-build-reads.test.js +218 -0
  5. package/dist/src/commands/android-java-version.test.js +93 -10
  6. package/dist/src/commands/android-scanner.d.ts +109 -8
  7. package/dist/src/commands/android-scanner.d.ts.map +1 -1
  8. package/dist/src/commands/android-scanner.js +397 -27
  9. package/dist/src/commands/build.d.ts +8 -0
  10. package/dist/src/commands/build.d.ts.map +1 -1
  11. package/dist/src/commands/build.js +17 -3
  12. package/dist/src/commands/index.d.ts +1 -0
  13. package/dist/src/commands/index.d.ts.map +1 -1
  14. package/dist/src/commands/index.js +3 -0
  15. package/dist/src/commands/ios-scanner.d.ts.map +1 -1
  16. package/dist/src/commands/ios-scanner.js +15 -24
  17. package/dist/src/commands/ios-scheme-ranking.test.js +5 -0
  18. package/dist/src/shared/detect-project.d.ts +32 -0
  19. package/dist/src/shared/detect-project.d.ts.map +1 -1
  20. package/dist/src/shared/detect-project.js +62 -10
  21. package/dist/src/shared/xcode-container.test.d.ts +2 -0
  22. package/dist/src/shared/xcode-container.test.d.ts.map +1 -0
  23. package/dist/src/shared/xcode-container.test.js +123 -0
  24. package/dist/src/yaml/steps/xcode-app-product.d.ts +90 -0
  25. package/dist/src/yaml/steps/xcode-app-product.d.ts.map +1 -0
  26. package/dist/src/yaml/steps/xcode-app-product.js +247 -0
  27. package/dist/src/yaml/steps/xcode-app-product.test.d.ts +2 -0
  28. package/dist/src/yaml/steps/xcode-app-product.test.d.ts.map +1 -0
  29. package/dist/src/yaml/steps/xcode-app-product.test.js +202 -0
  30. package/dist/src/yaml/steps/xcode-derived-data.test.js +66 -1
  31. package/dist/src/yaml/steps/xcode.d.ts.map +1 -1
  32. package/dist/src/yaml/steps/xcode.js +50 -3
  33. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { resolve, relative } from "node:path";
2
2
  import { existsSync, readFileSync, readdirSync } from "node:fs";
3
+ import { xcodeContainersIn } from "../shared/detect-project.js";
3
4
  // ---------------------------------------------------------------------------
4
5
  // File discovery
5
6
  // ---------------------------------------------------------------------------
@@ -18,17 +19,16 @@ function relPath(root, filePath) {
18
19
  * Finds the primary Xcode project path.
19
20
  * Prefers .xcworkspace over .xcodeproj (CocoaPods projects use workspace).
20
21
  * Returns the relative path from root, or empty string if not found.
22
+ *
23
+ * A candidate must be a real container — `isXcodeContainer` — and not merely
24
+ * a directory with the right suffix. `Uwi0/Oakane` ships `iosApp.xcodeproj`
25
+ * with no `project.pbxproj` beside the `oakane.xcodeproj` that has one, and
26
+ * this function returned the husk because it was first.
21
27
  */
22
28
  function findXcodeProjectPath(root) {
23
- let entries;
24
- try {
25
- entries = readdirSync(root);
26
- }
27
- catch {
28
- return "";
29
- }
30
- const workspaces = entries.filter((e) => e.endsWith(".xcworkspace"));
31
- const projects = entries.filter((e) => e.endsWith(".xcodeproj"));
29
+ const containers = xcodeContainersIn(root);
30
+ const workspaces = containers.filter((e) => e.endsWith(".xcworkspace"));
31
+ const projects = containers.filter((e) => e.endsWith(".xcodeproj"));
32
32
  // Prefer workspace (CocoaPods / multi-package setups use these)
33
33
  if (workspaces.length > 0)
34
34
  return workspaces[0];
@@ -43,14 +43,7 @@ function findXcodeProjectPath(root) {
43
43
  */
44
44
  const COMPANION_SCHEME = /(extension|widget|clip|intents?|notification|tvos|macos|watchos|visionos|tests?|screenshots?|staging|prototype|codegen)/i;
45
45
  function readSchemeFacts(root, name) {
46
- let entries;
47
- try {
48
- entries = readdirSync(root);
49
- }
50
- catch {
51
- return undefined;
52
- }
53
- for (const entry of entries) {
46
+ for (const entry of xcodeContainersIn(root)) {
54
47
  if (!entry.endsWith(".xcodeproj"))
55
48
  continue;
56
49
  const path = resolve(root, entry, "xcshareddata", "xcschemes", `${name}.xcscheme`);
@@ -194,13 +187,11 @@ export function rankSchemesWithReason(root, projectPath, schemes) {
194
187
  */
195
188
  function detectSchemes(root) {
196
189
  const schemes = new Set();
197
- let entries;
198
- try {
199
- entries = readdirSync(root);
200
- }
201
- catch {
202
- return [];
203
- }
190
+ // Real projects only. The fallback below invents a scheme from the
191
+ // directory's name, so a husk with no shared schemes contributes a scheme
192
+ // named after a project that cannot be opened — which is how `Uwi0/Oakane`
193
+ // got `IOS_SCHEME: iosApp` as well as `IOS_PROJECT_PATH: iosApp.xcodeproj`.
194
+ const entries = xcodeContainersIn(root);
204
195
  for (const entry of entries) {
205
196
  if (!entry.endsWith(".xcodeproj"))
206
197
  continue;
@@ -30,6 +30,11 @@ afterEach(() => {
30
30
  function scheme(project, name, { runnable, testable, appExtension }) {
31
31
  const dir = join(root, `${project}.xcodeproj`, "xcshareddata", "xcschemes");
32
32
  mkdirSync(dir, { recursive: true });
33
+ // A `.xcodeproj` is its `project.pbxproj`; without one Xcode refuses to open
34
+ // it and the scanners now skip it, so a fixture that omits it is describing
35
+ // a directory that cannot exist outside a test. Content is irrelevant here —
36
+ // the scheme XML is what the ranking reads — but it has to be there.
37
+ writeFileSync(join(root, `${project}.xcodeproj`, "project.pbxproj"), "// !$*UTF8*$!\n");
33
38
  writeFileSync(join(dir, `${name}.xcscheme`), `<?xml version="1.0" encoding="UTF-8"?>
34
39
  <Scheme LastUpgradeVersion = "1600"${appExtension ? `\n wasCreatedForAppExtension = "YES"` : ""} version = "1.7">
35
40
  <TestAction buildConfiguration = "Debug">
@@ -1,5 +1,37 @@
1
1
  export type MobileProjectType = "android" | "ios" | "kmm";
2
2
  declare function isDirectory(path: string): boolean;
3
+ /**
4
+ * True when a path that is *named* like an Xcode container actually is one.
5
+ *
6
+ * **The** predicate — every question of the form "is this `.xcodeproj` a
7
+ * project" goes through here, and nothing else in cibuild joins a directory
8
+ * name to "there is a project there".
9
+ *
10
+ * A `.xcodeproj` is a directory whose whole content is `project.pbxproj`;
11
+ * without it `xcodebuild` refuses to open the project at all — "missing its
12
+ * project.pbxproj file". A `.xcworkspace` is `contents.xcworkspacedata` in
13
+ * the same way. Anything else ending in those suffixes is a directory with a
14
+ * suggestive name, and offering one is offering something Xcode would reject.
15
+ *
16
+ * `Uwi0/Oakane` is the row that found it. Its `iosApp/` ships two: a tracked
17
+ * `iosApp.xcodeproj` holding nothing but `project.xcworkspace/`, and the real
18
+ * `oakane.xcodeproj` beside it with a 20 217-byte `project.pbxproj`. The husk
19
+ * carries the name the KMM wizard gives, so the conventional name outranked
20
+ * the project that exists — and it supplied BOTH `IOS_PROJECT_PATH` and, via
21
+ * the scheme scan's project-name fallback, `IOS_SCHEME`. The build reached
22
+ * step 9 and died on "Unable to read project 'iosApp.xcodeproj'".
23
+ *
24
+ * This is the iOS twin of the Gradle module scan once treating "a directory
25
+ * holding a file called build.gradle" as a module: wrong in the same
26
+ * direction, and fixed the same way — one reader, used by everyone.
27
+ *
28
+ * The `.pbxproj` is deliberately NOT parsed. Its existence and non-emptiness
29
+ * is the whole question; a shared `.xcscheme` remains the oracle for what a
30
+ * project builds.
31
+ */
32
+ export declare function isXcodeContainer(path: string): boolean;
33
+ /** The entries of `dir` that are real Xcode containers, in `readdir` order. */
34
+ export declare function xcodeContainersIn(dir: string): string[];
3
35
  /**
4
36
  * Detects whether the given directory is the root of an Android, iOS, or
5
37
  * KMM project. Returns the detected project type, or null if none match.
@@ -1 +1 @@
1
- {"version":3,"file":"detect-project.d.ts","sourceRoot":"","sources":["../../../src/shared/detect-project.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK,CAAC;AAoB1D,iBAAS,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAM1C;AA+ED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAiC7E;AAED,oEAAoE;AACpE,OAAO,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"detect-project.d.ts","sourceRoot":"","sources":["../../../src/shared/detect-project.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK,CAAC;AAoB1D,iBAAS,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAM1C;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAYtD;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAYvD;AAuED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CA4B7E;AAED,oEAAoE;AACpE,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -33,6 +33,62 @@ function readOrNull(path) {
33
33
  return null;
34
34
  }
35
35
  }
36
+ /**
37
+ * True when a path that is *named* like an Xcode container actually is one.
38
+ *
39
+ * **The** predicate — every question of the form "is this `.xcodeproj` a
40
+ * project" goes through here, and nothing else in cibuild joins a directory
41
+ * name to "there is a project there".
42
+ *
43
+ * A `.xcodeproj` is a directory whose whole content is `project.pbxproj`;
44
+ * without it `xcodebuild` refuses to open the project at all — "missing its
45
+ * project.pbxproj file". A `.xcworkspace` is `contents.xcworkspacedata` in
46
+ * the same way. Anything else ending in those suffixes is a directory with a
47
+ * suggestive name, and offering one is offering something Xcode would reject.
48
+ *
49
+ * `Uwi0/Oakane` is the row that found it. Its `iosApp/` ships two: a tracked
50
+ * `iosApp.xcodeproj` holding nothing but `project.xcworkspace/`, and the real
51
+ * `oakane.xcodeproj` beside it with a 20 217-byte `project.pbxproj`. The husk
52
+ * carries the name the KMM wizard gives, so the conventional name outranked
53
+ * the project that exists — and it supplied BOTH `IOS_PROJECT_PATH` and, via
54
+ * the scheme scan's project-name fallback, `IOS_SCHEME`. The build reached
55
+ * step 9 and died on "Unable to read project 'iosApp.xcodeproj'".
56
+ *
57
+ * This is the iOS twin of the Gradle module scan once treating "a directory
58
+ * holding a file called build.gradle" as a module: wrong in the same
59
+ * direction, and fixed the same way — one reader, used by everyone.
60
+ *
61
+ * The `.pbxproj` is deliberately NOT parsed. Its existence and non-emptiness
62
+ * is the whole question; a shared `.xcscheme` remains the oracle for what a
63
+ * project builds.
64
+ */
65
+ export function isXcodeContainer(path) {
66
+ const manifest = path.endsWith(".xcworkspace")
67
+ ? "contents.xcworkspacedata"
68
+ : path.endsWith(".xcodeproj")
69
+ ? "project.pbxproj"
70
+ : null;
71
+ if (manifest === null)
72
+ return false;
73
+ try {
74
+ return statSync(resolve(path, manifest)).size > 0;
75
+ }
76
+ catch {
77
+ return false;
78
+ }
79
+ }
80
+ /** The entries of `dir` that are real Xcode containers, in `readdir` order. */
81
+ export function xcodeContainersIn(dir) {
82
+ let entries;
83
+ try {
84
+ entries = readdirSync(dir);
85
+ }
86
+ catch {
87
+ return [];
88
+ }
89
+ return entries.filter((e) => (e.endsWith(".xcodeproj") || e.endsWith(".xcworkspace")) &&
90
+ isXcodeContainer(resolve(dir, e)));
91
+ }
36
92
  /** True when this directory holds something an Apple build reads. */
37
93
  function holdsAppleConsumer(dir) {
38
94
  let entries;
@@ -42,7 +98,7 @@ function holdsAppleConsumer(dir) {
42
98
  catch {
43
99
  return false;
44
100
  }
45
- if (entries.some((e) => e.endsWith(".xcodeproj") || e.endsWith(".xcworkspace"))) {
101
+ if (xcodeContainersIn(dir).length > 0) {
46
102
  return true;
47
103
  }
48
104
  if (entries.includes("Podfile"))
@@ -144,15 +200,11 @@ export function detectMobileProjectRoot(dir) {
144
200
  const iosFileIndicators = ["Podfile"];
145
201
  const hasIosFile = iosFileIndicators.some((f) => existsSync(resolve(dir, f)));
146
202
  if (!hasIosFile) {
147
- try {
148
- const entries = readdirSync(dir);
149
- const hasXcodeDir = entries.some((e) => e.endsWith(".xcodeproj") || e.endsWith(".xcworkspace"));
150
- if (hasXcodeDir)
151
- return "ios";
152
- }
153
- catch {
154
- // Unreadable directory — fall through.
155
- }
203
+ // A husk — a directory named `*.xcodeproj` with no `project.pbxproj` —
204
+ // does not make this an iOS project root. Saying `ios` on the strength of
205
+ // one writes a pipeline aimed at something xcodebuild cannot open.
206
+ if (xcodeContainersIn(dir).length > 0)
207
+ return "ios";
156
208
  }
157
209
  else {
158
210
  return "ios";
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=xcode-container.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xcode-container.test.d.ts","sourceRoot":"","sources":["../../../src/shared/xcode-container.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * A `.xcodeproj` with no `project.pbxproj` is not a project.
3
+ *
4
+ * `Uwi0/Oakane` is the row. Its `iosApp/` ships two Xcode projects: a tracked
5
+ * `iosApp.xcodeproj` holding nothing but `project.xcworkspace/`, and the real
6
+ * `oakane.xcodeproj` beside it. The scan chose the husk — `iosApp` is the name
7
+ * the KMM wizard gives, so the conventional name outranked the project that
8
+ * exists — and the build died at step 9 on
9
+ *
10
+ * xcodebuild: error: Unable to read project 'iosApp.xcodeproj' …
11
+ * Reason: … missing its project.pbxproj file.
12
+ *
13
+ * The husk supplied `IOS_SCHEME` too: with no shared schemes anywhere in that
14
+ * repository, `detectSchemes` falls back to each project's own directory name,
15
+ * so the husk contributed the scheme `iosApp` as well as the project path.
16
+ *
17
+ * This is the iOS twin of the Gradle module scan once treating "a directory
18
+ * holding a file called build.gradle" as a module, and it is fixed the same
19
+ * way: one reader, used by everyone.
20
+ */
21
+ import { mkdtempSync, rmSync, mkdirSync, writeFileSync } from "node:fs";
22
+ import { join } from "node:path";
23
+ import { tmpdir } from "node:os";
24
+ import { isXcodeContainer, xcodeContainersIn, detectMobileProjectRoot } from "./detect-project.js";
25
+ import { scanIosProject } from "../commands/ios-scanner.js";
26
+ let root;
27
+ beforeEach(() => {
28
+ root = mkdtempSync(join(tmpdir(), "cibuild-husk-"));
29
+ });
30
+ afterEach(() => {
31
+ rmSync(root, { recursive: true, force: true });
32
+ });
33
+ /** A project Xcode could open. */
34
+ function project(name) {
35
+ mkdirSync(join(root, `${name}.xcodeproj`), { recursive: true });
36
+ writeFileSync(join(root, `${name}.xcodeproj`, "project.pbxproj"), "// !$*UTF8*$!\n");
37
+ }
38
+ /** Oakane's shape: the name, the inner workspace, and no project at all. */
39
+ function husk(name) {
40
+ mkdirSync(join(root, `${name}.xcodeproj`, "project.xcworkspace"), { recursive: true });
41
+ writeFileSync(join(root, `${name}.xcodeproj`, "project.xcworkspace", "contents.xcworkspacedata"), '<?xml version="1.0" encoding="UTF-8"?>\n<Workspace version = "1.0"></Workspace>\n');
42
+ }
43
+ function workspace(name) {
44
+ mkdirSync(join(root, `${name}.xcworkspace`), { recursive: true });
45
+ writeFileSync(join(root, `${name}.xcworkspace`, "contents.xcworkspacedata"), '<?xml version="1.0" encoding="UTF-8"?>\n<Workspace version = "1.0"></Workspace>\n');
46
+ }
47
+ describe("isXcodeContainer", () => {
48
+ test("a project with a project.pbxproj is one", () => {
49
+ project("Real");
50
+ expect(isXcodeContainer(join(root, "Real.xcodeproj"))).toBe(true);
51
+ });
52
+ test("a project with no project.pbxproj is not", () => {
53
+ husk("iosApp");
54
+ expect(isXcodeContainer(join(root, "iosApp.xcodeproj"))).toBe(false);
55
+ });
56
+ test("an empty project.pbxproj is not a project either", () => {
57
+ mkdirSync(join(root, "Empty.xcodeproj"), { recursive: true });
58
+ writeFileSync(join(root, "Empty.xcodeproj", "project.pbxproj"), "");
59
+ expect(isXcodeContainer(join(root, "Empty.xcodeproj"))).toBe(false);
60
+ });
61
+ test("a workspace needs its contents.xcworkspacedata", () => {
62
+ workspace("Real");
63
+ mkdirSync(join(root, "Husk.xcworkspace"), { recursive: true });
64
+ expect(isXcodeContainer(join(root, "Real.xcworkspace"))).toBe(true);
65
+ expect(isXcodeContainer(join(root, "Husk.xcworkspace"))).toBe(false);
66
+ });
67
+ test("a path that is not named like a container is never one", () => {
68
+ mkdirSync(join(root, "Sources"), { recursive: true });
69
+ expect(isXcodeContainer(join(root, "Sources"))).toBe(false);
70
+ expect(isXcodeContainer(join(root, "does-not-exist"))).toBe(false);
71
+ });
72
+ });
73
+ describe("xcodeContainersIn", () => {
74
+ test("keeps the real projects and drops the husks", () => {
75
+ husk("iosApp");
76
+ project("oakane");
77
+ expect(xcodeContainersIn(root)).toEqual(["oakane.xcodeproj"]);
78
+ });
79
+ test("an unreadable directory is empty, not a throw", () => {
80
+ expect(xcodeContainersIn(join(root, "nowhere"))).toEqual([]);
81
+ });
82
+ });
83
+ describe("detectMobileProjectRoot", () => {
84
+ test("a husk alone is not an iOS project root", () => {
85
+ husk("iosApp");
86
+ expect(detectMobileProjectRoot(root)).toBeNull();
87
+ });
88
+ test("a real project beside a husk still is", () => {
89
+ husk("iosApp");
90
+ project("oakane");
91
+ expect(detectMobileProjectRoot(root)).toBe("ios");
92
+ });
93
+ });
94
+ describe("scanIosProject", () => {
95
+ test("Oakane's shape resolves the project that exists, and its scheme", async () => {
96
+ husk("iosApp");
97
+ project("oakane");
98
+ const scan = await scanIosProject(root);
99
+ expect(scan.projectPath).toBe("oakane.xcodeproj");
100
+ // No shared schemes anywhere, so each project falls back to its own name —
101
+ // and only one of them is a project.
102
+ expect(scan.detectedSchemes).toEqual(["oakane"]);
103
+ });
104
+ test("a repository whose only project is a husk resolves nothing", async () => {
105
+ husk("iosApp");
106
+ const scan = await scanIosProject(root);
107
+ expect(scan.projectPath).toBe("");
108
+ expect(scan.detectedSchemes).toEqual([]);
109
+ });
110
+ test("a single valid project is unchanged", async () => {
111
+ project("Contributions");
112
+ const scan = await scanIosProject(root);
113
+ expect(scan.projectPath).toBe("Contributions.xcodeproj");
114
+ expect(scan.detectedSchemes).toEqual(["Contributions"]);
115
+ });
116
+ test("a workspace still outranks a project beside it", async () => {
117
+ project("QiniuSDK");
118
+ workspace("QiniuSDK");
119
+ const scan = await scanIosProject(root);
120
+ expect(scan.projectPath).toBe("QiniuSDK.xcworkspace");
121
+ });
122
+ });
123
+ //# sourceMappingURL=xcode-container.test.js.map
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Which built `.app` belongs to the scheme that was built.
3
+ *
4
+ * A simulator build leaves every application bundle its graph produced under
5
+ * `DerivedData/Build/Products/<configuration>-<platform>/`, and a scheme that
6
+ * builds a watchOS or tvOS companion alongside the app produces two. Taking
7
+ * whichever one a directory scan reaches first is a coin toss, and it lands the
8
+ * wrong way often enough to matter: a project whose scheme builds both an iOS
9
+ * app and a watch companion exported the 588 KB watch bundle as the app under
10
+ * test. The build was green, the artifact manifest was non-empty, and the
11
+ * thing a user downloaded could not be installed on the device they built for.
12
+ * That is worse than delivering nothing, because nothing is visibly wrong and
13
+ * a plausible wrong answer is not.
14
+ *
15
+ * The scheme already knows. A shared `.xcscheme` lists its build entries with a
16
+ * `BuildableName` whose extension IS the product type, and `buildForRunning`
17
+ * separates what the scheme builds from what it merely references — a scheme
18
+ * may list several `.app` entries it does not build, so "mentions an app" is
19
+ * not the question and a check that asked it would pick just as badly.
20
+ *
21
+ * Where the scheme gives no answer this falls back rather than failing. A
22
+ * project with no shared scheme at all is ordinary — plenty of them never
23
+ * commit one — and those builds work. Absence of evidence is not evidence, so
24
+ * the destination's own platform directory decides, and failing to resolve an
25
+ * app is left to the caller's existing guard.
26
+ *
27
+ * The whole resolver runs on the machine that did the build, against the
28
+ * products that build actually produced, so it needs nothing from the step
29
+ * generator but the scheme name and the destination.
30
+ */
31
+ /** A built application bundle, as found under `Build/Products`. */
32
+ export interface BuiltApp {
33
+ /** The `<configuration>-<platform>` directory, or `''` directly under Products. */
34
+ platform: string;
35
+ /** The bundle's own name, e.g. `MyApp.app`. */
36
+ name: string;
37
+ /** Absolute path to the bundle. */
38
+ path: string;
39
+ }
40
+ /**
41
+ * The SDK suffix the Products directory carries for a given destination.
42
+ *
43
+ * `-destination 'generic/platform=iOS Simulator'` builds into
44
+ * `Debug-iphonesimulator`; the watchOS and tvOS spellings are the ones that
45
+ * matter here, because a companion target is exactly what produces the second
46
+ * bundle this resolver exists to skip past.
47
+ */
48
+ export declare function platformSuffixForDestination(destination: string): string;
49
+ /**
50
+ * The application bundles a scheme's build action actually builds.
51
+ *
52
+ * `buildForRunning="NO"` entries are listed and not built. A scheme can carry
53
+ * three `.app` entries that are API-compatibility testers in other containers
54
+ * beside the one framework it really produces, so the attribute is the whole
55
+ * filter rather than a refinement of one.
56
+ *
57
+ * Returns an empty list for a file that cannot be read or carries no build
58
+ * action — no evidence, which the caller must not read as "builds no app".
59
+ */
60
+ export declare function runnableAppProducts(schemeXml: string | null): string[];
61
+ /**
62
+ * The bundle to export, given everything that was built and what the scheme
63
+ * says it builds.
64
+ *
65
+ * In order: the scheme's own product on the destination's platform, the
66
+ * scheme's own product anywhere, anything on the destination's platform,
67
+ * anything at all. The last two are the no-shared-scheme path, and they are
68
+ * what keeps a project that never committed a scheme building exactly as it
69
+ * did before.
70
+ */
71
+ export declare function chooseAppProduct(apps: BuiltApp[], schemeProducts: string[], destination: string): BuiltApp | null;
72
+ /**
73
+ * The resolver as it runs on the build machine: dependency-free CommonJS,
74
+ * written to a temp file and invoked with
75
+ * `node <file> <productsDir> <projectPath> <scheme> <destination>`.
76
+ *
77
+ * It prints the chosen bundle's path and nothing else, and exits non-zero with
78
+ * no output when it cannot choose — which is the signal for the caller's
79
+ * existing scan to take over, so a machine without a usable node is no worse
80
+ * off than before this existed.
81
+ *
82
+ * Kept as source text rather than bundled because the step ships a shell
83
+ * script, not a module graph. The three functions above are the same rules in
84
+ * testable form, and `xcode-app-product.test.ts` holds them to each other.
85
+ *
86
+ * Must contain no backtick and no dollar-brace: it is emitted into a bash
87
+ * heredoc, and it is a TypeScript template literal on the way there.
88
+ */
89
+ export declare const APP_PRODUCT_RESOLVER_SOURCE: string;
90
+ //# sourceMappingURL=xcode-app-product.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xcode-app-product.d.ts","sourceRoot":"","sources":["../../../../src/yaml/steps/xcode-app-product.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,mEAAmE;AACnE,MAAM,WAAW,QAAQ;IACvB,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAMxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,EAAE,CAatE;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,QAAQ,EAAE,EAChB,cAAc,EAAE,MAAM,EAAE,EACxB,WAAW,EAAE,MAAM,GAClB,QAAQ,GAAG,IAAI,CAOjB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,2BAA2B,EAAE,MAqIzC,CAAC"}