diff --git a/lib/bootstrap.ts b/lib/bootstrap.ts index 3281d84930..0eb20383b9 100644 --- a/lib/bootstrap.ts +++ b/lib/bootstrap.ts @@ -60,6 +60,7 @@ injector.require("iOSProvisionService", "./services/ios-provision-service"); injector.require("xcconfigService", "./services/xcconfig-service"); injector.require("iOSSigningService", "./services/ios/ios-signing-service"); injector.require("spmService", "./services/ios/spm-service"); +injector.require("spmPbxprojService", "./services/ios/spm-pbxproj-service"); injector.require( "xcodebuildArgsService", "./services/ios/xcodebuild-args-service", diff --git a/lib/definitions/ios.d.ts b/lib/definitions/ios.d.ts index 43533d8d76..60c3430bbb 100644 --- a/lib/definitions/ios.d.ts +++ b/lib/definitions/ios.d.ts @@ -41,7 +41,42 @@ declare global { ): Promise; } - type IosSPMPackage = IosSPMPackageDefinition & { targets?: string[] }; + interface IosSPMPackageBase { + name: string; + /** Swift product names to link from the package. */ + libs: string[]; + /** + * Optional: if the project has additional targets (widgets, watch apps, + * extensions...) list their names here to link the package with them too. + */ + targets?: string[]; + } + + /** A package resolved from a git remote at a version, range, branch or revision. */ + interface IosRemoteSPMPackage extends IosSPMPackageBase { + repositoryURL: string; + version: string; + } + + /** A package resolved from a directory on disk. */ + interface IosLocalSPMPackage extends IosSPMPackageBase { + path: string; + } + + type IosSPMPackage = IosRemoteSPMPackage | IosLocalSPMPackage; + + /** One package linked into one target of the Xcode project. */ + interface IosSPMPackageAssignment { + targetName: string; + package: IosSPMPackage; + } + + interface ISPMPbxprojService { + addPackages( + projectRoot: string, + assignments: IosSPMPackageAssignment[], + ): boolean; + } interface ISPMService { applySPMPackages( diff --git a/lib/services/ios-watch-app-service.ts b/lib/services/ios-watch-app-service.ts index 83fcdf610e..e6112d4cf5 100644 --- a/lib/services/ios-watch-app-service.ts +++ b/lib/services/ios-watch-app-service.ts @@ -19,7 +19,6 @@ import { import { IPlatformData } from "../definitions/platform"; import { IFileSystem } from "../common/declarations"; import { injector } from "../common/yok"; -import { MobileProject } from "@nstudio/trapezedev-project"; import { Minimatch } from "minimatch"; const sourceExtensions = [ @@ -77,6 +76,7 @@ export class IOSWatchAppService implements IIOSWatchAppService { protected $xcode: IXcode, private $iOSNativeTargetService: IIOSNativeTargetService, private $logger: ILogger, + private $spmPbxprojService: ISPMPbxprojService, ) {} private addResourceFile( @@ -1416,20 +1416,8 @@ export class IOSWatchAppService implements IIOSWatchAppService { `Applying ${watchSPMPackages.length} SPM package(s) to targets:${targetNames}`, ); - const project = new MobileProject(platformData.projectRoot, { - ios: { - path: ".", - }, - enableAndroid: false, - }); - await project.load(); - - if (!project.ios) { - this.$logger.debug("No iOS project found via trapeze"); - return; - } - // Add SPM packages to each watch target + const assignments: IosSPMPackageAssignment[] = []; for (const pkg of watchSPMPackages) { if ("path" in pkg) { pkg.path = path.resolve(basedir, pkg.path); @@ -1439,11 +1427,22 @@ export class IOSWatchAppService implements IIOSWatchAppService { `Adding SPM package ${JSON.stringify(pkg)} to targets ${targetNames}`, ); for (const targetName of targetNames) { - project.ios.addSPMPackage(targetName, pkg); + assignments.push({ targetName, package: pkg }); } } - await project.commit(); + if ( + !this.$spmPbxprojService.addPackages( + platformData.projectRoot, + assignments, + ) + ) { + this.$logger.debug( + `No SPM packages were applied to targets ${targetNames}`, + ); + return; + } + this.$logger.debug( `Successfully applied SPM packages to targets ${targetNames}`, ); diff --git a/lib/services/ios/spm-pbxproj-service.ts b/lib/services/ios/spm-pbxproj-service.ts new file mode 100644 index 0000000000..0ab41f868c --- /dev/null +++ b/lib/services/ios/spm-pbxproj-service.ts @@ -0,0 +1,415 @@ +import * as path from "path"; +import * as semver from "semver"; +import { injector } from "../../common/yok"; +import { IFileSystem } from "../../common/declarations"; + +/** + * Writes Swift Package references directly into an Xcode project's pbxproj. + * + * Adding a Swift package to a target means touching four places in the + * pbxproj, which is why this is not a one-liner: + * + * 1. an `XCRemoteSwiftPackageReference` / `XCLocalSwiftPackageReference` + * object describing *where* the package comes from, listed in the + * project's `packageReferences`; + * 2. an `XCSwiftPackageProductDependency` per linked product (lib); + * 3. a `PBXBuildFile` wrapping each product dependency; + * 4. an entry in the target's Frameworks build phase, plus the target's + * `packageProductDependencies`. + * + * Every entry is keyed by its pbxproj comment (e.g. `XCRemoteSwiftPackageReference + * "Auth0"`), and an existing entry is updated in place rather than duplicated — + * so applying the same set of packages repeatedly (which the CLI does on every + * prepare) is idempotent and doesn't grow the pbxproj. + */ +export class SPMPbxprojService implements ISPMPbxprojService { + constructor( + private $fs: IFileSystem, + private $logger: ILogger, + private $xcode: IXcode, + ) {} + + /** + * Adds each package to its target in a single parse/write cycle. + * + * Returns true when the pbxproj was written. Missing targets are warned + * about and skipped rather than failing the whole batch — a package meant + * for a widget target shouldn't stop the app's own packages from applying. + */ + public addPackages( + projectRoot: string, + assignments: IosSPMPackageAssignment[], + ): boolean { + if (!assignments.length) { + return false; + } + + const pbxProjPath = this.findPbxProjPath(projectRoot); + if (!pbxProjPath) { + this.$logger.trace( + `SPM: no Xcode project found under ${projectRoot}; skipping.`, + ); + return false; + } + + const project = new this.$xcode.project(pbxProjPath); + project.parseSync(); + + let added = false; + for (const { targetName, package: pkg } of assignments) { + const targetId = this.findTargetId(project, targetName); + if (!targetId) { + this.$logger.warn( + `SPM: target "${targetName}" not found in ${path.basename(pbxProjPath)} — skipping package "${pkg.name}".`, + ); + continue; + } + + if (this.addPackageToTarget(project, targetId, pkg, projectRoot)) { + added = true; + } + } + + if (!added) { + return false; + } + + this.$fs.writeFile( + pbxProjPath, + project.writeSync({ omitEmptyValues: true }), + ); + return true; + } + + /** + * Locates `.xcodeproj/project.pbxproj` under the platform project + * root. The project is named after the app, so it's discovered rather than + * assumed. + */ + private findPbxProjPath(projectRoot: string): string | null { + if (!this.$fs.exists(projectRoot)) { + return null; + } + + const xcodeprojName = this.$fs + .readDirectory(projectRoot) + .find((entry) => entry.endsWith(".xcodeproj")); + if (!xcodeprojName) { + return null; + } + + const pbxProjPath = path.join( + projectRoot, + xcodeprojName, + "project.pbxproj", + ); + return this.$fs.exists(pbxProjPath) ? pbxProjPath : null; + } + + /** + * Resolves a target name to its pbxproj uuid. Target names in the pbxproj + * are quoted when they contain spaces, so both forms are matched. + */ + private findTargetId(project: any, targetName: string): string | null { + const targets = project.pbxNativeTargetSection() ?? {}; + for (const key of Object.keys(targets)) { + if (key.endsWith("_comment")) { + continue; + } + const name = targets[key]?.name; + if (name === targetName || name === `"${targetName}"`) { + return key; + } + } + return null; + } + + /** Returns true when the package was actually linked into the target. */ + private addPackageToTarget( + project: any, + targetId: string, + pkg: IosSPMPackage, + projectRoot: string, + ): boolean { + const target = project.pbxNativeTargetSection()[targetId]; + + // A target without a Frameworks build phase has nowhere to link the + // products; adding the package reference alone would leave the project + // in a state Xcode reports as corrupt, so bail out loudly instead — + // before touching the project, so a skipped package leaves no trace. + // (Resolved from the target's own buildPhases: the xcode lib's + // pbxFrameworksBuildPhaseObj falls back to *any* target's Frameworks + // phase when this one has none, which would link into the wrong target.) + const frameworkBuildPhaseObj = this.findFrameworksBuildPhase( + project, + target, + ); + if (!frameworkBuildPhaseObj) { + this.$logger.warn( + `SPM: target for package "${pkg.name}" has no Frameworks build phase — skipping.`, + ); + return false; + } + + const firstProject = project.getFirstProject().firstProject; + const packageReferences: any[] = (firstProject["packageReferences"] ??= []); + const packageProductReferences: any[] = (target[ + "packageProductDependencies" + ] ??= []); + const frameworkBuildPhaseFiles: any[] = (frameworkBuildPhaseObj["files"] ??= + []); + + let packageReferenceComment: string; + let packageReferenceSection: string; + let packageReferenceSectionContent: Record; + + if ("path" in pkg) { + // local package — Xcode stores the location relative to the project + const relativePath = path.relative( + projectRoot, + path.resolve(projectRoot, pkg.path), + ); + packageReferenceComment = `XCLocalSwiftPackageReference "${relativePath}"`; + packageReferenceSection = "XCLocalSwiftPackageReference"; + packageReferenceSectionContent = { + isa: packageReferenceSection, + relativePath: JSON.stringify(relativePath), + }; + } else { + packageReferenceComment = `XCRemoteSwiftPackageReference "${pkg.name}"`; + packageReferenceSection = "XCRemoteSwiftPackageReference"; + packageReferenceSectionContent = { + isa: packageReferenceSection, + repositoryURL: JSON.stringify(pkg.repositoryURL), + requirement: quoteValuesForPbxproj(classifyVersion(pkg.version)), + }; + } + + const { + uuid: spmPackageReferenceUUID, + comment: spmPackageReferenceComment, + } = this.addOrUpdateEntry( + project, + packageReferenceSection, + packageReferenceComment, + packageReferenceSectionContent, + ); + + this.addOrUpdateArrayEntry(packageReferences, spmPackageReferenceUUID, { + value: spmPackageReferenceUUID, + comment: packageReferenceComment, + }); + + for (const lib of pkg.libs ?? []) { + // The comment is just the product name, which two different packages + // can share (e.g. both exposing a "Core" lib) — so entries here are + // additionally matched on the package they belong to, otherwise the + // second package would silently repoint the first one's entries. + const { uuid: spmProductDependencyUUID } = this.addOrUpdateEntry( + project, + "XCSwiftPackageProductDependency", + lib, + { + isa: "XCSwiftPackageProductDependency", + package: spmPackageReferenceUUID, + package_comment: spmPackageReferenceComment, + productName: lib, + }, + (existing) => existing.package === spmPackageReferenceUUID, + ); + + const libComment = `${lib} in Frameworks`; + + const { uuid: spmBuildFileUuid } = this.addOrUpdateEntry( + project, + "PBXBuildFile", + libComment, + { + isa: "PBXBuildFile", + productRef: spmProductDependencyUUID, + productRef_comment: lib, + }, + (existing) => existing.productRef === spmProductDependencyUUID, + ); + + this.addOrUpdateArrayEntry( + packageProductReferences, + spmProductDependencyUUID, + { + value: spmProductDependencyUUID, + comment: lib, + }, + ); + + this.addOrUpdateArrayEntry(frameworkBuildPhaseFiles, spmBuildFileUuid, { + value: spmBuildFileUuid, + comment: libComment, + }); + } + + return true; + } + + /** Finds the Frameworks build phase listed in this target's own buildPhases. */ + private findFrameworksBuildPhase(project: any, target: any): any | null { + const section = + project.hash.project.objects["PBXFrameworksBuildPhase"] ?? {}; + for (const phase of target.buildPhases ?? []) { + const phaseObj = section[phase.value]; + if (phaseObj) { + return phaseObj; + } + } + return null; + } + + /** Replaces a matching array entry in place, or appends it. */ + private addOrUpdateArrayEntry( + array: any[], + lookupValue: string, + value: any, + ): void { + const existing = array.find((entry) => entry.value === lookupValue); + if (existing) { + Object.assign(existing, value); + return; + } + array.push(value); + } + + /** + * Writes an object into a pbxproj section, reusing the uuid of an entry + * with the same comment when one is already present. The comment is the + * identity of an entry here — it's what keeps repeated applies idempotent. + * When the comment alone is ambiguous (product names are not unique across + * packages), `matches` narrows the lookup to the right entry. + */ + private addOrUpdateEntry( + project: any, + section: string, + entryComment: string, + entry: any, + matches?: (existing: any) => boolean, + ): { uuid: string; comment: string } { + const pbxSection = (project.hash.project.objects[section] ??= {}); + const entryUuid = + this.findUuidByComment(project, section, entryComment, matches) ?? + project.generateUuid(); + + pbxSection[`${entryUuid}_comment`] = entryComment; + pbxSection[entryUuid] = entry; + + return { uuid: entryUuid, comment: entryComment }; + } + + private findUuidByComment( + project: any, + section: string, + comment: string, + matches?: (existing: any) => boolean, + ): string | null { + const pbxSection = project.hash.project.objects[section] ?? {}; + const commentKey = Object.keys(pbxSection).find((key) => { + if (!key.endsWith("_comment") || pbxSection[key] !== comment) { + return false; + } + if (!matches) { + return true; + } + const existing = pbxSection[key.replace(/_comment$/, "")]; + return existing != null && matches(existing); + }); + return commentKey ? commentKey.replace(/_comment$/, "") : null; + } +} + +/** + * Maps a package version string to the `requirement` object Xcode expects: + * + * "1.0.0" -> { kind: exactVersion, version } + * "^1.0.0" -> { kind: upToNextMajorVersion, minimumVersion } + * "~1.0.0" -> { kind: upToNextMinorVersion, minimumVersion } + * ">=1.0.0 <2.0.0" -> { kind: versionRange, minimumVersion, maximumVersion } + * "#" -> { kind: revision, revision } + * anything else -> { kind: branch, branch } + * + * A non-semver value is treated as a branch name, which is how a package can + * be pinned to e.g. "main". + */ +export function classifyVersion(version: string): Record { + if (version.startsWith("#")) { + return { + kind: "revision", + revision: version.replace("#", ""), + }; + } + + if (semver.valid(version)) { + return { + kind: "exactVersion", + version, + }; + } + + const range = semver.validRange(version); + if (range) { + const minimumVersion = semver.minVersion(range)?.version; + if (version.startsWith("^")) { + return { + kind: "upToNextMajorVersion", + minimumVersion, + }; + } + if (version.startsWith("~")) { + return { + kind: "upToNextMinorVersion", + minimumVersion, + }; + } + + const maximumVersion = semver.coerce( + version.replace(minimumVersion ?? "", ""), + )?.version; + + if (maximumVersion && maximumVersion !== minimumVersion) { + return { + kind: "versionRange", + minimumVersion, + maximumVersion, + }; + } + + return { + kind: "upToNextMajorVersion", + minimumVersion, + }; + } + + return { + kind: "branch", + branch: version, + }; +} + +/** + * The charset Xcode itself leaves unquoted in a pbxproj. The pbxproj writer + * emits values verbatim, so anything outside it — a prerelease version like + * "1.0.0-beta.1", a branch like "release 1.0" — must be quoted by the caller + * or the written file is malformed. + */ +const UNQUOTED_PBX_VALUE = /^[A-Za-z0-9_$./]+$/; + +function quoteValuesForPbxproj( + obj: Record, +): Record { + const result: Record = {}; + for (const [key, value] of Object.entries(obj)) { + result[key] = + typeof value === "string" && !UNQUOTED_PBX_VALUE.test(value) + ? JSON.stringify(value) + : value; + } + return result; +} + +injector.register("spmPbxprojService", SPMPbxprojService); diff --git a/lib/services/ios/spm-service.ts b/lib/services/ios/spm-service.ts index 84eb5d41e4..b4515b4dc7 100644 --- a/lib/services/ios/spm-service.ts +++ b/lib/services/ios/spm-service.ts @@ -1,6 +1,5 @@ import { injector } from "../../common/yok"; import { IProjectConfigService, IProjectData } from "../../definitions/project"; -import { MobileProject } from "@nstudio/trapezedev-project"; import { IPlatformData } from "../../definitions/platform"; import { IFileSystem } from "../../common/declarations"; import { ITerminalSpinnerService } from "../../definitions/terminal-spinner-service"; @@ -36,6 +35,7 @@ export class SPMService implements ISPMService { private $terminalSpinnerService: ITerminalSpinnerService, private $xcodebuildCommandService: IXcodebuildCommandService, private $xcodebuildArgsService: IXcodebuildArgsService, + private $spmPbxprojService: ISPMPbxprojService, ) {} public getSPMPackages( @@ -114,21 +114,8 @@ export class SPMService implements ISPMService { // dependency is responsible. this.$logger.info(this.formatPackageListing(spmPackages)); - const project = new MobileProject(platformData.projectRoot, { - ios: { - path: ".", - }, - enableAndroid: false, - }); - await project.load(); - - // note: in trapeze both visionOS and iOS are handled by the ios project. - if (!project.ios) { - this.$logger.trace("SPM: no iOS project found via trapeze."); - return; - } - // todo: handle removing packages? Or just warn and require a clean? + const assignments: IosSPMPackageAssignment[] = []; for (const pkg of spmPackages) { if ("path" in pkg) { // resolve the path relative to the project root @@ -143,16 +130,25 @@ export class SPMService implements ISPMService { } } this.$logger.trace(`SPM: adding package ${pkg.name} to project.`, pkg); - await project.ios.addSPMPackage(projectData.projectName, pkg); + assignments.push({ targetName: projectData.projectName, package: pkg }); // Add to other Targets if specified (like widgets, etc.) - if (pkg.targets?.length) { - for (const target of pkg.targets) { - await project.ios.addSPMPackage(target, pkg); - } + for (const target of pkg.targets ?? []) { + assignments.push({ targetName: target, package: pkg }); } } - await project.commit(); + + // note: visionOS shares the iOS Xcode project, so the same pbxproj is + // edited for both platforms. + if ( + !this.$spmPbxprojService.addPackages( + platformData.projectRoot, + assignments, + ) + ) { + this.$logger.trace("SPM: no packages were applied to the project."); + return; + } // finally resolve the dependencies await this.resolveSPMDependencies(platformData, projectData, { diff --git a/package-lock.json b/package-lock.json index 4fe752c4e1..35890a0ae8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,6 @@ "@nativescript/doctor": "2.0.17", "@nativescript/hook": "3.0.5", "@npmcli/arborist": "9.1.8", - "@nstudio/trapezedev-project": "7.2.4", "@rigor789/resolve-package-path": "1.0.7", "axios": "1.18.1", "byline": "5.0.0", @@ -185,18 +184,6 @@ } } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@emnapi/core": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", @@ -259,116 +246,6 @@ "node": ">=10.13.0" } }, - "node_modules/@ionic/utils-array": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@ionic/utils-array/-/utils-array-2.1.6.tgz", - "integrity": "sha512-0JZ1Zkp3wURnv8oq6Qt7fMPo5MpjbLoUoa9Bu2Q4PJuSDWM8H8gwF3dQO7VTeUj3/0o1IB1wGkFWZZYgUXZMUg==", - "license": "MIT", - "dependencies": { - "debug": "^4.0.0", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/utils-fs": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@ionic/utils-fs/-/utils-fs-3.1.7.tgz", - "integrity": "sha512-2EknRvMVfhnyhL1VhFkSLa5gOcycK91VnjfrTB0kbqkTFCOXyXgVLI5whzq7SLrgD9t1aqos3lMMQyVzaQ5gVA==", - "license": "MIT", - "dependencies": { - "@types/fs-extra": "^8.0.0", - "debug": "^4.0.0", - "fs-extra": "^9.0.0", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/utils-object": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@ionic/utils-object/-/utils-object-2.1.6.tgz", - "integrity": "sha512-vCl7sl6JjBHFw99CuAqHljYJpcE88YaH2ZW4ELiC/Zwxl5tiwn4kbdP/gxi2OT3MQb1vOtgAmSNRtusvgxI8ww==", - "license": "MIT", - "dependencies": { - "debug": "^4.0.0", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/utils-process": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/@ionic/utils-process/-/utils-process-2.1.11.tgz", - "integrity": "sha512-Uavxn+x8j3rDlZEk1X7YnaN6wCgbCwYQOeIjv/m94i1dzslqWhqIHEqxEyeE8HsT5Negboagg7GtQiABy+BLbA==", - "license": "MIT", - "dependencies": { - "@ionic/utils-object": "2.1.6", - "@ionic/utils-terminal": "2.3.4", - "debug": "^4.0.0", - "signal-exit": "^3.0.3", - "tree-kill": "^1.2.2", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/utils-stream": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@ionic/utils-stream/-/utils-stream-3.1.6.tgz", - "integrity": "sha512-4+Kitey1lTA1yGtnigeYNhV/0tggI3lWBMjC7tBs1K9GXa/q7q4CtOISppdh8QgtOhrhAXS2Igp8rbko/Cj+lA==", - "license": "MIT", - "dependencies": { - "debug": "^4.0.0", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/utils-subprocess": { - "version": "2.1.14", - "resolved": "https://registry.npmjs.org/@ionic/utils-subprocess/-/utils-subprocess-2.1.14.tgz", - "integrity": "sha512-nGYvyGVjU0kjPUcSRFr4ROTraT3w/7r502f5QJEsMRKTqa4eEzCshtwRk+/mpASm0kgBN5rrjYA5A/OZg8ahqg==", - "license": "MIT", - "dependencies": { - "@ionic/utils-array": "2.1.6", - "@ionic/utils-fs": "3.1.7", - "@ionic/utils-process": "2.1.11", - "@ionic/utils-stream": "3.1.6", - "@ionic/utils-terminal": "2.3.4", - "cross-spawn": "^7.0.3", - "debug": "^4.0.0", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@ionic/utils-terminal": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@ionic/utils-terminal/-/utils-terminal-2.3.4.tgz", - "integrity": "sha512-cEiMFl3jklE0sW60r8JHH3ijFTwh/jkdEKWbylSyExQwZ8pPuwoXz7gpkWoJRLuoRHHSvg+wzNYyPJazIHfoJA==", - "license": "MIT", - "dependencies": { - "@types/slice-ansi": "^4.0.0", - "debug": "^4.0.0", - "signal-exit": "^3.0.3", - "slice-ansi": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "tslib": "^2.0.1", - "untildify": "^4.0.0", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/@isaacs/cliui": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", @@ -809,31 +686,13 @@ "node": ">=18" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "node_modules/@kwsites/file-exists": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", @@ -1207,61 +1066,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@nstudio/trapezedev-project": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/@nstudio/trapezedev-project/-/trapezedev-project-7.2.4.tgz", - "integrity": "sha512-47/E/HMoWnfYpm6EW5wCy7zM168kNkomEiQJyH3r6TYd3HVsUIdH586v8NEOGqIMAxxi+71w+Qu08ztyKgubLQ==", - "license": "SEE LICENSE", - "dependencies": { - "@ionic/utils-fs": "^3.1.5", - "@ionic/utils-subprocess": "^2.1.8", - "@prettier/plugin-xml": "^2.2.0", - "@trapezedev/gradle-parse": "7.1.3", - "@xmldom/xmldom": "^0.8.11", - "cross-spawn": "^7.0.3", - "diff": "^5.1.0", - "env-paths": "^3.0.0", - "gradle-to-js": "^2.0.0", - "ini": "^2.0.0", - "kleur": "^4.1.5", - "lodash": "^4.17.21", - "plist": "^3.0.4", - "prettier": "^2.7.1", - "prompts": "^2.4.2", - "replace": "^1.1.0", - "simple-plist": "^1.4.0", - "tmp": "^0.2.1", - "ts-node": "^10.2.1", - "uuid": "^11.1.0", - "xml-js": "^1.6.11", - "xpath": "^0.0.32", - "yargs": "^17.2.1" - } - }, - "node_modules/@nstudio/trapezedev-project/node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/@nstudio/trapezedev-project/node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "license": "MIT", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/@oxc-project/types": { "version": "0.139.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", @@ -1272,16 +1076,6 @@ "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@prettier/plugin-xml": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-2.2.0.tgz", - "integrity": "sha512-UWRmygBsyj4bVXvDiqSccwT1kmsorcwQwaIy30yVh8T+Gspx4OlC0shX1y+ZuwXZvgnafmpRYKks0bAu9urJew==", - "license": "MIT", - "dependencies": { - "@xml-tools/parser": "^1.0.11", - "prettier": ">=2.4.0" - } - }, "node_modules/@rigor789/resolve-package-path": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@rigor789/resolve-package-path/-/resolve-package-path-1.0.7.tgz", @@ -1747,12 +1541,6 @@ "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", "license": "MIT" }, - "node_modules/@trapezedev/gradle-parse": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@trapezedev/gradle-parse/-/gradle-parse-7.1.3.tgz", - "integrity": "sha512-WQVF5pEJ5o/mUyvfGTG9nBKx9Te/ilKM3r2IT69GlbaooItT5ao7RyF1MUTBNjHLPk/xpGUY3c6PyVnjDlz0Vw==", - "license": "SEE LICENSE" - }, "node_modules/@ts-morph/common": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.26.1.tgz", @@ -1764,60 +1552,6 @@ "path-browserify": "^1.0.1" } }, - "node_modules/@ts-morph/common/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/@ts-morph/common/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@ts-morph/common/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "license": "MIT" - }, "node_modules/@tufjs/canonical-json": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", @@ -1947,15 +1681,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/fs-extra": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", - "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/lodash": { "version": "4.17.23", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", @@ -1993,6 +1718,7 @@ "version": "22.19.13", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.13.tgz", "integrity": "sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==", + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -2175,12 +1901,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-+OpjSaq85gvlZAYINyzKpLeiFkSC4EsC6IIiT6v6TLSU5k5U83fHGj9Lel8oKEXM0HqgrMVCjXPDPVICtxF7EQ==", - "license": "MIT" - }, "node_modules/@types/ssri": { "version": "7.1.5", "resolved": "https://registry.npmjs.org/@types/ssri/-/ssri-7.1.5.tgz", @@ -2416,15 +2136,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@xml-tools/parser": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.11.tgz", - "integrity": "sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==", - "license": "Apache-2.0", - "dependencies": { - "chevrotain": "7.1.1" - } - }, "node_modules/@xmldom/xmldom": { "version": "0.8.11", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", @@ -2446,30 +2157,6 @@ "node": ">=6.5" } }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.5", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", - "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/add-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", @@ -2553,12 +2240,6 @@ "node": ">= 8" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "license": "MIT" - }, "node_modules/array-ify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", @@ -2576,30 +2257,12 @@ "node": ">=12" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "license": "ISC", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/await-to-js": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-3.0.0.tgz", @@ -2958,15 +2621,6 @@ "node": ">= 16" } }, - "node_modules/chevrotain": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-7.1.1.tgz", - "integrity": "sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==", - "license": "Apache-2.0", - "dependencies": { - "regexp-to-ast": "0.5.0" - } - }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -3365,12 +3019,6 @@ "dot-prop": "^5.1.0" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, "node_modules/conventional-changelog": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-6.0.0.tgz", @@ -3615,12 +3263,6 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "license": "MIT" }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "license": "MIT" - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3754,15 +3396,6 @@ "node": ">=8" } }, - "node_modules/diff": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", - "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -3819,18 +3452,6 @@ "once": "^1.4.0" } }, - "node_modules/env-paths": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", - "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/environment": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", @@ -4233,21 +3854,6 @@ "node": ">= 6" } }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/fs-minipass": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", @@ -4463,18 +4069,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, - "node_modules/gradle-to-js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/gradle-to-js/-/gradle-to-js-2.0.1.tgz", - "integrity": "sha512-is3hDn9zb8XXnjbEeAEIqxTpLHUiGBqjegLmXPuyMBfKAggpadWFku4/AP8iYAGBX6qR9/5UIUIp47V0XI3aMw==", - "license": "Apache-2.0", - "dependencies": { - "lodash.merge": "^4.6.2" - }, - "bin": { - "gradle-to-js": "cli.js" - } - }, "node_modules/handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", @@ -5167,18 +4761,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, "node_modules/jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -5207,15 +4789,6 @@ "dev": true, "license": "MIT" }, - "node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/lightningcss": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", @@ -5614,12 +5187,6 @@ "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "license": "MIT" }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "license": "MIT" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -5840,12 +5407,6 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "license": "ISC" - }, "node_modules/make-fetch-happen": { "version": "15.0.4", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.4.tgz", @@ -6749,15 +6310,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -6883,15 +6435,6 @@ "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", "license": "MIT" }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -7441,298 +6984,6 @@ "node": ">=8.10.0" } }, - "node_modules/regexp-to-ast": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", - "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", - "license": "MIT" - }, - "node_modules/replace": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/replace/-/replace-1.2.2.tgz", - "integrity": "sha512-C4EDifm22XZM2b2JOYe6Mhn+lBsLBAvLbK8drfUQLTfD1KYl/n3VaW/CDju0Ny4w3xTtegBpg8YNSpFJPUDSjA==", - "license": "MIT", - "dependencies": { - "chalk": "2.4.2", - "minimatch": "3.0.5", - "yargs": "^15.3.1" - }, - "bin": { - "replace": "bin/replace.js", - "search": "bin/search.js" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/replace/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/replace/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/replace/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/replace/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/replace/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/replace/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/replace/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/replace/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" - }, - "node_modules/replace/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/replace/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/replace/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/replace/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/replace/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/replace/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/replace/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/replace/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/replace/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/replace/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/replace/node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/replace/node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/replace/node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/replace/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "license": "ISC" - }, - "node_modules/replace/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "license": "MIT", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/replace/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -7742,12 +6993,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "license": "ISC" - }, "node_modules/resolve": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", @@ -7930,12 +7175,6 @@ "node": ">=10" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -8205,23 +7444,6 @@ "node": ">=8" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -8696,15 +7918,6 @@ "node": ">=14.0.0" } }, - "node_modules/tmp": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", - "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -8734,15 +7947,6 @@ "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, "node_modules/treeverse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-3.0.0.tgz", @@ -8762,63 +7966,13 @@ "code-block-writer": "^13.0.3" } }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", - "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" + "dev": true, + "license": "0BSD", + "optional": true }, "node_modules/tuf-js": { "version": "4.1.0", @@ -8897,6 +8051,7 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, "license": "MIT" }, "node_modules/unicode-emoji-modifier-base": { @@ -8959,24 +8114,6 @@ "node": ">=12.18.2" } }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/utif2": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/utif2/-/utif2-4.1.0.tgz", @@ -9006,12 +8143,6 @@ "uuid": "dist/esm/bin/uuid" } }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "license": "MIT" - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -9270,12 +8401,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "license": "ISC" - }, "node_modules/why-is-node-running": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", @@ -9374,18 +8499,6 @@ } } }, - "node_modules/xml-js": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", - "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", - "license": "MIT", - "dependencies": { - "sax": "^1.2.4" - }, - "bin": { - "xml-js": "bin/cli.js" - } - }, "node_modules/xml-parse-from-string": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz", @@ -9423,15 +8536,6 @@ "node": ">=8.0" } }, - "node_modules/xpath": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.32.tgz", - "integrity": "sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==", - "license": "MIT", - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -9524,15 +8628,6 @@ "buffer-crc32": "^1.0.0" } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/zod": { "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", diff --git a/package.json b/package.json index ed73252ed4..84aefbf24c 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,6 @@ "@nativescript/doctor": "2.0.17", "@nativescript/hook": "3.0.5", "@npmcli/arborist": "9.1.8", - "@nstudio/trapezedev-project": "7.2.4", "@rigor789/resolve-package-path": "1.0.7", "axios": "1.18.1", "byline": "5.0.0", @@ -147,6 +146,9 @@ ], "overrides": { "@conventional-changelog/git-client": "2.5.1", + "@ts-morph/common@0.26.1": { + "minimatch": "10.2.4" + }, "uuid": "11.1.0", "jimp": { "xml2js": "0.6.2" diff --git a/test/services/ios/spm-pbxproj-service.ts b/test/services/ios/spm-pbxproj-service.ts new file mode 100644 index 0000000000..44a1f6a7eb --- /dev/null +++ b/test/services/ios/spm-pbxproj-service.ts @@ -0,0 +1,415 @@ +import { assert } from "chai"; +import { + mkdtempSync, + mkdirSync, + copyFileSync, + readFileSync, + writeFileSync, +} from "fs"; +import { tmpdir } from "os"; +import * as path from "path"; +import { Yok } from "../../../lib/common/yok"; +import { + SPMPbxprojService, + classifyVersion, +} from "../../../lib/services/ios/spm-pbxproj-service"; +import { FileSystem } from "../../../lib/common/file-system"; +import { IInjector } from "../../../lib/common/definitions/yok"; + +// the target that exists in test/files/project.pbxproj +const TARGET_NAME = "TNSBlank"; +// its PBXFrameworksBuildPhase uuid in that fixture (a group is also named +// "Frameworks", so tests that strip the phase must key on the uuid) +const FRAMEWORKS_PHASE_ID = "858B83F418CA22B800AB12DE"; + +const remotePackage: IosSPMPackage = { + name: "swift-numerics", + libs: ["RealModule", "ComplexModule"], + repositoryURL: "https://github.com/apple/swift-numerics.git", + version: "1.0.0", +}; + +const localPackage: IosSPMPackage = { + name: "LocalPkg", + libs: ["LocalPkg"], + path: "vendor/LocalPkg", +}; + +let warnings: string[] = []; + +function createTestInjector(): IInjector { + const injector = new Yok(); + warnings = []; + injector.register("fs", FileSystem); + injector.register("logger", { + warn: (message: string) => warnings.push(message), + trace: (): void => undefined, + debug: (): void => undefined, + }); + injector.register("xcode", require("nativescript-dev-xcode")); + injector.register("spmPbxprojService", SPMPbxprojService); + return injector; +} + +/** Creates a platform project root containing a copy of the fixture pbxproj. */ +function createProjectRoot(): string { + const projectRoot = mkdtempSync(path.join(tmpdir(), "spm-pbxproj-")); + const xcodeprojPath = path.join(projectRoot, `${TARGET_NAME}.xcodeproj`); + mkdirSync(xcodeprojPath); + copyFileSync( + path.join(__dirname, "..", "..", "files", "project.pbxproj"), + path.join(xcodeprojPath, "project.pbxproj"), + ); + return projectRoot; +} + +function readPbxproj(projectRoot: string): string { + return readFileSync( + path.join(projectRoot, `${TARGET_NAME}.xcodeproj`, "project.pbxproj"), + "utf8", + ); +} + +function countOccurrences(contents: string, needle: string): number { + return contents.split(needle).length - 1; +} + +describe("SPMPbxprojService", () => { + let service: ISPMPbxprojService; + let projectRoot: string; + + beforeEach(() => { + service = createTestInjector().resolve("spmPbxprojService"); + projectRoot = createProjectRoot(); + }); + + describe("classifyVersion", () => { + const testCases: Array<{ + version: string; + expected: Record; + }> = [ + { + version: "1.0.0", + expected: { kind: "exactVersion", version: "1.0.0" }, + }, + { + version: "^2.5.0", + expected: { kind: "upToNextMajorVersion", minimumVersion: "2.5.0" }, + }, + { + version: "~3.1.0", + expected: { kind: "upToNextMinorVersion", minimumVersion: "3.1.0" }, + }, + { + version: ">=1.2.0 <2.0.0", + expected: { + kind: "versionRange", + minimumVersion: "1.2.0", + maximumVersion: "2.0.0", + }, + }, + { version: "main", expected: { kind: "branch", branch: "main" } }, + { + version: "#5f03bfdc8cb6300ef8355695a3d27d11ba19f6a3", + expected: { + kind: "revision", + revision: "5f03bfdc8cb6300ef8355695a3d27d11ba19f6a3", + }, + }, + ]; + + testCases.forEach(({ version, expected }) => { + it(`maps "${version}" to ${expected.kind}`, () => { + assert.deepEqual(classifyVersion(version), expected); + }); + }); + }); + + describe("addPackages", () => { + it("writes a remote package reference and links each of its libs", () => { + const result = service.addPackages(projectRoot, [ + { targetName: TARGET_NAME, package: remotePackage }, + ]); + + assert.isTrue(result); + const contents = readPbxproj(projectRoot); + + // the package reference itself, listed on the project + assert.include( + contents, + 'XCRemoteSwiftPackageReference "swift-numerics"', + "expected a remote package reference section entry", + ); + assert.include(contents, "repositoryURL = "); + assert.include(contents, "https://github.com/apple/swift-numerics.git"); + assert.include(contents, "kind = exactVersion"); + assert.include(contents, "packageReferences = ("); + + // one product dependency + build file + Frameworks entry per lib + for (const lib of remotePackage.libs) { + assert.include( + contents, + `productName = ${lib}`, + `expected a product dependency for ${lib}`, + ); + assert.include( + contents, + `${lib} in Frameworks`, + `expected ${lib} in the Frameworks build phase`, + ); + } + assert.include(contents, "packageProductDependencies = ("); + }); + + it("writes a local package reference relative to the project root", () => { + const absolutePackagePath = path.join(projectRoot, "vendor", "LocalPkg"); + const result = service.addPackages(projectRoot, [ + { + targetName: TARGET_NAME, + package: { ...localPackage, path: absolutePackagePath }, + }, + ]); + + assert.isTrue(result); + const contents = readPbxproj(projectRoot); + + assert.include( + contents, + 'XCLocalSwiftPackageReference "vendor/LocalPkg"', + "expected the local package to be recorded by relative path", + ); + assert.include(contents, "relativePath = "); + assert.notInclude( + contents, + absolutePackagePath, + "the absolute path must not leak into the pbxproj", + ); + }); + + it("is idempotent — reapplying the same packages does not duplicate entries", () => { + const assignments: IosSPMPackageAssignment[] = [ + { targetName: TARGET_NAME, package: remotePackage }, + ]; + + assert.isTrue(service.addPackages(projectRoot, assignments)); + const afterFirst = readPbxproj(projectRoot); + + assert.isTrue(service.addPackages(projectRoot, assignments)); + const afterSecond = readPbxproj(projectRoot); + + assert.equal( + afterSecond, + afterFirst, + "reapplying the same packages should leave the pbxproj byte-identical", + ); + assert.equal( + countOccurrences( + afterSecond, + 'XCRemoteSwiftPackageReference "swift-numerics" */ = {', + ), + 1, + "the package reference should be defined exactly once", + ); + assert.equal( + countOccurrences(afterSecond, "RealModule in Frameworks */ = {"), + 1, + "the build file should be defined exactly once", + ); + }); + + it("updates an existing package reference in place when the version changes", () => { + assert.isTrue( + service.addPackages(projectRoot, [ + { targetName: TARGET_NAME, package: remotePackage }, + ]), + ); + assert.isTrue( + service.addPackages(projectRoot, [ + { + targetName: TARGET_NAME, + package: { ...remotePackage, version: "2.0.0" }, + }, + ]), + ); + + const contents = readPbxproj(projectRoot); + assert.equal( + countOccurrences( + contents, + 'XCRemoteSwiftPackageReference "swift-numerics" */ = {', + ), + 1, + "the package should still be defined exactly once", + ); + assert.include(contents, "version = 2.0.0"); + assert.notInclude(contents, "version = 1.0.0"); + }); + + it("skips a target without a Frameworks build phase, warns, and writes nothing", () => { + // strip the Frameworks build phase from the fixture target — both the + // section entry and its slot in the target's buildPhases + const pbxPath = path.join( + projectRoot, + `${TARGET_NAME}.xcodeproj`, + "project.pbxproj", + ); + const stripped = readFileSync(pbxPath, "utf8") + .replace( + new RegExp( + `^\\s*${FRAMEWORKS_PHASE_ID} /\\* Frameworks \\*/,\\n`, + "m", + ), + "", + ) + .replace( + new RegExp( + `^\\s*${FRAMEWORKS_PHASE_ID} /\\* Frameworks \\*/ = \\{[\\s\\S]*?\\};\\n`, + "m", + ), + "", + ); + writeFileSync(pbxPath, stripped); + + const result = service.addPackages(projectRoot, [ + { targetName: TARGET_NAME, package: remotePackage }, + ]); + + assert.isFalse( + result, + "nothing could be applied, so nothing was written", + ); + assert.isTrue( + warnings.some((w) => w.includes("no Frameworks build phase")), + `expected a warning about the missing build phase, got: ${warnings}`, + ); + const contents = readPbxproj(projectRoot); + assert.notInclude(contents, "XCRemoteSwiftPackageReference"); + assert.notInclude( + contents, + "packageReferences", + "the skipped package must leave no trace, not even an empty list", + ); + }); + + it("keeps same-named products from different packages distinct", () => { + const otherPackage: IosSPMPackage = { + name: "other-numerics", + libs: ["RealModule"], + repositoryURL: "https://example.com/other/other-numerics.git", + version: "2.0.0", + }; + const assignments: IosSPMPackageAssignment[] = [ + { targetName: TARGET_NAME, package: remotePackage }, + { targetName: TARGET_NAME, package: otherPackage }, + ]; + + assert.isTrue(service.addPackages(projectRoot, assignments)); + // reapply to prove the scoped lookup is still idempotent + assert.isTrue(service.addPackages(projectRoot, assignments)); + + const xcode = require("nativescript-dev-xcode"); + const project = new xcode.project( + path.join(projectRoot, `${TARGET_NAME}.xcodeproj`, "project.pbxproj"), + ); + project.parseSync(); + const section = + project.hash.project.objects["XCSwiftPackageProductDependency"]; + const realModuleDeps = Object.keys(section) + .filter((key) => !key.endsWith("_comment")) + .map((key) => section[key]) + .filter((entry) => entry.productName === "RealModule"); + + assert.equal( + realModuleDeps.length, + 2, + "each package should own its own RealModule product dependency", + ); + assert.equal( + new Set(realModuleDeps.map((entry) => entry.package)).size, + 2, + "the two product dependencies should point at different packages", + ); + }); + + it("quotes requirement values a pbxproj cannot hold bare", () => { + assert.isTrue( + service.addPackages(projectRoot, [ + { + targetName: TARGET_NAME, + package: { ...remotePackage, version: "1.0.0-beta.1" }, + }, + ]), + ); + + assert.include(readPbxproj(projectRoot), 'version = "1.0.0-beta.1";'); + }); + + it("quotes branch requirements containing spaces", () => { + assert.isTrue( + service.addPackages(projectRoot, [ + { + targetName: TARGET_NAME, + package: { ...remotePackage, version: "release 1.0" }, + }, + ]), + ); + + assert.include(readPbxproj(projectRoot), 'branch = "release 1.0";'); + }); + + it("skips a package whose target is missing, and warns", () => { + const result = service.addPackages(projectRoot, [ + { targetName: "NoSuchTarget", package: remotePackage }, + ]); + + assert.isFalse( + result, + "nothing could be applied, so nothing was written", + ); + assert.isTrue( + warnings.some((w) => w.includes("NoSuchTarget")), + `expected a warning naming the missing target, got: ${warnings}`, + ); + assert.notInclude( + readPbxproj(projectRoot), + "XCRemoteSwiftPackageReference", + ); + }); + + it("still applies packages for targets that do exist when another is missing", () => { + const result = service.addPackages(projectRoot, [ + { targetName: "NoSuchTarget", package: localPackage }, + { targetName: TARGET_NAME, package: remotePackage }, + ]); + + assert.isTrue(result); + const contents = readPbxproj(projectRoot); + assert.include( + contents, + 'XCRemoteSwiftPackageReference "swift-numerics"', + ); + assert.notInclude(contents, "XCLocalSwiftPackageReference"); + }); + + it("returns false when there are no packages to apply", () => { + assert.isFalse(service.addPackages(projectRoot, [])); + }); + + it("returns false when the project root has no .xcodeproj", () => { + const emptyRoot = mkdtempSync(path.join(tmpdir(), "spm-empty-")); + assert.isFalse( + service.addPackages(emptyRoot, [ + { targetName: TARGET_NAME, package: remotePackage }, + ]), + ); + }); + + it("returns false when the project root does not exist", () => { + assert.isFalse( + service.addPackages(path.join(tmpdir(), "spm-does-not-exist"), [ + { targetName: TARGET_NAME, package: remotePackage }, + ]), + ); + }); + }); +});