@swiftbrowser/cli 0.1.0 → 0.3.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 +340 -65
- package/dist/assetSymbols.d.ts +25 -0
- package/dist/assetSymbols.js +218 -0
- package/dist/assetSymbols.js.map +1 -0
- package/dist/build.d.ts +27 -2
- package/dist/build.js +71 -14
- package/dist/build.js.map +1 -1
- package/dist/buildSettings.d.ts +15 -0
- package/dist/buildSettings.js +74 -0
- package/dist/buildSettings.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +66 -11
- package/dist/cli.js.map +1 -1
- package/dist/commands/build.js +6 -5
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/check.js +2 -2
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/dev.d.ts +5 -2
- package/dist/commands/dev.js +19 -13
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.d.ts +18 -0
- package/dist/commands/init.js +59 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/kit.d.ts +3 -0
- package/dist/commands/kit.js +21 -0
- package/dist/commands/kit.js.map +1 -0
- package/dist/commands/shared.d.ts +28 -4
- package/dist/commands/shared.js +106 -11
- package/dist/commands/shared.js.map +1 -1
- package/dist/commands/test.d.ts +22 -0
- package/dist/commands/test.js +95 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/compat.d.ts +44 -6
- package/dist/compat.js +64 -36
- package/dist/compat.js.map +1 -1
- package/dist/config.d.ts +48 -10
- package/dist/config.js +64 -8
- package/dist/config.js.map +1 -1
- package/dist/coreml.d.ts +194 -0
- package/dist/coreml.js +626 -0
- package/dist/coreml.js.map +1 -0
- package/dist/icu.d.ts +17 -4
- package/dist/icu.js +32 -18
- package/dist/icu.js.map +1 -1
- package/dist/kit.d.ts +133 -0
- package/dist/kit.js +403 -0
- package/dist/kit.js.map +1 -0
- package/dist/objc.d.ts +31 -0
- package/dist/objc.js +319 -0
- package/dist/objc.js.map +1 -0
- package/dist/packagePatches.d.ts +24 -0
- package/dist/packagePatches.js +107 -0
- package/dist/packagePatches.js.map +1 -0
- package/dist/packages.d.ts +59 -0
- package/dist/packages.js +149 -0
- package/dist/packages.js.map +1 -0
- package/dist/project.d.ts +97 -4
- package/dist/project.js +157 -20
- package/dist/project.js.map +1 -1
- package/dist/protobuf.d.ts +62 -0
- package/dist/protobuf.js +233 -0
- package/dist/protobuf.js.map +1 -0
- package/dist/stage.d.ts +175 -28
- package/dist/stage.js +551 -85
- package/dist/stage.js.map +1 -1
- package/dist/strings.d.ts +44 -0
- package/dist/strings.js +386 -0
- package/dist/strings.js.map +1 -0
- package/dist/template.d.ts +39 -0
- package/dist/template.js +678 -0
- package/dist/template.js.map +1 -0
- package/dist/testRunner.d.ts +1 -0
- package/dist/testRunner.js +44 -0
- package/dist/testRunner.js.map +1 -0
- package/dist/threadStacks.d.ts +14 -0
- package/dist/threadStacks.js +78 -0
- package/dist/threadStacks.js.map +1 -0
- package/dist/toolchain.d.ts +7 -1
- package/dist/toolchain.js +8 -2
- package/dist/toolchain.js.map +1 -1
- package/dist/urlSchemes.d.ts +11 -0
- package/dist/urlSchemes.js +58 -0
- package/dist/urlSchemes.js.map +1 -0
- package/dist/vendor.d.ts +109 -0
- package/dist/vendor.js +440 -0
- package/dist/vendor.js.map +1 -0
- package/dist/wasm.d.ts +28 -0
- package/dist/wasm.js +84 -0
- package/dist/wasm.js.map +1 -0
- package/package.json +7 -6
package/dist/packages.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// The Swift packages an Xcode project depends on (Package Dependencies in
|
|
2
|
+
// Xcode: `XCRemoteSwiftPackageReference`, `XCLocalSwiftPackageReference`).
|
|
3
|
+
// Each becomes one of two things in the staging package:
|
|
4
|
+
//
|
|
5
|
+
// - a real SwiftPM dependency, with the version rule the project records, so
|
|
6
|
+
// a pure-Swift package that builds for WASI is fetched and compiled into
|
|
7
|
+
// the module like any other code;
|
|
8
|
+
// - nothing, for a package SwiftBrowser knows cannot work in the browser
|
|
9
|
+
// (a camera scanner over AVFoundation and UIKit): the shim ships a module
|
|
10
|
+
// of the same name with the package's public API (`STAND_IN_FRAMEWORKS`
|
|
11
|
+
// in compat.ts), linked when a source imports it.
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { packageIdentity } from '@swiftbrowser/xcodeproj';
|
|
14
|
+
/**
|
|
15
|
+
* Packages the shim stands in for, by SwiftPM identity, with the reason the
|
|
16
|
+
* real one cannot be used and the products it provides. Each product is a
|
|
17
|
+
* module of the SwiftBrowser package (Sources/<Product>), listed in
|
|
18
|
+
* `STAND_IN_FRAMEWORKS`. When another package depends on one, the staging
|
|
19
|
+
* gives that package a redirect in its place (vendor.ts).
|
|
20
|
+
*/
|
|
21
|
+
export const PACKAGE_STAND_INS = {};
|
|
22
|
+
/** `swiftbrowser.json`'s packages (config.ts), as the Xcode project's are: paths relative to `root`. */
|
|
23
|
+
export function configPackages(packages, root) {
|
|
24
|
+
return packages.map((entry) => {
|
|
25
|
+
if (entry.path) {
|
|
26
|
+
const dir = path.resolve(root, entry.path);
|
|
27
|
+
return { reference: { kind: 'local', path: dir, identity: packageIdentity(dir) }, products: [...entry.products] };
|
|
28
|
+
}
|
|
29
|
+
const url = entry.url;
|
|
30
|
+
const requirement = entry.from
|
|
31
|
+
? { kind: 'upToNextMajorVersion', minimumVersion: entry.from }
|
|
32
|
+
: entry.exact
|
|
33
|
+
? { kind: 'exactVersion', version: entry.exact }
|
|
34
|
+
: entry.branch
|
|
35
|
+
? { kind: 'branch', branch: entry.branch }
|
|
36
|
+
: { kind: 'revision', revision: entry.revision };
|
|
37
|
+
return { reference: { kind: 'remote', url, identity: packageIdentity(url), requirement }, products: [...entry.products] };
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/** Groups a target's package products by package, in the order the project lists them. */
|
|
41
|
+
export function groupPackageProducts(dependencies) {
|
|
42
|
+
const byIdentity = new Map();
|
|
43
|
+
const out = [];
|
|
44
|
+
for (const dependency of dependencies) {
|
|
45
|
+
if (!dependency.package) {
|
|
46
|
+
out.push({ products: [dependency.product] });
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const key = `${dependency.package.kind}:${dependency.package.identity}`;
|
|
50
|
+
let entry = byIdentity.get(key);
|
|
51
|
+
if (!entry) {
|
|
52
|
+
entry = { reference: dependency.package, products: [] };
|
|
53
|
+
byIdentity.set(key, entry);
|
|
54
|
+
out.push(entry);
|
|
55
|
+
}
|
|
56
|
+
if (!entry.products.includes(dependency.product))
|
|
57
|
+
entry.products.push(dependency.product);
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
/** What the staging does with each package (`standIns` for tests: none today). */
|
|
62
|
+
export function planPackages(packages, standIns = PACKAGE_STAND_INS) {
|
|
63
|
+
return packages.map((entry) => {
|
|
64
|
+
const reference = entry.reference;
|
|
65
|
+
if (!reference) {
|
|
66
|
+
return { kind: 'unresolved', package: entry, problem: 'the project does not say which package it comes from' };
|
|
67
|
+
}
|
|
68
|
+
const standIn = standIns[reference.identity];
|
|
69
|
+
if (standIn)
|
|
70
|
+
return { kind: 'stand-in', package: entry, reason: standIn.reason };
|
|
71
|
+
if (reference.kind === 'local') {
|
|
72
|
+
return { kind: 'dependency', package: entry, identity: reference.identity, declaration: `.package(path: ${JSON.stringify(reference.path)})` };
|
|
73
|
+
}
|
|
74
|
+
if (!reference.requirement) {
|
|
75
|
+
return { kind: 'unresolved', package: entry, problem: 'its dependency rule is not one SwiftBrowser knows; set a version in Xcode' };
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
kind: 'dependency',
|
|
79
|
+
package: entry,
|
|
80
|
+
identity: reference.identity,
|
|
81
|
+
declaration: `.package(url: ${JSON.stringify(reference.url)}, ${requirementArgument(reference.requirement)})`,
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/** Xcode's dependency rule as the argument of SwiftPM's `.package(url:…)`. */
|
|
86
|
+
export function requirementArgument(requirement) {
|
|
87
|
+
switch (requirement.kind) {
|
|
88
|
+
case 'upToNextMajorVersion':
|
|
89
|
+
return `from: ${JSON.stringify(requirement.minimumVersion)}`;
|
|
90
|
+
case 'upToNextMinorVersion':
|
|
91
|
+
return `.upToNextMinor(from: ${JSON.stringify(requirement.minimumVersion)})`;
|
|
92
|
+
case 'exactVersion':
|
|
93
|
+
return `exact: ${JSON.stringify(requirement.version)}`;
|
|
94
|
+
case 'versionRange':
|
|
95
|
+
return `${JSON.stringify(requirement.minimumVersion)}..<${JSON.stringify(requirement.maximumVersion)}`;
|
|
96
|
+
case 'branch':
|
|
97
|
+
return `branch: ${JSON.stringify(requirement.branch)}`;
|
|
98
|
+
case 'revision':
|
|
99
|
+
return `revision: ${JSON.stringify(requirement.revision)}`;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** The rule in words, as Xcode's package list shows it. */
|
|
103
|
+
export function describeRequirement(requirement) {
|
|
104
|
+
switch (requirement.kind) {
|
|
105
|
+
case 'upToNextMajorVersion':
|
|
106
|
+
return `up to next major from ${requirement.minimumVersion}`;
|
|
107
|
+
case 'upToNextMinorVersion':
|
|
108
|
+
return `up to next minor from ${requirement.minimumVersion}`;
|
|
109
|
+
case 'exactVersion':
|
|
110
|
+
return `exactly ${requirement.version}`;
|
|
111
|
+
case 'versionRange':
|
|
112
|
+
return `${requirement.minimumVersion} to ${requirement.maximumVersion}`;
|
|
113
|
+
case 'branch':
|
|
114
|
+
return `branch ${requirement.branch}`;
|
|
115
|
+
case 'revision':
|
|
116
|
+
return `revision ${requirement.revision.slice(0, 12)}`;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** A package as people name it: the URL's last component (case kept), or the folder. */
|
|
120
|
+
export function packageDisplayName(entry) {
|
|
121
|
+
const reference = entry.reference;
|
|
122
|
+
if (!reference)
|
|
123
|
+
return entry.products.join(', ');
|
|
124
|
+
const location = reference.kind === 'remote' ? reference.url : reference.path;
|
|
125
|
+
const last = location.replace(/[/\\]+$/, '').split(/[/\\:]/).pop() ?? location;
|
|
126
|
+
return last.replace(/\.git$/i, '');
|
|
127
|
+
}
|
|
128
|
+
/** Where a package comes from, and on what rule, for the `check` report. */
|
|
129
|
+
export function packageSource(entry) {
|
|
130
|
+
const reference = entry.reference;
|
|
131
|
+
if (!reference)
|
|
132
|
+
return '';
|
|
133
|
+
if (reference.kind === 'local')
|
|
134
|
+
return reference.path;
|
|
135
|
+
const url = reference.url.replace(/^https?:\/\//, '').replace(/\.git$/i, '');
|
|
136
|
+
return reference.requirement ? `${url}, ${describeRequirement(reference.requirement)}` : url;
|
|
137
|
+
}
|
|
138
|
+
/** Module names the dependency packages provide, guessed as their product names → the package's name. */
|
|
139
|
+
export function packageModules(plans) {
|
|
140
|
+
const modules = new Map();
|
|
141
|
+
for (const plan of plans) {
|
|
142
|
+
if (plan.kind !== 'dependency')
|
|
143
|
+
continue;
|
|
144
|
+
for (const product of plan.package.products)
|
|
145
|
+
modules.set(product, packageDisplayName(plan.package));
|
|
146
|
+
}
|
|
147
|
+
return modules;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=packages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"packages.js","sourceRoot":"","sources":["../src/packages.ts"],"names":[],"mappings":"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"}
|
package/dist/project.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { SwiftPackageReference } from '@swiftbrowser/xcodeproj';
|
|
2
|
+
import { type SwiftLanguageMode } from './config.js';
|
|
3
|
+
import { type AppPackage } from './packages.js';
|
|
4
|
+
import { type SwiftSettings } from './buildSettings.js';
|
|
2
5
|
export interface ResolvedApp {
|
|
3
6
|
/** Swift module name (`[A-Za-z_][A-Za-z0-9_]*`); also the URL name. */
|
|
4
7
|
name: string;
|
|
@@ -7,17 +10,53 @@ export interface ResolvedApp {
|
|
|
7
10
|
root: string;
|
|
8
11
|
/** Absolute paths of the Swift sources, in build order. */
|
|
9
12
|
sources: string[];
|
|
13
|
+
/**
|
|
14
|
+
* Absolute paths of the Core ML models (`.mlmodel`, `.mlpackage`) the app
|
|
15
|
+
* compiles; each becomes a generated class (coreml.ts). Absent means none.
|
|
16
|
+
*/
|
|
17
|
+
models?: string[];
|
|
10
18
|
/** Absolute paths of `*.xcassets` directories. */
|
|
11
19
|
catalogs: string[];
|
|
12
20
|
/** Absolute paths of the resource files and folders `Bundle.main` serves. */
|
|
13
21
|
resources: string[];
|
|
22
|
+
/**
|
|
23
|
+
* Absolute paths of the string catalogs (`.xcstrings`) and `.strings` /
|
|
24
|
+
* `.stringsdict` files compiled into the app's string tables (strings.ts).
|
|
25
|
+
* Absent means none.
|
|
26
|
+
*/
|
|
27
|
+
localizations?: string[];
|
|
14
28
|
/** A PNG app icon, when one was found. */
|
|
15
29
|
icon?: string;
|
|
16
30
|
swiftLanguageMode: SwiftLanguageMode;
|
|
17
|
-
|
|
31
|
+
/**
|
|
32
|
+
* The Xcode target's concurrency settings (default actor isolation,
|
|
33
|
+
* upcoming features; buildSettings.ts). Absent for a folder of sources.
|
|
34
|
+
*/
|
|
35
|
+
swiftSettings?: SwiftSettings;
|
|
36
|
+
/**
|
|
37
|
+
* The generated asset symbols (assetSymbols.ts): `false` when the Xcode
|
|
38
|
+
* target turns them off (`ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS =
|
|
39
|
+
* NO`), `'extensions'` when it also wants the `Color` and `ShapeStyle`
|
|
40
|
+
* members (`ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS =
|
|
41
|
+
* YES`, which Xcode's templates set). Absent: the resource members only.
|
|
42
|
+
*/
|
|
43
|
+
assetSymbols?: false | 'extensions';
|
|
18
44
|
/** Languages whose ICU data a full-Foundation build keeps. */
|
|
19
45
|
locales: string[];
|
|
46
|
+
/** The app's URL schemes (Info.plist `CFBundleURLTypes`, or `urlSchemes` in swiftbrowser.json); see urlSchemes.ts. */
|
|
47
|
+
urlSchemes?: string[];
|
|
48
|
+
/** A CORS proxy the page retries refused cross-origin reads through (`corsProxy` in swiftbrowser.json, `--cors-proxy`). */
|
|
49
|
+
corsProxy?: string;
|
|
50
|
+
/** Hosts the app's requests may not reach (`blockHosts` in swiftbrowser.json, `--block-host`). */
|
|
51
|
+
blockHosts?: string[];
|
|
52
|
+
/** Whether ICU's collation tables ship (`collation` in swiftbrowser.json; default true). */
|
|
53
|
+
collation: boolean;
|
|
20
54
|
defines: string[];
|
|
55
|
+
/**
|
|
56
|
+
* The Swift packages the Xcode target links (Package Dependencies), and
|
|
57
|
+
* those `swiftbrowser.json` lists, each with its products. See packages.ts.
|
|
58
|
+
*/
|
|
59
|
+
packages: AppPackage[];
|
|
21
60
|
/** How the app was found. */
|
|
22
61
|
origin: {
|
|
23
62
|
kind: 'xcodeproj';
|
|
@@ -26,23 +65,76 @@ export interface ResolvedApp {
|
|
|
26
65
|
} | {
|
|
27
66
|
kind: 'folder';
|
|
28
67
|
};
|
|
68
|
+
/**
|
|
69
|
+
* The app's unit tests, for `swiftbrowser test` (testTargets): the Xcode
|
|
70
|
+
* unit-test targets hosted by the app, or a folder's `*Tests` folders.
|
|
71
|
+
* Absent means none.
|
|
72
|
+
*/
|
|
73
|
+
tests?: TestTarget[];
|
|
29
74
|
}
|
|
75
|
+
/** A unit-test target of the app: a module of tests that `@testable import` it. */
|
|
76
|
+
export interface TestTarget {
|
|
77
|
+
/** Swift module name. */
|
|
78
|
+
name: string;
|
|
79
|
+
/** Absolute paths of its Swift sources. */
|
|
80
|
+
sources: string[];
|
|
81
|
+
}
|
|
82
|
+
/** Xcode's product type of a unit-test bundle (UI tests, `bundle.ui-testing`, drive a simulator and are not run). */
|
|
83
|
+
export declare const UNIT_TEST_PRODUCT_TYPE = "com.apple.product-type.bundle.unit-test";
|
|
30
84
|
export interface ResolveOptions {
|
|
31
85
|
target?: string;
|
|
32
86
|
configFile?: string;
|
|
33
|
-
foundation?: FoundationMode;
|
|
34
87
|
}
|
|
35
88
|
/** `Guess The Flag` → `GuessTheFlag`; a leading digit gets an underscore. */
|
|
36
89
|
export declare function moduleName(raw: string): string;
|
|
37
|
-
/**
|
|
90
|
+
/** A Core ML model Xcode compiles into a class: an `.mlmodel` file or an `.mlpackage` bundle. */
|
|
91
|
+
export declare function isCoreMLModel(file: string): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* The unit tests of a folder of sources, by convention: the `.swift` files
|
|
94
|
+
* under its `Tests` and `*Tests` folders (`*UITests` excepted), which the app's
|
|
95
|
+
* sources leave out, as one target `<app>Tests`.
|
|
96
|
+
*/
|
|
97
|
+
export declare function discoverTests(dir: string, appName: string): TestTarget[];
|
|
98
|
+
/**
|
|
99
|
+
* The Xcode unit-test targets that test `app`: those that depend on it or
|
|
100
|
+
* load into it (`TEST_HOST`, `BUNDLE_LOADER` naming its product). Each is a
|
|
101
|
+
* module of its own, as in Xcode.
|
|
102
|
+
*/
|
|
103
|
+
export declare function xcodeTestTargets(targets: readonly XcodeTargetLike[], app: XcodeTargetLike): TestTarget[];
|
|
104
|
+
/** Every `.swift` file, Core ML model and `.xcassets` folder under `dir`, by convention. */
|
|
38
105
|
export declare function discoverByConvention(dir: string): {
|
|
39
106
|
sources: string[];
|
|
107
|
+
models: string[];
|
|
40
108
|
catalogs: string[];
|
|
109
|
+
localizations: string[];
|
|
41
110
|
};
|
|
42
111
|
/** The largest PNG of the app icon set, for the home-screen manifest. */
|
|
43
112
|
export declare function findAppIcon(catalogs: readonly string[], iconName?: string): string | undefined;
|
|
44
113
|
/** `.xcodeproj` bundles directly in `dir`, else one level down. */
|
|
45
114
|
export declare function xcodeProjectsIn(dir: string): string[];
|
|
115
|
+
interface XcodeTargetLike {
|
|
116
|
+
name: string;
|
|
117
|
+
productName: string;
|
|
118
|
+
productType: string;
|
|
119
|
+
displayName?: string;
|
|
120
|
+
appIconName?: string;
|
|
121
|
+
swiftVersion?: string;
|
|
122
|
+
sources: string[];
|
|
123
|
+
/** Absent in @swiftbrowser/xcodeproj releases before Core ML models were read. */
|
|
124
|
+
models?: string[];
|
|
125
|
+
/** String catalogs and `.strings` / `.stringsdict` files; absent in older @swiftbrowser/xcodeproj releases. */
|
|
126
|
+
localizations?: string[];
|
|
127
|
+
resources: string[];
|
|
128
|
+
assetCatalogs: string[];
|
|
129
|
+
packageDependencies?: {
|
|
130
|
+
product: string;
|
|
131
|
+
package?: SwiftPackageReference;
|
|
132
|
+
}[];
|
|
133
|
+
/** Names of the targets it depends on; absent in older @swiftbrowser/xcodeproj releases' typings. */
|
|
134
|
+
dependencies?: string[];
|
|
135
|
+
/** Build settings (`INFOPLIST_FILE` for the URL schemes); absent in older @swiftbrowser/xcodeproj releases' typings. */
|
|
136
|
+
settings?(configuration?: string): Record<string, string>;
|
|
137
|
+
}
|
|
46
138
|
/** The Xcode target's copied resources: everything but asset catalogs and compiled resources, in project order. */
|
|
47
139
|
export declare function bundleResources(resources: readonly string[]): string[];
|
|
48
140
|
/** Resolves `input` (an .xcodeproj, a folder with one, or a folder of sources) to an app. */
|
|
@@ -54,3 +146,4 @@ export declare function resolveApp(input: string, options?: ResolveOptions): Pro
|
|
|
54
146
|
* against its directory; the path comes back unchanged when nothing matches.
|
|
55
147
|
*/
|
|
56
148
|
export declare function repairCase(file: string): string;
|
|
149
|
+
export {};
|
package/dist/project.js
CHANGED
|
@@ -5,6 +5,12 @@ import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { loadConfig } from './config.js';
|
|
7
7
|
import { CliError } from './log.js';
|
|
8
|
+
import { configPackages, groupPackageProducts } from './packages.js';
|
|
9
|
+
import { swiftSettingsOf } from './buildSettings.js';
|
|
10
|
+
import { isLocalizationFile, localizationsAmong } from './strings.js';
|
|
11
|
+
import { urlSchemesOfTarget } from './urlSchemes.js';
|
|
12
|
+
/** Xcode's product type of a unit-test bundle (UI tests, `bundle.ui-testing`, drive a simulator and are not run). */
|
|
13
|
+
export const UNIT_TEST_PRODUCT_TYPE = 'com.apple.product-type.bundle.unit-test';
|
|
8
14
|
/** Directories never searched for sources or catalogs. */
|
|
9
15
|
const SKIP_DIRS = new Set(['.build', '.swiftbrowser', '.git', 'node_modules', 'DerivedData', 'Pods', 'Carthage', 'build', 'Preview Content']);
|
|
10
16
|
/** `Guess The Flag` → `GuessTheFlag`; a leading digit gets an underscore. */
|
|
@@ -20,7 +26,7 @@ function walk(dir, visit) {
|
|
|
20
26
|
if (entry.isDirectory()) {
|
|
21
27
|
if (SKIP_DIRS.has(entry.name) || entry.name.startsWith('.') || /(Tests|UITests)$/.test(entry.name))
|
|
22
28
|
continue;
|
|
23
|
-
if (entry.name.endsWith('.xcassets') || entry.name.endsWith('.xcodeproj') || entry.name.endsWith('.xcworkspace')) {
|
|
29
|
+
if (entry.name.endsWith('.xcassets') || entry.name.endsWith('.xcodeproj') || entry.name.endsWith('.xcworkspace') || entry.name.endsWith('.mlpackage')) {
|
|
24
30
|
visit(full, statSync(full));
|
|
25
31
|
continue;
|
|
26
32
|
}
|
|
@@ -31,31 +37,100 @@ function walk(dir, visit) {
|
|
|
31
37
|
}
|
|
32
38
|
}
|
|
33
39
|
}
|
|
34
|
-
/**
|
|
40
|
+
/** A Core ML model Xcode compiles into a class: an `.mlmodel` file or an `.mlpackage` bundle. */
|
|
41
|
+
export function isCoreMLModel(file) {
|
|
42
|
+
return file.endsWith('.mlmodel') || file.endsWith('.mlpackage');
|
|
43
|
+
}
|
|
44
|
+
/** A folder of tests by convention: `Tests`, `MyAppTests`, but not `MyAppUITests`. */
|
|
45
|
+
const TESTS_DIR = /Tests$/;
|
|
46
|
+
const UI_TESTS_DIR = /UITests$/;
|
|
47
|
+
/**
|
|
48
|
+
* The unit tests of a folder of sources, by convention: the `.swift` files
|
|
49
|
+
* under its `Tests` and `*Tests` folders (`*UITests` excepted), which the app's
|
|
50
|
+
* sources leave out, as one target `<app>Tests`.
|
|
51
|
+
*/
|
|
52
|
+
export function discoverTests(dir, appName) {
|
|
53
|
+
const sources = [];
|
|
54
|
+
const visit = (current, inTests) => {
|
|
55
|
+
for (const entry of readdirSync(current, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
56
|
+
const full = path.join(current, entry.name);
|
|
57
|
+
if (entry.isDirectory()) {
|
|
58
|
+
if (SKIP_DIRS.has(entry.name) || entry.name.startsWith('.') || UI_TESTS_DIR.test(entry.name) || entry.name.endsWith('.xcodeproj'))
|
|
59
|
+
continue;
|
|
60
|
+
visit(full, inTests || TESTS_DIR.test(entry.name));
|
|
61
|
+
}
|
|
62
|
+
else if (inTests && entry.isFile() && entry.name.endsWith('.swift')) {
|
|
63
|
+
sources.push(full);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
visit(dir, false);
|
|
68
|
+
return sources.length > 0 ? [{ name: `${appName}Tests`, sources }] : [];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The Xcode unit-test targets that test `app`: those that depend on it or
|
|
72
|
+
* load into it (`TEST_HOST`, `BUNDLE_LOADER` naming its product). Each is a
|
|
73
|
+
* module of its own, as in Xcode.
|
|
74
|
+
*/
|
|
75
|
+
export function xcodeTestTargets(targets, app) {
|
|
76
|
+
const product = app.productName || app.name;
|
|
77
|
+
const hosted = (target) => {
|
|
78
|
+
if (target.dependencies?.includes(app.name))
|
|
79
|
+
return true;
|
|
80
|
+
const settings = target.settings?.() ?? {};
|
|
81
|
+
return [settings['TEST_HOST'], settings['BUNDLE_LOADER']].some((value) => value !== undefined && value.includes(`/${product}.app/`));
|
|
82
|
+
};
|
|
83
|
+
return targets
|
|
84
|
+
.filter((target) => target.productType === UNIT_TEST_PRODUCT_TYPE && hosted(target))
|
|
85
|
+
.map((target) => ({ name: moduleName(target.productName || target.name), sources: target.sources.filter((file) => file.endsWith('.swift')) }))
|
|
86
|
+
.filter((target) => target.sources.length > 0);
|
|
87
|
+
}
|
|
88
|
+
/** Every `.swift` file, Core ML model and `.xcassets` folder under `dir`, by convention. */
|
|
35
89
|
export function discoverByConvention(dir) {
|
|
36
90
|
const sources = [];
|
|
91
|
+
const models = [];
|
|
37
92
|
const catalogs = [];
|
|
93
|
+
const localizations = [];
|
|
38
94
|
walk(dir, (file) => {
|
|
39
95
|
if (file.endsWith('.swift') && !/(Tests|UITests)\.swift$/.test(path.basename(file)) && !/Package\.swift$/.test(file))
|
|
40
96
|
sources.push(file);
|
|
97
|
+
else if (isCoreMLModel(file))
|
|
98
|
+
models.push(file);
|
|
41
99
|
else if (file.endsWith('.xcassets'))
|
|
42
100
|
catalogs.push(file);
|
|
101
|
+
else if (file.endsWith('.xcstrings') || (isLocalizationFile(file) && path.dirname(file).endsWith('.lproj')))
|
|
102
|
+
localizations.push(file);
|
|
43
103
|
});
|
|
44
|
-
return { sources, catalogs };
|
|
104
|
+
return { sources, models, catalogs, localizations };
|
|
105
|
+
}
|
|
106
|
+
/** A string catalog, table or `.lproj` folder: compiled into string tables, not copied. */
|
|
107
|
+
function isLocalizationSource(file) {
|
|
108
|
+
return isLocalizationFile(file) || file.endsWith('.lproj');
|
|
45
109
|
}
|
|
46
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* Swift files and Core ML models named by a config `sources` list: files as
|
|
112
|
+
* is (a model by its extension), directories recursively.
|
|
113
|
+
*/
|
|
47
114
|
function expandSources(root, entries) {
|
|
48
|
-
const
|
|
115
|
+
const sources = [];
|
|
116
|
+
const models = [];
|
|
49
117
|
for (const entry of entries) {
|
|
50
118
|
const full = path.resolve(root, entry);
|
|
51
119
|
if (!existsSync(full))
|
|
52
120
|
throw new CliError(`sources entry not found: ${entry}`);
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
121
|
+
if (isCoreMLModel(full)) {
|
|
122
|
+
models.push(full);
|
|
123
|
+
}
|
|
124
|
+
else if (statSync(full).isDirectory()) {
|
|
125
|
+
const found = discoverByConvention(full);
|
|
126
|
+
sources.push(...found.sources);
|
|
127
|
+
models.push(...found.models);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
sources.push(full);
|
|
131
|
+
}
|
|
57
132
|
}
|
|
58
|
-
return
|
|
133
|
+
return { sources, models };
|
|
59
134
|
}
|
|
60
135
|
function applyExcludes(root, files, exclude) {
|
|
61
136
|
if (!exclude || exclude.length === 0)
|
|
@@ -137,9 +212,9 @@ export async function resolveApp(input, options = {}) {
|
|
|
137
212
|
}
|
|
138
213
|
const config = loadConfig(root, options.configFile);
|
|
139
214
|
const swiftLanguageMode = config.swiftLanguageMode ?? '5';
|
|
140
|
-
const foundation = options.foundation ?? config.foundation ?? 'full';
|
|
141
215
|
const defines = config.defines ?? [];
|
|
142
216
|
const locales = config.locales ?? ['en'];
|
|
217
|
+
const collation = config.collation ?? true;
|
|
143
218
|
if (projectPath) {
|
|
144
219
|
const project = await readXcode(projectPath);
|
|
145
220
|
const apps = project.appTargets();
|
|
@@ -161,48 +236,92 @@ export async function resolveApp(input, options = {}) {
|
|
|
161
236
|
}
|
|
162
237
|
if (!chosen)
|
|
163
238
|
throw new CliError('no target chosen');
|
|
164
|
-
const
|
|
239
|
+
const listed = config.sources ? expandSources(root, config.sources) : null;
|
|
240
|
+
const sources = applyExcludes(root, listed ? listed.sources : chosen.sources.filter((f) => f.endsWith('.swift')), config.exclude);
|
|
241
|
+
const models = applyExcludes(root, listed ? listed.models : (chosen.models ?? []), config.exclude);
|
|
165
242
|
const catalogs = config.catalogs ? config.catalogs.map((c) => path.resolve(root, c)) : chosen.assetCatalogs;
|
|
166
|
-
const
|
|
243
|
+
const listedResources = config.resources?.map((r) => path.resolve(root, r));
|
|
244
|
+
const resources = listedResources ? listedResources.filter((r) => !isLocalizationSource(r)) : bundleResources(chosen.resources ?? []);
|
|
245
|
+
const localizations = listedResources ? localizationsAmong(listedResources) : (chosen.localizations ?? []);
|
|
167
246
|
const icon = config.icon ? path.resolve(root, config.icon) : findAppIcon(catalogs, chosen.appIconName);
|
|
168
247
|
const app = {
|
|
169
248
|
name: config.name ?? moduleName(chosen.productName || chosen.name),
|
|
170
249
|
displayName: config.displayName ?? chosen.displayName ?? chosen.productName ?? chosen.name,
|
|
171
250
|
root,
|
|
172
251
|
sources,
|
|
252
|
+
models,
|
|
173
253
|
catalogs,
|
|
174
254
|
resources,
|
|
255
|
+
...(localizations.length > 0 ? { localizations } : {}),
|
|
175
256
|
swiftLanguageMode: config.swiftLanguageMode ?? (chosen.swiftVersion?.startsWith('6') ? '6' : swiftLanguageMode),
|
|
176
|
-
foundation,
|
|
177
257
|
locales,
|
|
258
|
+
collation,
|
|
178
259
|
defines,
|
|
260
|
+
packages: [...groupPackageProducts(chosen.packageDependencies ?? []), ...configPackages(config.packages ?? [], root)],
|
|
179
261
|
origin: { kind: 'xcodeproj', project: projectPath, target: chosen.name },
|
|
180
262
|
};
|
|
181
263
|
if (icon)
|
|
182
264
|
app.icon = icon;
|
|
265
|
+
const buildSettings = chosen.settings?.();
|
|
266
|
+
if (buildSettings) {
|
|
267
|
+
const settings = swiftSettingsOf(buildSettings, app.swiftLanguageMode);
|
|
268
|
+
if (settings.defaultIsolationMainActor || settings.upcomingFeatures.length > 0)
|
|
269
|
+
app.swiftSettings = settings;
|
|
270
|
+
if (/^(NO|FALSE|0)$/i.test(buildSettings['ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS'] ?? ''))
|
|
271
|
+
app.assetSymbols = false;
|
|
272
|
+
else if (/^(YES|TRUE|1)$/i.test(buildSettings['ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS'] ?? ''))
|
|
273
|
+
app.assetSymbols = 'extensions';
|
|
274
|
+
}
|
|
275
|
+
const tests = xcodeTestTargets(project.targets, chosen);
|
|
276
|
+
if (tests.length > 0)
|
|
277
|
+
app.tests = tests;
|
|
278
|
+
const urlSchemes = config.urlSchemes ?? urlSchemesOfTarget(chosen, root);
|
|
279
|
+
if (urlSchemes.length > 0)
|
|
280
|
+
app.urlSchemes = urlSchemes;
|
|
281
|
+
if (config.corsProxy)
|
|
282
|
+
app.corsProxy = config.corsProxy;
|
|
283
|
+
if (config.blockHosts?.length)
|
|
284
|
+
app.blockHosts = config.blockHosts;
|
|
183
285
|
return finish(app);
|
|
184
286
|
}
|
|
185
287
|
const discovered = discoverByConvention(root);
|
|
186
|
-
const
|
|
288
|
+
const listed = config.sources ? expandSources(root, config.sources) : null;
|
|
289
|
+
const sources = applyExcludes(root, listed ? listed.sources : discovered.sources, config.exclude);
|
|
290
|
+
const models = applyExcludes(root, listed ? listed.models : discovered.models, config.exclude);
|
|
187
291
|
const catalogs = config.catalogs ? config.catalogs.map((c) => path.resolve(root, c)) : discovered.catalogs;
|
|
188
|
-
// A plain folder has no Copy Bundle Resources phase: resources come from the
|
|
189
|
-
|
|
292
|
+
// A plain folder has no Copy Bundle Resources phase: resources come from the
|
|
293
|
+
// config only, string tables from the config or the folder.
|
|
294
|
+
const listedResources = (config.resources ?? []).map((r) => path.resolve(root, r));
|
|
295
|
+
const resources = listedResources.filter((r) => !isLocalizationSource(r));
|
|
296
|
+
const localizations = config.resources ? localizationsAmong(listedResources) : discovered.localizations;
|
|
190
297
|
const icon = config.icon ? path.resolve(root, config.icon) : findAppIcon(catalogs);
|
|
191
298
|
const app = {
|
|
192
299
|
name: config.name ?? moduleName(path.basename(root)),
|
|
193
300
|
displayName: config.displayName ?? path.basename(root),
|
|
194
301
|
root,
|
|
195
302
|
sources,
|
|
303
|
+
models,
|
|
196
304
|
catalogs,
|
|
197
305
|
resources,
|
|
306
|
+
...(localizations.length > 0 ? { localizations } : {}),
|
|
198
307
|
swiftLanguageMode,
|
|
199
|
-
foundation,
|
|
200
308
|
locales,
|
|
309
|
+
collation,
|
|
201
310
|
defines,
|
|
311
|
+
packages: configPackages(config.packages ?? [], root),
|
|
202
312
|
origin: { kind: 'folder' },
|
|
203
313
|
};
|
|
204
314
|
if (icon)
|
|
205
315
|
app.icon = icon;
|
|
316
|
+
const tests = discoverTests(root, app.name);
|
|
317
|
+
if (tests.length > 0)
|
|
318
|
+
app.tests = tests;
|
|
319
|
+
if (config.urlSchemes?.length)
|
|
320
|
+
app.urlSchemes = config.urlSchemes;
|
|
321
|
+
if (config.corsProxy)
|
|
322
|
+
app.corsProxy = config.corsProxy;
|
|
323
|
+
if (config.blockHosts?.length)
|
|
324
|
+
app.blockHosts = config.blockHosts;
|
|
206
325
|
return finish(app);
|
|
207
326
|
}
|
|
208
327
|
/**
|
|
@@ -239,6 +358,8 @@ function finish(app) {
|
|
|
239
358
|
// An Xcode project made on macOS can name files whose case differs from the
|
|
240
359
|
// disk's; repair what can be repaired, report the rest.
|
|
241
360
|
app.sources = app.sources.map(repairCase);
|
|
361
|
+
if (app.models)
|
|
362
|
+
app.models = app.models.map(repairCase);
|
|
242
363
|
app.catalogs = app.catalogs.map(repairCase);
|
|
243
364
|
app.resources = app.resources.map(repairCase);
|
|
244
365
|
if (app.icon)
|
|
@@ -247,18 +368,34 @@ function finish(app) {
|
|
|
247
368
|
if (missing.length > 0) {
|
|
248
369
|
throw new CliError(`${missing.length} source file${missing.length === 1 ? '' : 's'} named by the project ${missing.length === 1 ? 'does' : 'do'} not exist:\n ${missing.join('\n ')}`);
|
|
249
370
|
}
|
|
371
|
+
const missingModels = (app.models ?? []).filter((file) => !existsSync(file));
|
|
372
|
+
if (missingModels.length > 0) {
|
|
373
|
+
throw new CliError(`${missingModels.length} Core ML model${missingModels.length === 1 ? '' : 's'} named by the project ${missingModels.length === 1 ? 'does' : 'do'} not exist:\n ${missingModels.join('\n ')}`);
|
|
374
|
+
}
|
|
250
375
|
const missingResources = app.resources.filter((file) => !existsSync(file));
|
|
251
376
|
if (missingResources.length > 0) {
|
|
252
377
|
throw new CliError(`${missingResources.length} resource${missingResources.length === 1 ? '' : 's'} named by the project ${missingResources.length === 1 ? 'does' : 'do'} not exist:\n ${missingResources.join('\n ')}`);
|
|
253
378
|
}
|
|
379
|
+
uniqueFileNames(app.sources);
|
|
380
|
+
for (const target of app.tests ?? []) {
|
|
381
|
+
target.sources = target.sources.map(repairCase);
|
|
382
|
+
const gone = target.sources.filter((file) => !existsSync(file));
|
|
383
|
+
if (gone.length > 0) {
|
|
384
|
+
throw new CliError(`${gone.length} test source${gone.length === 1 ? '' : 's'} named by the project ${gone.length === 1 ? 'does' : 'do'} not exist:\n ${gone.join('\n ')}`);
|
|
385
|
+
}
|
|
386
|
+
uniqueFileNames(target.sources);
|
|
387
|
+
}
|
|
388
|
+
return app;
|
|
389
|
+
}
|
|
390
|
+
/** Swift needs the files of a module to have unique names. */
|
|
391
|
+
function uniqueFileNames(files) {
|
|
254
392
|
const names = new Map();
|
|
255
|
-
for (const file of
|
|
393
|
+
for (const file of files) {
|
|
256
394
|
const base = path.basename(file);
|
|
257
395
|
const other = names.get(base);
|
|
258
396
|
if (other)
|
|
259
397
|
throw new CliError(`two sources share the file name ${base} (Swift needs unique names in a module):\n ${other}\n ${file}`);
|
|
260
398
|
names.set(base, file);
|
|
261
399
|
}
|
|
262
|
-
return app;
|
|
263
400
|
}
|
|
264
401
|
//# sourceMappingURL=project.js.map
|