@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/template.js
ADDED
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
// The new-project template behind `swiftbrowser init`: an iOS SwiftUI app as
|
|
2
|
+
// Xcode 16's App template lays it out with "Include Tests" (an app target and
|
|
3
|
+
// a Swift Testing unit-test target, each with a synchronized folder; an asset
|
|
4
|
+
// catalog), so the same project opens in Xcode, runs with `swiftbrowser dev`
|
|
5
|
+
// and tests with `swiftbrowser test` or ⌘U. Everything here is pure:
|
|
6
|
+
// `projectFiles` returns the files to write, and commands/init.ts writes them.
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
/** A Swift type name: a letter, then letters and digits. The app's struct is `<name>App`. */
|
|
9
|
+
export const APP_NAME = /^[A-Za-z][A-Za-z0-9]*$/;
|
|
10
|
+
/**
|
|
11
|
+
* The app name a directory suggests: `my-app` → `MyApp`, `hello world` →
|
|
12
|
+
* `HelloWorld`; a leading digit gets `My` in front. Undefined when nothing
|
|
13
|
+
* usable is left.
|
|
14
|
+
*/
|
|
15
|
+
export function appNameFrom(dir) {
|
|
16
|
+
const words = dir.split(/[^A-Za-z0-9]+/).filter(Boolean);
|
|
17
|
+
if (words.length === 0)
|
|
18
|
+
return undefined;
|
|
19
|
+
const name = words.map((word) => word[0].toUpperCase() + word.slice(1)).join('');
|
|
20
|
+
return /^[0-9]/.test(name) ? `My${name}` : name;
|
|
21
|
+
}
|
|
22
|
+
/** Every file of a new project, relative to its directory. */
|
|
23
|
+
export function projectFiles(options) {
|
|
24
|
+
const { name } = options;
|
|
25
|
+
if (!APP_NAME.test(name))
|
|
26
|
+
throw new Error(`not an app name: ${name}`);
|
|
27
|
+
const bundleId = options.bundleId ?? `com.example.${name}`;
|
|
28
|
+
const json = (value) => `${JSON.stringify(value, null, 2)}\n`;
|
|
29
|
+
return [
|
|
30
|
+
{ path: `${name}.xcodeproj/project.pbxproj`, contents: pbxproj(name, bundleId) },
|
|
31
|
+
{ path: `${name}.xcodeproj/project.xcworkspace/contents.xcworkspacedata`, contents: WORKSPACE },
|
|
32
|
+
{ path: `${name}/${name}App.swift`, contents: appSource(name) },
|
|
33
|
+
{ path: `${name}/ContentView.swift`, contents: CONTENT_VIEW },
|
|
34
|
+
{ path: `${name}/Assets.xcassets/Contents.json`, contents: json(CATALOG_INFO) },
|
|
35
|
+
{ path: `${name}/Assets.xcassets/AccentColor.colorset/Contents.json`, contents: json(ACCENT_COLOR) },
|
|
36
|
+
{ path: `${name}/Assets.xcassets/AppIcon.appiconset/Contents.json`, contents: json(APP_ICON) },
|
|
37
|
+
{ path: `${name}Tests/${name}Tests.swift`, contents: testSource(name) },
|
|
38
|
+
{ path: `${name}.xcodeproj/xcshareddata/xcschemes/${name}.xcscheme`, contents: scheme(name) },
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
/** The lines a new project's `.gitignore` holds (merged into an existing one). */
|
|
42
|
+
export const GITIGNORE_LINES = [
|
|
43
|
+
'# SwiftBrowser: staging packages and `swiftbrowser build` output',
|
|
44
|
+
'.swiftbrowser/',
|
|
45
|
+
'dist/',
|
|
46
|
+
'# Xcode',
|
|
47
|
+
'xcuserdata/',
|
|
48
|
+
'DerivedData/',
|
|
49
|
+
'.DS_Store',
|
|
50
|
+
];
|
|
51
|
+
/** `existing` with the template's lines it lacks appended; `existing` itself when it has them all. */
|
|
52
|
+
export function mergeGitignore(existing) {
|
|
53
|
+
const have = new Set((existing ?? '').split('\n').map((line) => line.trim()));
|
|
54
|
+
const missing = GITIGNORE_LINES.filter((line) => line.startsWith('#') ? false : !have.has(line));
|
|
55
|
+
if (existing !== undefined && missing.length === 0)
|
|
56
|
+
return existing;
|
|
57
|
+
if (existing === undefined)
|
|
58
|
+
return `${GITIGNORE_LINES.join('\n')}\n`;
|
|
59
|
+
const separator = existing === '' || existing.endsWith('\n') ? '' : '\n';
|
|
60
|
+
return `${existing}${separator}\n${['# SwiftBrowser and Xcode', ...missing].join('\n')}\n`;
|
|
61
|
+
}
|
|
62
|
+
/** A short README for a new project (written only where there is none). */
|
|
63
|
+
export function readme(name) {
|
|
64
|
+
return `# ${name}
|
|
65
|
+
|
|
66
|
+
A SwiftUI app that runs on iOS and, with [SwiftBrowser](https://github.com/noya-app/SwiftBrowser), in the browser.
|
|
67
|
+
|
|
68
|
+
- Xcode: open \`${name}.xcodeproj\`.
|
|
69
|
+
- Browser: \`npx @swiftbrowser/cli dev .\` serves it with rebuild on save
|
|
70
|
+
(\`--host\` to open it on a phone on the same network).
|
|
71
|
+
- \`npx @swiftbrowser/cli check .\` compiles it against SwiftBrowser in seconds;
|
|
72
|
+
\`npx @swiftbrowser/cli build .\` writes a static site to \`dist/\`.
|
|
73
|
+
- Tests: \`npx @swiftbrowser/cli test .\` runs \`${name}Tests/\` in WebAssembly, as the
|
|
74
|
+
browser runs the app; ⌘U runs the same tests in Xcode.
|
|
75
|
+
|
|
76
|
+
Add Swift files anywhere under \`${name}/\` (tests under \`${name}Tests/\`): Xcode and
|
|
77
|
+
SwiftBrowser both pick them up.
|
|
78
|
+
`;
|
|
79
|
+
}
|
|
80
|
+
function appSource(name) {
|
|
81
|
+
return `import SwiftUI
|
|
82
|
+
|
|
83
|
+
@main
|
|
84
|
+
struct ${name}App: App {
|
|
85
|
+
var body: some Scene {
|
|
86
|
+
WindowGroup {
|
|
87
|
+
ContentView()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
const CONTENT_VIEW = `import SwiftUI
|
|
94
|
+
|
|
95
|
+
struct ContentView: View {
|
|
96
|
+
@State private var taps = 0
|
|
97
|
+
|
|
98
|
+
var body: some View {
|
|
99
|
+
VStack(spacing: 16) {
|
|
100
|
+
Image(systemName: "globe")
|
|
101
|
+
.imageScale(.large)
|
|
102
|
+
.foregroundStyle(.tint)
|
|
103
|
+
Text("Hello, world!")
|
|
104
|
+
Button(Self.tapCount(taps)) {
|
|
105
|
+
taps += 1
|
|
106
|
+
}
|
|
107
|
+
.buttonStyle(.borderedProminent)
|
|
108
|
+
}
|
|
109
|
+
.padding()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/// The button's title after \`taps\` taps (checked by the tests).
|
|
113
|
+
static func tapCount(_ taps: Int) -> String {
|
|
114
|
+
taps == 1 ? "Tapped once" : "Tapped \\(taps) times"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
#Preview {
|
|
119
|
+
ContentView()
|
|
120
|
+
}
|
|
121
|
+
`;
|
|
122
|
+
function testSource(name) {
|
|
123
|
+
return `import Testing
|
|
124
|
+
@testable import ${name}
|
|
125
|
+
|
|
126
|
+
// Swift Testing, as Xcode's template writes it: \`swiftbrowser test\` runs
|
|
127
|
+
// these in WebAssembly, ⌘U in the iOS Simulator.
|
|
128
|
+
@MainActor
|
|
129
|
+
struct ${name}Tests {
|
|
130
|
+
@Test func tapCountReadsNaturally() {
|
|
131
|
+
#expect(ContentView.tapCount(0) == "Tapped 0 times")
|
|
132
|
+
#expect(ContentView.tapCount(1) == "Tapped once")
|
|
133
|
+
#expect(ContentView.tapCount(2) == "Tapped 2 times")
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
`;
|
|
137
|
+
}
|
|
138
|
+
const WORKSPACE = `<?xml version="1.0" encoding="UTF-8"?>
|
|
139
|
+
<Workspace
|
|
140
|
+
version = "1.0">
|
|
141
|
+
<FileRef
|
|
142
|
+
location = "self:">
|
|
143
|
+
</FileRef>
|
|
144
|
+
</Workspace>
|
|
145
|
+
`;
|
|
146
|
+
const CATALOG_INFO = { info: { author: 'xcode', version: 1 } };
|
|
147
|
+
// Xcode's template leaves the accent color empty; a value (iOS's system blue)
|
|
148
|
+
// keeps both Xcode and SwiftBrowser from reporting an empty color set.
|
|
149
|
+
const ACCENT_COLOR = {
|
|
150
|
+
colors: [
|
|
151
|
+
{
|
|
152
|
+
color: { 'color-space': 'srgb', components: { alpha: '1.000', blue: '1.000', green: '0.533', red: '0.000' } },
|
|
153
|
+
idiom: 'universal',
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
info: { author: 'xcode', version: 1 },
|
|
157
|
+
};
|
|
158
|
+
const APP_ICON = {
|
|
159
|
+
images: [
|
|
160
|
+
{ idiom: 'universal', platform: 'ios', size: '1024x1024' },
|
|
161
|
+
{ appearances: [{ appearance: 'luminosity', value: 'dark' }], idiom: 'universal', platform: 'ios', size: '1024x1024' },
|
|
162
|
+
{ appearances: [{ appearance: 'luminosity', value: 'tinted' }], idiom: 'universal', platform: 'ios', size: '1024x1024' },
|
|
163
|
+
],
|
|
164
|
+
info: { author: 'xcode', version: 1 },
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* The app's shared scheme: builds and runs the app, and tests `<name>Tests`
|
|
168
|
+
* (⌘U, `xcodebuild test -scheme <name>`). Xcode would make one per user on
|
|
169
|
+
* first open; a shared one gives every checkout, and CI, the same test action.
|
|
170
|
+
*/
|
|
171
|
+
export function scheme(name) {
|
|
172
|
+
const reference = (target, product) => `<BuildableReference
|
|
173
|
+
BuildableIdentifier = "primary"
|
|
174
|
+
BlueprintIdentifier = "${objectId(name, target)}"
|
|
175
|
+
BuildableName = "${product}"
|
|
176
|
+
BlueprintName = "${product.replace(/\.[a-z]+$/, '')}"
|
|
177
|
+
ReferencedContainer = "container:${name}.xcodeproj">
|
|
178
|
+
</BuildableReference>`;
|
|
179
|
+
const app = reference('target', `${name}.app`);
|
|
180
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
181
|
+
<Scheme
|
|
182
|
+
LastUpgradeVersion = "1600"
|
|
183
|
+
version = "1.7">
|
|
184
|
+
<BuildAction
|
|
185
|
+
parallelizeBuildables = "YES"
|
|
186
|
+
buildImplicitDependencies = "YES"
|
|
187
|
+
buildArchitectures = "Automatic">
|
|
188
|
+
<BuildActionEntries>
|
|
189
|
+
<BuildActionEntry
|
|
190
|
+
buildForTesting = "YES"
|
|
191
|
+
buildForRunning = "YES"
|
|
192
|
+
buildForProfiling = "YES"
|
|
193
|
+
buildForArchiving = "YES"
|
|
194
|
+
buildForAnalyzing = "YES">
|
|
195
|
+
${app}
|
|
196
|
+
</BuildActionEntry>
|
|
197
|
+
</BuildActionEntries>
|
|
198
|
+
</BuildAction>
|
|
199
|
+
<TestAction
|
|
200
|
+
buildConfiguration = "Debug"
|
|
201
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
202
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
203
|
+
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
204
|
+
shouldAutocreateTestPlan = "YES">
|
|
205
|
+
<Testables>
|
|
206
|
+
<TestableReference
|
|
207
|
+
skipped = "NO"
|
|
208
|
+
parallelizable = "YES">
|
|
209
|
+
${reference('tests-target', `${name}Tests.xctest`)}
|
|
210
|
+
</TestableReference>
|
|
211
|
+
</Testables>
|
|
212
|
+
</TestAction>
|
|
213
|
+
<LaunchAction
|
|
214
|
+
buildConfiguration = "Debug"
|
|
215
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
216
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
217
|
+
launchStyle = "0"
|
|
218
|
+
useCustomWorkingDirectory = "NO"
|
|
219
|
+
ignoresPersistentStateOnLaunch = "NO"
|
|
220
|
+
debugDocumentVersioning = "YES"
|
|
221
|
+
debugServiceExtension = "internal"
|
|
222
|
+
allowLocationSimulation = "YES">
|
|
223
|
+
<BuildableProductRunnable
|
|
224
|
+
runnableDebuggingMode = "0">
|
|
225
|
+
${app}
|
|
226
|
+
</BuildableProductRunnable>
|
|
227
|
+
</LaunchAction>
|
|
228
|
+
<ProfileAction
|
|
229
|
+
buildConfiguration = "Release"
|
|
230
|
+
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
231
|
+
savedToolIdentifier = ""
|
|
232
|
+
useCustomWorkingDirectory = "NO"
|
|
233
|
+
debugDocumentVersioning = "YES">
|
|
234
|
+
<BuildableProductRunnable
|
|
235
|
+
runnableDebuggingMode = "0">
|
|
236
|
+
${app}
|
|
237
|
+
</BuildableProductRunnable>
|
|
238
|
+
</ProfileAction>
|
|
239
|
+
<AnalyzeAction
|
|
240
|
+
buildConfiguration = "Debug">
|
|
241
|
+
</AnalyzeAction>
|
|
242
|
+
<ArchiveAction
|
|
243
|
+
buildConfiguration = "Release"
|
|
244
|
+
revealArchiveInOrganizer = "YES">
|
|
245
|
+
</ArchiveAction>
|
|
246
|
+
</Scheme>
|
|
247
|
+
`;
|
|
248
|
+
}
|
|
249
|
+
/** A pbxproj object id: 24 hex digits, stable for a name and role. */
|
|
250
|
+
function objectId(name, role) {
|
|
251
|
+
return createHash('sha1').update(`${name}/${role}`).digest('hex').slice(0, 24).toUpperCase();
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Xcode 16's iOS App template with "Include Tests" (objectVersion 77,
|
|
255
|
+
* synchronized root groups) without its UI tests, named `name`: the app
|
|
256
|
+
* target and `<name>Tests`, a unit-test bundle hosted by the app.
|
|
257
|
+
*/
|
|
258
|
+
export function pbxproj(name, bundleId) {
|
|
259
|
+
const id = (role) => objectId(name, role);
|
|
260
|
+
const app = id('product');
|
|
261
|
+
const folder = id('folder');
|
|
262
|
+
const frameworks = id('frameworks');
|
|
263
|
+
const tests = `${name}Tests`;
|
|
264
|
+
const testBundle = id('tests-product');
|
|
265
|
+
const testFolder = id('tests-folder');
|
|
266
|
+
const testFrameworks = id('tests-frameworks');
|
|
267
|
+
const testTarget = id('tests-target');
|
|
268
|
+
const testConfigs = id('tests-configs');
|
|
269
|
+
const testSources = id('tests-sources');
|
|
270
|
+
const testResources = id('tests-resources');
|
|
271
|
+
const testDebug = id('tests-debug');
|
|
272
|
+
const testRelease = id('tests-release');
|
|
273
|
+
const testDependency = id('tests-dependency');
|
|
274
|
+
const testProxy = id('tests-proxy');
|
|
275
|
+
const mainGroup = id('main-group');
|
|
276
|
+
const products = id('products');
|
|
277
|
+
const target = id('target');
|
|
278
|
+
const targetConfigs = id('target-configs');
|
|
279
|
+
const sources = id('sources');
|
|
280
|
+
const resources = id('resources');
|
|
281
|
+
const project = id('project');
|
|
282
|
+
const projectConfigs = id('project-configs');
|
|
283
|
+
const projectDebug = id('project-debug');
|
|
284
|
+
const projectRelease = id('project-release');
|
|
285
|
+
const targetDebug = id('target-debug');
|
|
286
|
+
const targetRelease = id('target-release');
|
|
287
|
+
const quoted = (value) => (/^[A-Za-z0-9_./]+$/.test(value) ? value : JSON.stringify(value));
|
|
288
|
+
const projectSettings = (debug) => {
|
|
289
|
+
const settings = [
|
|
290
|
+
['ALWAYS_SEARCH_USER_PATHS', 'NO'],
|
|
291
|
+
['ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS', 'YES'],
|
|
292
|
+
['CLANG_ANALYZER_NONNULL', 'YES'],
|
|
293
|
+
['CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION', 'YES_AGGRESSIVE'],
|
|
294
|
+
['CLANG_CXX_LANGUAGE_STANDARD', '"gnu++20"'],
|
|
295
|
+
['CLANG_ENABLE_MODULES', 'YES'],
|
|
296
|
+
['CLANG_ENABLE_OBJC_ARC', 'YES'],
|
|
297
|
+
['CLANG_ENABLE_OBJC_WEAK', 'YES'],
|
|
298
|
+
['CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING', 'YES'],
|
|
299
|
+
['CLANG_WARN_BOOL_CONVERSION', 'YES'],
|
|
300
|
+
['CLANG_WARN_COMMA', 'YES'],
|
|
301
|
+
['CLANG_WARN_CONSTANT_CONVERSION', 'YES'],
|
|
302
|
+
['CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS', 'YES'],
|
|
303
|
+
['CLANG_WARN_DIRECT_OBJC_ISA_USAGE', 'YES_ERROR'],
|
|
304
|
+
['CLANG_WARN_DOCUMENTATION_COMMENTS', 'YES'],
|
|
305
|
+
['CLANG_WARN_EMPTY_BODY', 'YES'],
|
|
306
|
+
['CLANG_WARN_ENUM_CONVERSION', 'YES'],
|
|
307
|
+
['CLANG_WARN_INFINITE_RECURSION', 'YES'],
|
|
308
|
+
['CLANG_WARN_INT_CONVERSION', 'YES'],
|
|
309
|
+
['CLANG_WARN_NON_LITERAL_NULL_CONVERSION', 'YES'],
|
|
310
|
+
['CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF', 'YES'],
|
|
311
|
+
['CLANG_WARN_OBJC_LITERAL_CONVERSION', 'YES'],
|
|
312
|
+
['CLANG_WARN_OBJC_ROOT_CLASS', 'YES_ERROR'],
|
|
313
|
+
['CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER', 'YES'],
|
|
314
|
+
['CLANG_WARN_RANGE_LOOP_ANALYSIS', 'YES'],
|
|
315
|
+
['CLANG_WARN_STRICT_PROTOTYPES', 'YES'],
|
|
316
|
+
['CLANG_WARN_SUSPICIOUS_MOVE', 'YES'],
|
|
317
|
+
['CLANG_WARN_UNGUARDED_AVAILABILITY', 'YES_AGGRESSIVE'],
|
|
318
|
+
['CLANG_WARN_UNREACHABLE_CODE', 'YES'],
|
|
319
|
+
['CLANG_WARN__DUPLICATE_METHOD_CALL', 'YES'],
|
|
320
|
+
['COPY_PHASE_STRIP', 'NO'],
|
|
321
|
+
['DEBUG_INFORMATION_FORMAT', debug ? 'dwarf' : '"dwarf-with-dsym"'],
|
|
322
|
+
...(debug ? [] : [['ENABLE_NS_ASSERTIONS', 'NO']]),
|
|
323
|
+
['ENABLE_STRICT_OBJC_MSGSEND', 'YES'],
|
|
324
|
+
...(debug ? [['ENABLE_TESTABILITY', 'YES']] : []),
|
|
325
|
+
['ENABLE_USER_SCRIPT_SANDBOXING', 'YES'],
|
|
326
|
+
['GCC_C_LANGUAGE_STANDARD', 'gnu17'],
|
|
327
|
+
...(debug ? [['GCC_DYNAMIC_NO_PIC', 'NO']] : []),
|
|
328
|
+
['GCC_NO_COMMON_BLOCKS', 'YES'],
|
|
329
|
+
...(debug
|
|
330
|
+
? [
|
|
331
|
+
['GCC_OPTIMIZATION_LEVEL', '0'],
|
|
332
|
+
['GCC_PREPROCESSOR_DEFINITIONS', '(\n\t\t\t\t\t"DEBUG=1",\n\t\t\t\t\t"$(inherited)",\n\t\t\t\t)'],
|
|
333
|
+
]
|
|
334
|
+
: []),
|
|
335
|
+
['GCC_WARN_64_TO_32_BIT_CONVERSION', 'YES'],
|
|
336
|
+
['GCC_WARN_ABOUT_RETURN_TYPE', 'YES_ERROR'],
|
|
337
|
+
['GCC_WARN_UNDECLARED_SELECTOR', 'YES'],
|
|
338
|
+
['GCC_WARN_UNINITIALIZED_AUTOS', 'YES_AGGRESSIVE'],
|
|
339
|
+
['GCC_WARN_UNUSED_FUNCTION', 'YES'],
|
|
340
|
+
['GCC_WARN_UNUSED_VARIABLE', 'YES'],
|
|
341
|
+
['IPHONEOS_DEPLOYMENT_TARGET', '18.0'],
|
|
342
|
+
['LOCALIZATION_PREFERS_STRING_CATALOGS', 'YES'],
|
|
343
|
+
['MTL_ENABLE_DEBUG_INFO', debug ? 'INCLUDE_SOURCE' : 'NO'],
|
|
344
|
+
['MTL_FAST_MATH', 'YES'],
|
|
345
|
+
...(debug ? [['ONLY_ACTIVE_ARCH', 'YES']] : []),
|
|
346
|
+
['SDKROOT', 'iphoneos'],
|
|
347
|
+
...(debug
|
|
348
|
+
? [
|
|
349
|
+
['SWIFT_ACTIVE_COMPILATION_CONDITIONS', '"DEBUG $(inherited)"'],
|
|
350
|
+
['SWIFT_OPTIMIZATION_LEVEL', '"-Onone"'],
|
|
351
|
+
]
|
|
352
|
+
: [
|
|
353
|
+
['SWIFT_COMPILATION_MODE', 'wholemodule'],
|
|
354
|
+
['VALIDATE_PRODUCT', 'YES'],
|
|
355
|
+
]),
|
|
356
|
+
];
|
|
357
|
+
return settings.map(([key, value]) => `\t\t\t\t${key} = ${value};`).join('\n');
|
|
358
|
+
};
|
|
359
|
+
const targetSettings = [
|
|
360
|
+
['ASSETCATALOG_COMPILER_APPICON_NAME', 'AppIcon'],
|
|
361
|
+
['ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME', 'AccentColor'],
|
|
362
|
+
['CODE_SIGN_STYLE', 'Automatic'],
|
|
363
|
+
['CURRENT_PROJECT_VERSION', '1'],
|
|
364
|
+
['ENABLE_PREVIEWS', 'YES'],
|
|
365
|
+
['GENERATE_INFOPLIST_FILE', 'YES'],
|
|
366
|
+
['INFOPLIST_KEY_CFBundleDisplayName', quoted(name)],
|
|
367
|
+
['INFOPLIST_KEY_UIApplicationSceneManifest_Generation', 'YES'],
|
|
368
|
+
['INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents', 'YES'],
|
|
369
|
+
['INFOPLIST_KEY_UILaunchScreen_Generation', 'YES'],
|
|
370
|
+
['INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad', '"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"'],
|
|
371
|
+
['INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone', '"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"'],
|
|
372
|
+
['LD_RUNPATH_SEARCH_PATHS', '(\n\t\t\t\t\t"$(inherited)",\n\t\t\t\t\t"@executable_path/Frameworks",\n\t\t\t\t)'],
|
|
373
|
+
['MARKETING_VERSION', '1.0'],
|
|
374
|
+
['PRODUCT_BUNDLE_IDENTIFIER', quoted(bundleId)],
|
|
375
|
+
['PRODUCT_NAME', '"$(TARGET_NAME)"'],
|
|
376
|
+
['SWIFT_EMIT_LOC_STRINGS', 'YES'],
|
|
377
|
+
['SWIFT_VERSION', '5.0'],
|
|
378
|
+
['TARGETED_DEVICE_FAMILY', '"1,2"'],
|
|
379
|
+
]
|
|
380
|
+
.map(([key, value]) => `\t\t\t\t${key} = ${value};`)
|
|
381
|
+
.join('\n');
|
|
382
|
+
// The test bundle loads into the app (TEST_HOST), so `@testable import` sees its internals.
|
|
383
|
+
const testSettings = [
|
|
384
|
+
['BUNDLE_LOADER', '"$(TEST_HOST)"'],
|
|
385
|
+
['CODE_SIGN_STYLE', 'Automatic'],
|
|
386
|
+
['CURRENT_PROJECT_VERSION', '1'],
|
|
387
|
+
['GENERATE_INFOPLIST_FILE', 'YES'],
|
|
388
|
+
['MARKETING_VERSION', '1.0'],
|
|
389
|
+
['PRODUCT_BUNDLE_IDENTIFIER', quoted(`${bundleId}Tests`)],
|
|
390
|
+
['PRODUCT_NAME', '"$(TARGET_NAME)"'],
|
|
391
|
+
['SWIFT_EMIT_LOC_STRINGS', 'NO'],
|
|
392
|
+
['SWIFT_VERSION', '5.0'],
|
|
393
|
+
['TARGETED_DEVICE_FAMILY', '"1,2"'],
|
|
394
|
+
['TEST_HOST', `"$(BUILT_PRODUCTS_DIR)/${name}.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/${name}"`],
|
|
395
|
+
]
|
|
396
|
+
.map(([key, value]) => `\t\t\t\t${key} = ${value};`)
|
|
397
|
+
.join('\n');
|
|
398
|
+
return `// !$*UTF8*$!
|
|
399
|
+
{
|
|
400
|
+
archiveVersion = 1;
|
|
401
|
+
classes = {
|
|
402
|
+
};
|
|
403
|
+
objectVersion = 77;
|
|
404
|
+
objects = {
|
|
405
|
+
|
|
406
|
+
/* Begin PBXContainerItemProxy section */
|
|
407
|
+
${testProxy} /* PBXContainerItemProxy */ = {
|
|
408
|
+
isa = PBXContainerItemProxy;
|
|
409
|
+
containerPortal = ${project} /* Project object */;
|
|
410
|
+
proxyType = 1;
|
|
411
|
+
remoteGlobalIDString = ${target};
|
|
412
|
+
remoteInfo = ${name};
|
|
413
|
+
};
|
|
414
|
+
/* End PBXContainerItemProxy section */
|
|
415
|
+
|
|
416
|
+
/* Begin PBXFileReference section */
|
|
417
|
+
${app} /* ${name}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ${name}.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
418
|
+
${testBundle} /* ${tests}.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ${tests}.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
419
|
+
/* End PBXFileReference section */
|
|
420
|
+
|
|
421
|
+
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
|
422
|
+
${folder} /* ${name} */ = {
|
|
423
|
+
isa = PBXFileSystemSynchronizedRootGroup;
|
|
424
|
+
path = ${name};
|
|
425
|
+
sourceTree = "<group>";
|
|
426
|
+
};
|
|
427
|
+
${testFolder} /* ${tests} */ = {
|
|
428
|
+
isa = PBXFileSystemSynchronizedRootGroup;
|
|
429
|
+
path = ${tests};
|
|
430
|
+
sourceTree = "<group>";
|
|
431
|
+
};
|
|
432
|
+
/* End PBXFileSystemSynchronizedRootGroup section */
|
|
433
|
+
|
|
434
|
+
/* Begin PBXFrameworksBuildPhase section */
|
|
435
|
+
${frameworks} /* Frameworks */ = {
|
|
436
|
+
isa = PBXFrameworksBuildPhase;
|
|
437
|
+
buildActionMask = 2147483647;
|
|
438
|
+
files = (
|
|
439
|
+
);
|
|
440
|
+
runOnlyForDeploymentPostprocessing = 0;
|
|
441
|
+
};
|
|
442
|
+
${testFrameworks} /* Frameworks */ = {
|
|
443
|
+
isa = PBXFrameworksBuildPhase;
|
|
444
|
+
buildActionMask = 2147483647;
|
|
445
|
+
files = (
|
|
446
|
+
);
|
|
447
|
+
runOnlyForDeploymentPostprocessing = 0;
|
|
448
|
+
};
|
|
449
|
+
/* End PBXFrameworksBuildPhase section */
|
|
450
|
+
|
|
451
|
+
/* Begin PBXGroup section */
|
|
452
|
+
${mainGroup} = {
|
|
453
|
+
isa = PBXGroup;
|
|
454
|
+
children = (
|
|
455
|
+
${folder} /* ${name} */,
|
|
456
|
+
${testFolder} /* ${tests} */,
|
|
457
|
+
${products} /* Products */,
|
|
458
|
+
);
|
|
459
|
+
sourceTree = "<group>";
|
|
460
|
+
};
|
|
461
|
+
${products} /* Products */ = {
|
|
462
|
+
isa = PBXGroup;
|
|
463
|
+
children = (
|
|
464
|
+
${app} /* ${name}.app */,
|
|
465
|
+
${testBundle} /* ${tests}.xctest */,
|
|
466
|
+
);
|
|
467
|
+
name = Products;
|
|
468
|
+
sourceTree = "<group>";
|
|
469
|
+
};
|
|
470
|
+
/* End PBXGroup section */
|
|
471
|
+
|
|
472
|
+
/* Begin PBXNativeTarget section */
|
|
473
|
+
${target} /* ${name} */ = {
|
|
474
|
+
isa = PBXNativeTarget;
|
|
475
|
+
buildConfigurationList = ${targetConfigs} /* Build configuration list for PBXNativeTarget "${name}" */;
|
|
476
|
+
buildPhases = (
|
|
477
|
+
${sources} /* Sources */,
|
|
478
|
+
${frameworks} /* Frameworks */,
|
|
479
|
+
${resources} /* Resources */,
|
|
480
|
+
);
|
|
481
|
+
buildRules = (
|
|
482
|
+
);
|
|
483
|
+
dependencies = (
|
|
484
|
+
);
|
|
485
|
+
fileSystemSynchronizedGroups = (
|
|
486
|
+
${folder} /* ${name} */,
|
|
487
|
+
);
|
|
488
|
+
name = ${name};
|
|
489
|
+
packageProductDependencies = (
|
|
490
|
+
);
|
|
491
|
+
productName = ${name};
|
|
492
|
+
productReference = ${app} /* ${name}.app */;
|
|
493
|
+
productType = "com.apple.product-type.application";
|
|
494
|
+
};
|
|
495
|
+
${testTarget} /* ${tests} */ = {
|
|
496
|
+
isa = PBXNativeTarget;
|
|
497
|
+
buildConfigurationList = ${testConfigs} /* Build configuration list for PBXNativeTarget "${tests}" */;
|
|
498
|
+
buildPhases = (
|
|
499
|
+
${testSources} /* Sources */,
|
|
500
|
+
${testFrameworks} /* Frameworks */,
|
|
501
|
+
${testResources} /* Resources */,
|
|
502
|
+
);
|
|
503
|
+
buildRules = (
|
|
504
|
+
);
|
|
505
|
+
dependencies = (
|
|
506
|
+
${testDependency} /* PBXTargetDependency */,
|
|
507
|
+
);
|
|
508
|
+
fileSystemSynchronizedGroups = (
|
|
509
|
+
${testFolder} /* ${tests} */,
|
|
510
|
+
);
|
|
511
|
+
name = ${tests};
|
|
512
|
+
packageProductDependencies = (
|
|
513
|
+
);
|
|
514
|
+
productName = ${tests};
|
|
515
|
+
productReference = ${testBundle} /* ${tests}.xctest */;
|
|
516
|
+
productType = "com.apple.product-type.bundle.unit-test";
|
|
517
|
+
};
|
|
518
|
+
/* End PBXNativeTarget section */
|
|
519
|
+
|
|
520
|
+
/* Begin PBXProject section */
|
|
521
|
+
${project} /* Project object */ = {
|
|
522
|
+
isa = PBXProject;
|
|
523
|
+
attributes = {
|
|
524
|
+
BuildIndependentTargetsInParallel = 1;
|
|
525
|
+
LastSwiftUpdateCheck = 1600;
|
|
526
|
+
LastUpgradeCheck = 1600;
|
|
527
|
+
TargetAttributes = {
|
|
528
|
+
${target} = {
|
|
529
|
+
CreatedOnToolsVersion = 16.0;
|
|
530
|
+
};
|
|
531
|
+
${testTarget} = {
|
|
532
|
+
CreatedOnToolsVersion = 16.0;
|
|
533
|
+
TestTargetID = ${target};
|
|
534
|
+
};
|
|
535
|
+
};
|
|
536
|
+
};
|
|
537
|
+
buildConfigurationList = ${projectConfigs} /* Build configuration list for PBXProject "${name}" */;
|
|
538
|
+
developmentRegion = en;
|
|
539
|
+
hasScannedForEncodings = 0;
|
|
540
|
+
knownRegions = (
|
|
541
|
+
en,
|
|
542
|
+
Base,
|
|
543
|
+
);
|
|
544
|
+
mainGroup = ${mainGroup};
|
|
545
|
+
minimizedProjectReferenceProxies = 1;
|
|
546
|
+
preferredProjectObjectVersion = 77;
|
|
547
|
+
productRefGroup = ${products} /* Products */;
|
|
548
|
+
projectDirPath = "";
|
|
549
|
+
projectRoot = "";
|
|
550
|
+
targets = (
|
|
551
|
+
${target} /* ${name} */,
|
|
552
|
+
${testTarget} /* ${tests} */,
|
|
553
|
+
);
|
|
554
|
+
};
|
|
555
|
+
/* End PBXProject section */
|
|
556
|
+
|
|
557
|
+
/* Begin PBXResourcesBuildPhase section */
|
|
558
|
+
${resources} /* Resources */ = {
|
|
559
|
+
isa = PBXResourcesBuildPhase;
|
|
560
|
+
buildActionMask = 2147483647;
|
|
561
|
+
files = (
|
|
562
|
+
);
|
|
563
|
+
runOnlyForDeploymentPostprocessing = 0;
|
|
564
|
+
};
|
|
565
|
+
${testResources} /* Resources */ = {
|
|
566
|
+
isa = PBXResourcesBuildPhase;
|
|
567
|
+
buildActionMask = 2147483647;
|
|
568
|
+
files = (
|
|
569
|
+
);
|
|
570
|
+
runOnlyForDeploymentPostprocessing = 0;
|
|
571
|
+
};
|
|
572
|
+
/* End PBXResourcesBuildPhase section */
|
|
573
|
+
|
|
574
|
+
/* Begin PBXSourcesBuildPhase section */
|
|
575
|
+
${sources} /* Sources */ = {
|
|
576
|
+
isa = PBXSourcesBuildPhase;
|
|
577
|
+
buildActionMask = 2147483647;
|
|
578
|
+
files = (
|
|
579
|
+
);
|
|
580
|
+
runOnlyForDeploymentPostprocessing = 0;
|
|
581
|
+
};
|
|
582
|
+
${testSources} /* Sources */ = {
|
|
583
|
+
isa = PBXSourcesBuildPhase;
|
|
584
|
+
buildActionMask = 2147483647;
|
|
585
|
+
files = (
|
|
586
|
+
);
|
|
587
|
+
runOnlyForDeploymentPostprocessing = 0;
|
|
588
|
+
};
|
|
589
|
+
/* End PBXSourcesBuildPhase section */
|
|
590
|
+
|
|
591
|
+
/* Begin PBXTargetDependency section */
|
|
592
|
+
${testDependency} /* PBXTargetDependency */ = {
|
|
593
|
+
isa = PBXTargetDependency;
|
|
594
|
+
target = ${target} /* ${name} */;
|
|
595
|
+
targetProxy = ${testProxy} /* PBXContainerItemProxy */;
|
|
596
|
+
};
|
|
597
|
+
/* End PBXTargetDependency section */
|
|
598
|
+
|
|
599
|
+
/* Begin XCBuildConfiguration section */
|
|
600
|
+
${projectDebug} /* Debug */ = {
|
|
601
|
+
isa = XCBuildConfiguration;
|
|
602
|
+
buildSettings = {
|
|
603
|
+
${projectSettings(true)}
|
|
604
|
+
};
|
|
605
|
+
name = Debug;
|
|
606
|
+
};
|
|
607
|
+
${projectRelease} /* Release */ = {
|
|
608
|
+
isa = XCBuildConfiguration;
|
|
609
|
+
buildSettings = {
|
|
610
|
+
${projectSettings(false)}
|
|
611
|
+
};
|
|
612
|
+
name = Release;
|
|
613
|
+
};
|
|
614
|
+
${targetDebug} /* Debug */ = {
|
|
615
|
+
isa = XCBuildConfiguration;
|
|
616
|
+
buildSettings = {
|
|
617
|
+
${targetSettings}
|
|
618
|
+
};
|
|
619
|
+
name = Debug;
|
|
620
|
+
};
|
|
621
|
+
${targetRelease} /* Release */ = {
|
|
622
|
+
isa = XCBuildConfiguration;
|
|
623
|
+
buildSettings = {
|
|
624
|
+
${targetSettings}
|
|
625
|
+
};
|
|
626
|
+
name = Release;
|
|
627
|
+
};
|
|
628
|
+
${testDebug} /* Debug */ = {
|
|
629
|
+
isa = XCBuildConfiguration;
|
|
630
|
+
buildSettings = {
|
|
631
|
+
${testSettings}
|
|
632
|
+
};
|
|
633
|
+
name = Debug;
|
|
634
|
+
};
|
|
635
|
+
${testRelease} /* Release */ = {
|
|
636
|
+
isa = XCBuildConfiguration;
|
|
637
|
+
buildSettings = {
|
|
638
|
+
${testSettings}
|
|
639
|
+
};
|
|
640
|
+
name = Release;
|
|
641
|
+
};
|
|
642
|
+
/* End XCBuildConfiguration section */
|
|
643
|
+
|
|
644
|
+
/* Begin XCConfigurationList section */
|
|
645
|
+
${projectConfigs} /* Build configuration list for PBXProject "${name}" */ = {
|
|
646
|
+
isa = XCConfigurationList;
|
|
647
|
+
buildConfigurations = (
|
|
648
|
+
${projectDebug} /* Debug */,
|
|
649
|
+
${projectRelease} /* Release */,
|
|
650
|
+
);
|
|
651
|
+
defaultConfigurationIsVisible = 0;
|
|
652
|
+
defaultConfigurationName = Release;
|
|
653
|
+
};
|
|
654
|
+
${targetConfigs} /* Build configuration list for PBXNativeTarget "${name}" */ = {
|
|
655
|
+
isa = XCConfigurationList;
|
|
656
|
+
buildConfigurations = (
|
|
657
|
+
${targetDebug} /* Debug */,
|
|
658
|
+
${targetRelease} /* Release */,
|
|
659
|
+
);
|
|
660
|
+
defaultConfigurationIsVisible = 0;
|
|
661
|
+
defaultConfigurationName = Release;
|
|
662
|
+
};
|
|
663
|
+
${testConfigs} /* Build configuration list for PBXNativeTarget "${tests}" */ = {
|
|
664
|
+
isa = XCConfigurationList;
|
|
665
|
+
buildConfigurations = (
|
|
666
|
+
${testDebug} /* Debug */,
|
|
667
|
+
${testRelease} /* Release */,
|
|
668
|
+
);
|
|
669
|
+
defaultConfigurationIsVisible = 0;
|
|
670
|
+
defaultConfigurationName = Release;
|
|
671
|
+
};
|
|
672
|
+
/* End XCConfigurationList section */
|
|
673
|
+
};
|
|
674
|
+
rootObject = ${project} /* Project object */;
|
|
675
|
+
}
|
|
676
|
+
`;
|
|
677
|
+
}
|
|
678
|
+
//# sourceMappingURL=template.js.map
|