rork-xcode 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -100,7 +100,7 @@ const text = project.build();
100
100
 
101
101
  ### Targets and build settings
102
102
 
103
- `getBuildSetting` resolves hierarchically the way Xcode does: the target's default configuration first, then the project-level configuration. Writes go to every configuration of the target, so Debug and Release stay consistent.
103
+ `getBuildSetting` resolves hierarchically the way Xcode does, reading the target's default configuration first and the project-level configuration below it. Writes go to every configuration of the target, so Debug and Release stay consistent.
104
104
 
105
105
  ```ts
106
106
  const app = project.findMainAppTarget("ios"); // "macos" | "tvos" | "watchos" | "visionos"
@@ -114,6 +114,13 @@ for (const target of project.nativeTargets()) {
114
114
  }
115
115
  ```
116
116
 
117
+ `resolveBuildSetting` reads the same layers and expands the `$(NAME)` and `${NAME}` references in the value. Referenced settings resolve through the chain, `$(inherited)` continues from the next layer down, and `$(TARGET_NAME)` falls back to the target's name, so the template's `PRODUCT_NAME = "$(TARGET_NAME)"` resolves without any setup. References the document cannot answer (build-system paths like `$(BUILT_PRODUCTS_DIR)`) stay verbatim unless a caller-supplied lookup answers them, so nothing is invented.
118
+
119
+ ```ts
120
+ app?.resolveBuildSetting("PRODUCT_NAME"); // "DemoApp", from PRODUCT_NAME = "$(TARGET_NAME)"
121
+ app?.resolveBuildSetting("WIDGET_ID"); // "com.example.demo.widget", through PRODUCT_BUNDLE_IDENTIFIER
122
+ ```
123
+
117
124
  `project.targets()` returns every target kind. Aggregate targets (`PBXAggregateTarget`) and legacy external-build-tool targets (`PBXLegacyTarget`) share the full target surface, from configurations and build settings to phases and dependency wiring.
118
125
 
119
126
  ```ts
@@ -314,6 +321,24 @@ project.registerXcconfig(reference, Xcconfig.parse(text));
314
321
  app.getBuildSetting("SDKROOT"); // now sees values the xcconfig defines
315
322
  ```
316
323
 
324
+ ## Build-setting references
325
+
326
+ Values reference other build settings as `$(NAME)` and `${NAME}`, in the pbxproj, in xcconfig files, and in Info.plist templates. The syntax is Xcode's own, down to the `:` operators, and Xcode's app templates write values in exactly this shape, for example `PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.$(PRODUCT_NAME:rfc1034identifier)`. `expandBuildSettingReferences` evaluates the syntax through a caller-supplied lookup, so the same code serves all three formats. Substituted text expands recursively, names may themselves contain references (`$(SETTING_$(VARIANT))`), cycles stay finite, and a reference the lookup cannot answer stays verbatim, so partial resolution loses no information.
327
+
328
+ ```ts
329
+ import { expandBuildSettingReferences } from "rork-xcode";
330
+
331
+ // A value as found in a project file. The references and their operators
332
+ // are part of the document, so the expander takes them from the text
333
+ // rather than from options.
334
+ const found = "com.example.$(PRODUCT_NAME:rfc1034identifier)";
335
+
336
+ expandBuildSettingReferences(found, (name) => (name === "PRODUCT_NAME" ? "My App" : undefined));
337
+ // "com.example.My-App"
338
+ ```
339
+
340
+ The `:` operators are honored for `lower`, `upper`, `rfc1034identifier` (the mapping into RFC 1034 host-name characters that bundle identifiers need), `c99extidentifier`, and `default=`. A reference carrying any other operator stays verbatim rather than expanding to a wrongly transformed value. The model composes the expander with settings resolution as `target.resolveBuildSetting(key)`, described under [Targets and build settings](#targets-and-build-settings).
341
+
317
342
  ## Performance
318
343
 
319
344
  `rork-xcode` is measured against the pbxproj parsers on npm, [`@bacons/xcode`](https://www.npmjs.com/package/@bacons/xcode) (its `/json` parse/build entry point) and [`xcode`](https://www.npmjs.com/package/xcode) (the long-standing package used by native build tooling), on three documents: two real Xcode-written projects from the test suite and a deterministically generated five-target app with 800 source files. It is the fastest at both operations on every document, with zero dependencies.
package/dist/index.d.ts CHANGED
@@ -207,6 +207,73 @@ declare class PbxprojBuildError extends Error {
207
207
  constructor(message: string, path: string);
208
208
  }
209
209
  //#endregion
210
+ //#region src/expansion.d.ts
211
+ /**
212
+ * Expansion of `$(NAME)` and `${NAME}` build-setting references.
213
+ *
214
+ * Values in the pbxproj, in xcconfig files, and in Info.plist templates
215
+ * reference other build settings, and every consumer that needs the
216
+ * resolved string ends up re-implementing the substitution informally.
217
+ * The expander here is a pure function over a caller-supplied lookup, so
218
+ * the same code serves all three formats. The model composes it with
219
+ * settings resolution in `Target.resolveBuildSetting`.
220
+ *
221
+ * @module
222
+ */
223
+ /**
224
+ * The value a reference expands to, or `undefined` to leave the
225
+ * reference in place. Returning the empty string expands to nothing,
226
+ * which is how Xcode itself treats settings that exist but are empty.
227
+ */
228
+ type BuildSettingLookup = (name: string) => string | undefined;
229
+ interface ExpandBuildSettingOptions {
230
+ /**
231
+ * Whether lookup answers are expanded again, which is the default and
232
+ * suits lookups reading raw stored values. A lookup that resolves
233
+ * references itself, like the model's layered resolution, turns this
234
+ * off so text it deliberately left verbatim is not reinterpreted in
235
+ * the outer value's context.
236
+ */
237
+ expandLookupValues?: boolean;
238
+ }
239
+ /**
240
+ * Expands every `$(NAME)` and `${NAME}` reference in a value through the
241
+ * lookup. Substituted text is expanded again, so references are followed
242
+ * through chains of values, and reference names may themselves contain
243
+ * references (`$(SETTING_$(VARIANT))`), which expand innermost first.
244
+ *
245
+ * A lookup answer of `undefined` leaves the reference in the output
246
+ * verbatim, so partial resolution loses no information. A reference
247
+ * whose expansion would recurse into itself also stays verbatim, which
248
+ * keeps cyclic definitions finite. Xcode's `:` operators are honored for
249
+ * the forms below, and a reference carrying any other operator stays
250
+ * verbatim rather than expanding to a wrongly transformed value.
251
+ *
252
+ * The supported operators are `lower` and `upper` for case mapping,
253
+ * `rfc1034identifier` and `c99extidentifier` for the identifier
254
+ * mappings bundle identifiers and product module names use, and
255
+ * `default=value` for substituting a fallback when the setting resolves
256
+ * empty or is not known to the lookup.
257
+ */
258
+ declare function expandBuildSettingReferences(value: string, lookup: BuildSettingLookup, options?: ExpandBuildSettingOptions): string;
259
+ /**
260
+ * The transforming operators the expander supports, keyed by the name
261
+ * they are written with. `default=` is not listed because it carries an
262
+ * argument and substitutes rather than transforms, so the reference
263
+ * expansion handles it structurally.
264
+ */
265
+ declare const OPERATOR_TRANSFORMS: {
266
+ c99extidentifier: (value: string) => string;
267
+ lower: (value: string) => string;
268
+ rfc1034identifier: (value: string) => string;
269
+ upper: (value: string) => string;
270
+ };
271
+ /**
272
+ * A transforming operator name honored in `$(NAME:operator)` references,
273
+ * alongside the structural `default=`.
274
+ */
275
+ type BuildSettingOperator = keyof typeof OPERATOR_TRANSFORMS;
276
+ //#endregion
210
277
  //#region src/model/isa.d.ts
211
278
  /**
212
279
  * Names and well-known values of the pbxproj object vocabulary.
@@ -593,6 +660,16 @@ interface BuildStyleProperties extends PbxprojObject {
593
660
  }
594
661
  //#endregion
595
662
  //#region src/model/target.d.ts
663
+ interface ResolveBuildSettingOptions {
664
+ /**
665
+ * Answers references the document itself cannot, for example
666
+ * `$(BUILT_PRODUCTS_DIR)` when the caller knows the build layout. The
667
+ * lookup is consulted after the setting layers and before the built-in
668
+ * `$(TARGET_NAME)` fallback, and a reference it leaves unanswered
669
+ * stays verbatim in the result.
670
+ */
671
+ lookup?: BuildSettingLookup;
672
+ }
596
673
  /**
597
674
  * The behavior every target kind shares. A target of any kind carries
598
675
  * build configurations and settings, build phases, and dependencies, and
@@ -637,6 +714,22 @@ declare class Target<Properties extends TargetProperties = TargetProperties> ext
637
714
  * reads as `undefined`.
638
715
  */
639
716
  getBuildSetting(key: string): string | undefined;
717
+ /**
718
+ * Reads a build setting like {@link getBuildSetting} and expands the
719
+ * `$(NAME)` and `${NAME}` references in it. Referenced settings resolve
720
+ * through the same layering, `$(inherited)` and a setting referencing
721
+ * itself continue from the next layer down the way Xcode composes
722
+ * values, and `$(TARGET_NAME)` falls back to the target's name, so the
723
+ * common `PRODUCT_NAME = "$(TARGET_NAME)"` resolves without any caller
724
+ * setup.
725
+ *
726
+ * References the model cannot resolve (build-system paths like
727
+ * `$(BUILT_PRODUCTS_DIR)`, environment values) stay in the result
728
+ * verbatim unless the caller's lookup answers them, so no information
729
+ * is invented. See {@link expandBuildSettingReferences} for the
730
+ * operator forms honored during expansion.
731
+ */
732
+ resolveBuildSetting(key: string, options?: ResolveBuildSettingOptions): string | undefined;
640
733
  /**
641
734
  * Writes a build setting on every configuration of the target, so Debug
642
735
  * and Release stay consistent.
@@ -2296,4 +2389,4 @@ declare function buildXcconfig(document: XcconfigDocument): string;
2296
2389
  */
2297
2390
  declare function parseXcconfig(source: string): XcconfigDocument;
2298
2391
  //#endregion
2299
- export { type AddNativeTargetOptions, AggregateTarget, type ApplePlatform, AppleScriptBuildPhase, BuildConfiguration, type BuildConfigurationProperties, BuildFile, BuildFileExceptionSet, type BuildFileProperties, BuildPhase, type BuildPhaseIsa, BuildPhaseMembershipExceptionSet, type BuildPhaseMembershipExceptionSetProperties, type BuildPhaseOf, type BuildPhaseProperties, BuildRule, type BuildRuleProperties, type BuildSettings, BuildStyle, type BuildStyleProperties, BuildableReference, ConfigurationList, type ConfigurationListProperties, ContainerItemProxy, type ContainerItemProxyProperties, CopyFilesBuildPhase, type CopyFilesBuildPhaseProperties, CopyFilesDestination, type CreateXcschemeOptions, ExceptionSet, type ExceptionSetProperties, FileReference, type FileReferenceProperties, FrameworksBuildPhase, Group, type GroupProperties, HeadersBuildPhase, Isa, type IsaValue, LegacyTarget, type LegacyTargetProperties, LocalSwiftPackageReference, type LocalSwiftPackageReferenceProperties, NativeTarget, type NativeTargetProperties, type PbxprojArray, PbxprojBuildError, type PbxprojErrorPosition, type PbxprojObject, PbxprojParseError, type PbxprojValue, ProductType, type ProjectIssue, type ProjectIssueKind, ReferenceProxy, type ReferenceProxyProperties, RemoteSwiftPackageReference, type RemoteSwiftPackageReferenceProperties, ResourcesBuildPhase, RezBuildPhase, RootProject, type RootProjectProperties, ShellScriptBuildPhase, type ShellScriptBuildPhaseProperties, SourcesBuildPhase, SwiftPackageProductDependency, type SwiftPackageProductDependencyProperties, SwiftPackageReference, type SwiftPackageReferenceProperties, SyncRootGroup, type SyncRootGroupProperties, Target, TargetDependency, type TargetDependencyProperties, type TargetProperties, VariantGroup, VersionGroup, type VersionGroupProperties, type ViewByIsa, type ViewOf, Xcconfig, type XcconfigAssignment, type XcconfigBlank, type XcconfigComment, type XcconfigCondition, type XcconfigDocument, type XcconfigInclude, type XcconfigIncludeResolver, XcconfigParseError, type XcconfigSettingsOptions, type XcconfigStatement, XcodeModelError, XcodeObject, XcodeProject, Xcscheme, XcschemeBuildError, type XcschemeComment, type XcschemeDocument, type XcschemeElement, type XcschemeNode, XcschemeParseError, buildPbxproj, buildXcconfig, buildXcscheme, createXcscheme, generateObjectId, isXcschemeElement, parseApplePlatform, parsePbxproj, parseXcconfig, parseXcscheme, xcschemeElements };
2392
+ export { type AddNativeTargetOptions, AggregateTarget, type ApplePlatform, AppleScriptBuildPhase, BuildConfiguration, type BuildConfigurationProperties, BuildFile, BuildFileExceptionSet, type BuildFileProperties, BuildPhase, type BuildPhaseIsa, BuildPhaseMembershipExceptionSet, type BuildPhaseMembershipExceptionSetProperties, type BuildPhaseOf, type BuildPhaseProperties, BuildRule, type BuildRuleProperties, type BuildSettingLookup, type BuildSettingOperator, type BuildSettings, BuildStyle, type BuildStyleProperties, BuildableReference, ConfigurationList, type ConfigurationListProperties, ContainerItemProxy, type ContainerItemProxyProperties, CopyFilesBuildPhase, type CopyFilesBuildPhaseProperties, CopyFilesDestination, type CreateXcschemeOptions, ExceptionSet, type ExceptionSetProperties, type ExpandBuildSettingOptions, FileReference, type FileReferenceProperties, FrameworksBuildPhase, Group, type GroupProperties, HeadersBuildPhase, Isa, type IsaValue, LegacyTarget, type LegacyTargetProperties, LocalSwiftPackageReference, type LocalSwiftPackageReferenceProperties, NativeTarget, type NativeTargetProperties, type PbxprojArray, PbxprojBuildError, type PbxprojErrorPosition, type PbxprojObject, PbxprojParseError, type PbxprojValue, ProductType, type ProjectIssue, type ProjectIssueKind, ReferenceProxy, type ReferenceProxyProperties, RemoteSwiftPackageReference, type RemoteSwiftPackageReferenceProperties, type ResolveBuildSettingOptions, ResourcesBuildPhase, RezBuildPhase, RootProject, type RootProjectProperties, ShellScriptBuildPhase, type ShellScriptBuildPhaseProperties, SourcesBuildPhase, SwiftPackageProductDependency, type SwiftPackageProductDependencyProperties, SwiftPackageReference, type SwiftPackageReferenceProperties, SyncRootGroup, type SyncRootGroupProperties, Target, TargetDependency, type TargetDependencyProperties, type TargetProperties, VariantGroup, VersionGroup, type VersionGroupProperties, type ViewByIsa, type ViewOf, Xcconfig, type XcconfigAssignment, type XcconfigBlank, type XcconfigComment, type XcconfigCondition, type XcconfigDocument, type XcconfigInclude, type XcconfigIncludeResolver, XcconfigParseError, type XcconfigSettingsOptions, type XcconfigStatement, XcodeModelError, XcodeObject, XcodeProject, Xcscheme, XcschemeBuildError, type XcschemeComment, type XcschemeDocument, type XcschemeElement, type XcschemeNode, XcschemeParseError, buildPbxproj, buildXcconfig, buildXcscheme, createXcscheme, expandBuildSettingReferences, generateObjectId, isXcschemeElement, parseApplePlatform, parsePbxproj, parseXcconfig, parseXcscheme, xcschemeElements };
package/dist/index.js CHANGED
@@ -815,6 +815,154 @@ function buildPbxproj(root) {
815
815
  return new Writer(root).toString();
816
816
  }
817
817
  //#endregion
818
+ //#region src/expansion.ts
819
+ /**
820
+ * Expands every `$(NAME)` and `${NAME}` reference in a value through the
821
+ * lookup. Substituted text is expanded again, so references are followed
822
+ * through chains of values, and reference names may themselves contain
823
+ * references (`$(SETTING_$(VARIANT))`), which expand innermost first.
824
+ *
825
+ * A lookup answer of `undefined` leaves the reference in the output
826
+ * verbatim, so partial resolution loses no information. A reference
827
+ * whose expansion would recurse into itself also stays verbatim, which
828
+ * keeps cyclic definitions finite. Xcode's `:` operators are honored for
829
+ * the forms below, and a reference carrying any other operator stays
830
+ * verbatim rather than expanding to a wrongly transformed value.
831
+ *
832
+ * The supported operators are `lower` and `upper` for case mapping,
833
+ * `rfc1034identifier` and `c99extidentifier` for the identifier
834
+ * mappings bundle identifiers and product module names use, and
835
+ * `default=value` for substituting a fallback when the setting resolves
836
+ * empty or is not known to the lookup.
837
+ */
838
+ function expandBuildSettingReferences(value, lookup, options) {
839
+ return expand(value, lookup, options?.expandLookupValues !== false, /* @__PURE__ */ new Set());
840
+ }
841
+ /** The UTF-16 code unit of `$`, which starts every reference. */
842
+ const CODE_DOLLAR = 36;
843
+ /**
844
+ * One expansion pass over a value. Active names carry the references
845
+ * currently being expanded up the call stack, so a cycle is detected the
846
+ * moment a name would expand inside its own expansion.
847
+ */
848
+ function expand(value, lookup, expandLookupValues, active) {
849
+ if (!value.includes("$")) return value;
850
+ let out = "";
851
+ let index = 0;
852
+ while (index < value.length) {
853
+ const open = value.charCodeAt(index) === CODE_DOLLAR ? value[index + 1] : void 0;
854
+ if (open !== "(" && open !== "{") {
855
+ out += value[index];
856
+ index++;
857
+ continue;
858
+ }
859
+ const end = findClosingDelimiter(value, index + 2, open === "(" ? ")" : "}");
860
+ if (end === -1) {
861
+ out += value.slice(index);
862
+ break;
863
+ }
864
+ const reference = value.slice(index, end + 1);
865
+ const inner = expand(value.slice(index + 2, end), lookup, expandLookupValues, active);
866
+ out += expandReference(reference, inner, lookup, expandLookupValues, active);
867
+ index = end + 1;
868
+ }
869
+ return out;
870
+ }
871
+ /**
872
+ * Finds the index of the closing delimiter matching an opener at
873
+ * `start - 1`, honoring nested delimiters of the same kind, or -1 when
874
+ * the reference is unterminated.
875
+ */
876
+ function findClosingDelimiter(value, start, close) {
877
+ const open = close === ")" ? "(" : "{";
878
+ let depth = 0;
879
+ for (let i = start; i < value.length; i++) {
880
+ const ch = value[i];
881
+ if (ch === open) depth++;
882
+ else if (ch === close) {
883
+ if (depth === 0) return i;
884
+ depth--;
885
+ }
886
+ }
887
+ return -1;
888
+ }
889
+ /**
890
+ * Expands one reference whose name and operators have already had their
891
+ * own references resolved. Returns the original reference text whenever
892
+ * the expansion cannot honestly produce a value.
893
+ */
894
+ function expandReference(reference, inner, lookup, expandLookupValues, active) {
895
+ const colon = inner.indexOf(":");
896
+ const name = colon === -1 ? inner : inner.slice(0, colon);
897
+ if (active.has(name)) return reference;
898
+ const raw = lookup(name);
899
+ const nested = new Set(active);
900
+ nested.add(name);
901
+ let value = raw;
902
+ if (raw != null && expandLookupValues) value = expand(raw, lookup, expandLookupValues, nested);
903
+ if (colon !== -1) {
904
+ for (const operator of splitOperators(inner.slice(colon + 1))) if (operator.startsWith("default=")) {
905
+ if (value == null || value === "") value = operator.slice(8);
906
+ } else if (value != null) {
907
+ const applied = applyOperator(operator, value);
908
+ if (applied == null) return reference;
909
+ value = applied;
910
+ } else if (applyOperator(operator, "") == null) return reference;
911
+ }
912
+ return value ?? reference;
913
+ }
914
+ /**
915
+ * Splits an operator chain at colons, keeping a `default=` value intact
916
+ * even when it contains colons of its own, the way Xcode consumes the
917
+ * rest of the reference as the default.
918
+ */
919
+ function splitOperators(operators) {
920
+ const parts = [];
921
+ let rest = operators;
922
+ while (rest.length > 0) {
923
+ if (rest.startsWith("default=")) {
924
+ parts.push(rest);
925
+ break;
926
+ }
927
+ const colon = rest.indexOf(":");
928
+ if (colon === -1) {
929
+ parts.push(rest);
930
+ break;
931
+ }
932
+ parts.push(rest.slice(0, colon));
933
+ rest = rest.slice(colon + 1);
934
+ }
935
+ return parts;
936
+ }
937
+ /**
938
+ * The transforming operators the expander supports, keyed by the name
939
+ * they are written with. `default=` is not listed because it carries an
940
+ * argument and substitutes rather than transforms, so the reference
941
+ * expansion handles it structurally.
942
+ */
943
+ const OPERATOR_TRANSFORMS = {
944
+ c99extidentifier: (value) => value.replaceAll(/[^A-Za-z0-9_]/gu, "_"),
945
+ lower: (value) => value.toLowerCase(),
946
+ rfc1034identifier: (value) => value.replaceAll(/[^A-Za-z0-9-]/gu, "-"),
947
+ upper: (value) => value.toUpperCase()
948
+ };
949
+ /**
950
+ * Whether a parsed operator names one of the supported transforms. The
951
+ * check is an own-property test, so document text like `toString` cannot
952
+ * reach the table's prototype.
953
+ */
954
+ function isBuildSettingOperator(operator) {
955
+ return Object.hasOwn(OPERATOR_TRANSFORMS, operator);
956
+ }
957
+ /**
958
+ * Applies one operator to a resolved value, or returns `undefined` for
959
+ * operators outside {@link BuildSettingOperator}, which the caller turns
960
+ * into a verbatim reference.
961
+ */
962
+ function applyOperator(operator, value) {
963
+ return isBuildSettingOperator(operator) ? OPERATOR_TRANSFORMS[operator](value) : void 0;
964
+ }
965
+ //#endregion
818
966
  //#region src/model/isa.ts
819
967
  /**
820
968
  * Names and well-known values of the pbxproj object vocabulary.
@@ -3034,6 +3182,48 @@ var Target = class extends XcodeObject {
3034
3182
  return (projectConfiguration == null ? void 0 : this.project.xcconfigSettingsOf(projectConfiguration))?.[key];
3035
3183
  }
3036
3184
  /**
3185
+ * Reads a build setting like {@link getBuildSetting} and expands the
3186
+ * `$(NAME)` and `${NAME}` references in it. Referenced settings resolve
3187
+ * through the same layering, `$(inherited)` and a setting referencing
3188
+ * itself continue from the next layer down the way Xcode composes
3189
+ * values, and `$(TARGET_NAME)` falls back to the target's name, so the
3190
+ * common `PRODUCT_NAME = "$(TARGET_NAME)"` resolves without any caller
3191
+ * setup.
3192
+ *
3193
+ * References the model cannot resolve (build-system paths like
3194
+ * `$(BUILT_PRODUCTS_DIR)`, environment values) stay in the result
3195
+ * verbatim unless the caller's lookup answers them, so no information
3196
+ * is invented. See {@link expandBuildSettingReferences} for the
3197
+ * operator forms honored during expansion.
3198
+ */
3199
+ resolveBuildSetting(key, options) {
3200
+ const targetConfiguration = defaultConfigurationOf(this.project, this.getString("buildConfigurationList"));
3201
+ const projectConfiguration = defaultConfigurationOf(this.project, this.project.rootProject.getString("buildConfigurationList"));
3202
+ const layers = [
3203
+ asDictionary(targetConfiguration?.properties["buildSettings"]),
3204
+ targetConfiguration == null ? void 0 : this.project.xcconfigSettingsOf(targetConfiguration),
3205
+ asDictionary(projectConfiguration?.properties["buildSettings"]),
3206
+ projectConfiguration == null ? void 0 : this.project.xcconfigSettingsOf(projectConfiguration)
3207
+ ];
3208
+ const resolve = (name, fromLayer, active) => {
3209
+ const guard = `${fromLayer}:${name}`;
3210
+ if (active.has(guard)) return;
3211
+ const nested = new Set(active);
3212
+ nested.add(guard);
3213
+ for (let layer = fromLayer; layer < layers.length; layer++) {
3214
+ const settings = layers[layer];
3215
+ if (settings == null || !(name in settings)) continue;
3216
+ const value = asString(settings[name]);
3217
+ if (value == null) return;
3218
+ return expandBuildSettingReferences(value, (reference) => {
3219
+ if (reference === "inherited" || reference === name) return resolve(name, layer + 1, nested) ?? "";
3220
+ return resolve(reference, 0, nested) ?? options?.lookup?.(reference) ?? builtinSetting(this, reference);
3221
+ }, { expandLookupValues: false });
3222
+ }
3223
+ };
3224
+ return resolve(key, 0, /* @__PURE__ */ new Set());
3225
+ }
3226
+ /**
3037
3227
  * Writes a build setting on every configuration of the target, so Debug
3038
3228
  * and Release stay consistent.
3039
3229
  */
@@ -3147,6 +3337,15 @@ var Target = class extends XcodeObject {
3147
3337
  }
3148
3338
  };
3149
3339
  /**
3340
+ * The settings the build system defines from the target itself rather
3341
+ * than from the document. `TARGET_NAME` is the one programmatic reads
3342
+ * meet constantly, through the template's `PRODUCT_NAME` of
3343
+ * `$(TARGET_NAME)`.
3344
+ */
3345
+ function builtinSetting(target, name) {
3346
+ return name === "TARGET_NAME" ? target.name : void 0;
3347
+ }
3348
+ /**
3150
3349
  * A `PBXNativeTarget` is a product the project compiles and packages
3151
3350
  * itself, such as an application or an app extension.
3152
3351
  */
@@ -5095,4 +5294,4 @@ var Xcconfig = class Xcconfig {
5095
5294
  }
5096
5295
  };
5097
5296
  //#endregion
5098
- export { AggregateTarget, AppleScriptBuildPhase, BuildConfiguration, BuildFile, BuildFileExceptionSet, BuildPhase, BuildPhaseMembershipExceptionSet, BuildRule, BuildStyle, BuildableReference, ConfigurationList, ContainerItemProxy, CopyFilesBuildPhase, CopyFilesDestination, ExceptionSet, FileReference, FrameworksBuildPhase, Group, HeadersBuildPhase, Isa, LegacyTarget, LocalSwiftPackageReference, NativeTarget, PbxprojBuildError, PbxprojParseError, ProductType, ReferenceProxy, RemoteSwiftPackageReference, ResourcesBuildPhase, RezBuildPhase, RootProject, ShellScriptBuildPhase, SourcesBuildPhase, SwiftPackageProductDependency, SwiftPackageReference, SyncRootGroup, Target, TargetDependency, VariantGroup, VersionGroup, Xcconfig, XcconfigParseError, XcodeModelError, XcodeObject, XcodeProject, Xcscheme, XcschemeBuildError, XcschemeParseError, buildPbxproj, buildXcconfig, buildXcscheme, createXcscheme, generateObjectId, isXcschemeElement, parseApplePlatform, parsePbxproj, parseXcconfig, parseXcscheme, xcschemeElements };
5297
+ export { AggregateTarget, AppleScriptBuildPhase, BuildConfiguration, BuildFile, BuildFileExceptionSet, BuildPhase, BuildPhaseMembershipExceptionSet, BuildRule, BuildStyle, BuildableReference, ConfigurationList, ContainerItemProxy, CopyFilesBuildPhase, CopyFilesDestination, ExceptionSet, FileReference, FrameworksBuildPhase, Group, HeadersBuildPhase, Isa, LegacyTarget, LocalSwiftPackageReference, NativeTarget, PbxprojBuildError, PbxprojParseError, ProductType, ReferenceProxy, RemoteSwiftPackageReference, ResourcesBuildPhase, RezBuildPhase, RootProject, ShellScriptBuildPhase, SourcesBuildPhase, SwiftPackageProductDependency, SwiftPackageReference, SyncRootGroup, Target, TargetDependency, VariantGroup, VersionGroup, Xcconfig, XcconfigParseError, XcodeModelError, XcodeObject, XcodeProject, Xcscheme, XcschemeBuildError, XcschemeParseError, buildPbxproj, buildXcconfig, buildXcscheme, createXcscheme, expandBuildSettingReferences, generateObjectId, isXcschemeElement, parseApplePlatform, parsePbxproj, parseXcconfig, parseXcscheme, xcschemeElements };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rork-xcode",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Zero-dependency Xcode project (pbxproj) and scheme (xcscheme) parser, builder, and object model that runs identically in every JavaScript runtime",
5
5
  "keywords": [
6
6
  "apple",