@yahoo/uds 0.1.12 → 0.1.13
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/cli/README.md +135 -0
- package/cli/commands/config/config.ts +10 -0
- package/cli/commands/config/sync.ts +22 -0
- package/cli/commands/expo/_setup.ts +260 -0
- package/cli/commands/expo/build.ts +15 -0
- package/cli/commands/expo/dev.ts +79 -0
- package/cli/commands/expo/expo.ts +23 -0
- package/cli/commands/expo/launch.ts +15 -0
- package/cli/commands/expo/update.ts +16 -0
- package/cli/commands/nextjs/dev.ts +17 -0
- package/cli/commands/nextjs/nextjs.ts +10 -0
- package/cli/commands/uds.ts +10 -0
- package/cli/commands/version.ts +11 -0
- package/cli/env.d.ts +15 -0
- package/cli/eslint.config.mjs +8 -0
- package/cli/tsconfig.json +10 -0
- package/cli/uds-cli +7 -0
- package/cli/utils/configWorker.ts +9 -0
- package/cli/utils/getCommandHelp.ts +65 -0
- package/cli/utils/setupConfigWorker.ts +81 -0
- package/cli/utils/sortKeys.ts +27 -0
- package/cli/utils/types.ts +13 -0
- package/dist/{chunk-JKZI2WLD.js → chunk-AWTLI4D3.js} +1 -1
- package/dist/chunk-D4K3CXV6.js +0 -0
- package/dist/{chunk-Z34QGHWU.js → chunk-MBOOJIH7.js} +1 -1
- package/dist/chunk-MFA2Y7DA.js +1 -0
- package/dist/chunk-P7GR6E3K.js +1 -0
- package/dist/chunk-PQBOZFJV.js +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +7 -40
- package/dist/index.d.ts +7 -40
- package/dist/index.js +1 -1
- package/dist/{index.native-VVqy3X9H.d.cts → index.native-3ww4C4UV.d.cts} +1 -1
- package/dist/{index.native-DzfcCYUh.d.ts → index.native-9kYJrUPa.d.ts} +1 -1
- package/dist/index.native.cjs +1 -0
- package/dist/index.native.d.cts +1493 -0
- package/dist/index.native.d.ts +1493 -0
- package/dist/index.native.js +1 -0
- package/dist/tailwindPlugin.cjs +1 -1
- package/dist/tailwindPlugin.d.cts +1 -1
- package/dist/tailwindPlugin.d.ts +1 -1
- package/dist/tailwindPlugin.js +1 -1
- package/dist/tokens/index.cjs +1 -1
- package/dist/tokens/index.d.cts +3 -3
- package/dist/tokens/index.d.ts +3 -3
- package/dist/tokens/index.js +1 -1
- package/dist/tokens/index.native.cjs +1 -1
- package/dist/tokens/index.native.d.cts +2 -2
- package/dist/tokens/index.native.d.ts +2 -2
- package/dist/tokens/index.native.js +1 -1
- package/dist/tokens/parseTokens.cjs +1 -1
- package/dist/tokens/parseTokens.d.cts +1 -1
- package/dist/tokens/parseTokens.d.ts +1 -1
- package/dist/tokens/parseTokens.js +1 -1
- package/dist/tokens/parseTokens.native.d.cts +1 -1
- package/dist/tokens/parseTokens.native.d.ts +1 -1
- package/dist/tokens/parseTokens.native.js +1 -1
- package/dist/types-J4DLS6Xj.d.cts +38 -0
- package/dist/types-J4DLS6Xj.d.ts +38 -0
- package/dist/{types-VgTlNoi_.d.cts → types-hirL9Qk5.d.cts} +1 -0
- package/dist/{types-VgTlNoi_.d.ts → types-hirL9Qk5.d.ts} +1 -0
- package/fonts/mobile.cjs +29 -0
- package/fonts/mobile.d.ts +3 -0
- package/fonts/yahoo-icons.ttf +0 -0
- package/fonts/yahoo-sans-beta-bold.otf +0 -0
- package/fonts/yahoo-sans-beta-medium.otf +0 -0
- package/fonts/yahoo-sans-beta-regular.otf +0 -0
- package/fonts/yahoo-sans-black.otf +0 -0
- package/fonts/yahoo-sans-bold.otf +0 -0
- package/fonts/yahoo-sans-condensed-black.otf +0 -0
- package/fonts/yahoo-sans-condensed-bold.otf +0 -0
- package/fonts/yahoo-sans-condensed-light.otf +0 -0
- package/fonts/yahoo-sans-condensed-medium.otf +0 -0
- package/fonts/yahoo-sans-condensed-regular.otf +0 -0
- package/fonts/yahoo-sans-extrabold.otf +0 -0
- package/fonts/yahoo-sans-extralight.otf +0 -0
- package/fonts/yahoo-sans-italic.otf +0 -0
- package/fonts/yahoo-sans-light.otf +0 -0
- package/fonts/yahoo-sans-medium.otf +0 -0
- package/fonts/yahoo-sans-regular.otf +0 -0
- package/fonts/yahoo-sans-semibold.otf +0 -0
- package/fonts/yahoo-serif-display-black.otf +0 -0
- package/fonts/yahoo-serif-display-bold.otf +0 -0
- package/fonts/yahoo-serif-display-extrabold.otf +0 -0
- package/fonts/yahoo-serif-display-light.otf +0 -0
- package/fonts/yahoo-serif-display-regular.otf +0 -0
- package/fonts/yahoo-serif-text-bold.otf +0 -0
- package/fonts/yahoo-serif-text-italic.otf +0 -0
- package/fonts/yahoo-serif-text-regular.otf +0 -0
- package/package.json +122 -45
- package/bin/uds +0 -0
- package/dist/chunk-7FQGDIJ2.js +0 -1
package/cli/README.md
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
# UDS ClI
|
2
|
+
|
3
|
+
We leverage Bluebun, which is a CLI framework inspired by [Gluegun](https://github.com/infinitered/gluegun), but specifically designed to be used with [Bun](https://bun.sh), the new JS runtime.
|
4
|
+
|
5
|
+
Bluebun relies on Bun APIs and is designed to be extremely fast, with no-dependencies.
|
6
|
+
|
7
|
+
# Standalone executable
|
8
|
+
|
9
|
+
We use Bun to build our standalone executable. See [Bun build docs](https://bun.sh/docs/bundler/executables) for more details. The uds package.json's `build:cli` script handles building the CLI. The bin is output to the `dist/uds` binary file and this path is defined in the package.json's bin field.
|
10
|
+
|
11
|
+
# Commands
|
12
|
+
|
13
|
+
## Command structure
|
14
|
+
|
15
|
+
Commands are organized in a tree structure. The root command is the name of the CLI (uds), and then we can have subcommands under that, and subcommands under those, and so on.
|
16
|
+
|
17
|
+
For example, a command structure might look like this:
|
18
|
+
|
19
|
+
```
|
20
|
+
cli/
|
21
|
+
commands/
|
22
|
+
pizza.ts # pizza
|
23
|
+
help.ts # pizza help
|
24
|
+
bake/
|
25
|
+
bake.ts # pizza bake
|
26
|
+
cheese.ts # pizza bake cheese
|
27
|
+
pepperoni.ts # pizza bake pepperoni
|
28
|
+
```
|
29
|
+
|
30
|
+
## Command files
|
31
|
+
|
32
|
+
Commands are exported as defaults from each command file. They look like this:
|
33
|
+
|
34
|
+
```typescript
|
35
|
+
import { type Props } from 'bluebun';
|
36
|
+
|
37
|
+
export default {
|
38
|
+
name: 'bake',
|
39
|
+
description: 'Bake a pizza',
|
40
|
+
alias: ['b'],
|
41
|
+
run: async (props: Props) => {
|
42
|
+
// bake it!
|
43
|
+
},
|
44
|
+
};
|
45
|
+
```
|
46
|
+
|
47
|
+
## Command properties
|
48
|
+
|
49
|
+
Commands have the following properties:
|
50
|
+
|
51
|
+
- `name` - the name of the command
|
52
|
+
- `description` - a description of the command for the automatic help system
|
53
|
+
- `alias` - an array of aliases for the command (can also be a single string)
|
54
|
+
- `run` - the function that is run when the command is run, usually `async`
|
55
|
+
|
56
|
+
## Props
|
57
|
+
|
58
|
+
The `run` function is passed a `Props` object. This object contains the command path, the arguments, and the options, as well as a few other useful things.
|
59
|
+
|
60
|
+
Here are the properties available on the `props` object if we were to run `uds bake cheese convection --sliced --temp=400 --time 30`:
|
61
|
+
|
62
|
+
- `name` - the name of the CLI (uds)
|
63
|
+
- `cliPath` - the path to the CLI (./uds-cli)
|
64
|
+
- `argv` - the raw arguments passed to the CLI (e.g. `["/bin/bun", "/bin/uds", "bake", "cheese", "convection", "--sliced", "--temp=400", "--time", "30"]`)
|
65
|
+
- `commandPath` - the path to the command that was run (e.g. `["bake", "cheese"]`)
|
66
|
+
- `arguments` - the positional arguments passed to the command (e.g. `["convection"]`)
|
67
|
+
- `options` - the options passed to the command (e.g. `{ sliced: true, temp: 400, time: 30 }`)
|
68
|
+
- `first` - the first argument passed to the command (e.g. `"convection"`)
|
69
|
+
- `second` - the second argument passed to the command (e.g. `undefined`)
|
70
|
+
- `third` - the third argument passed to the command (e.g. `undefined`)
|
71
|
+
|
72
|
+
Given these props, we might have a command that looks like this:
|
73
|
+
|
74
|
+
```typescript
|
75
|
+
import { type Props, spinStart, spinStop } from 'bluebun';
|
76
|
+
import { createPizza, slice } from './_pizza';
|
77
|
+
import { convectionBake, toasterBake, regularBake } from './_bakePizza';
|
78
|
+
|
79
|
+
export default {
|
80
|
+
name: 'bake',
|
81
|
+
description: 'Bake a pizza',
|
82
|
+
alias: ['b'],
|
83
|
+
run: async (props: Props) => {
|
84
|
+
const { first, second, third, options } = props;
|
85
|
+
|
86
|
+
const pizza = createPizza();
|
87
|
+
|
88
|
+
spinStart('Baking pizza...');
|
89
|
+
if (first === 'convection') {
|
90
|
+
await convectionBake(pizza, options.temp, options.time);
|
91
|
+
} else if (first === 'toaster') {
|
92
|
+
await toasterBake(pizza, options.temp, options.time);
|
93
|
+
} else {
|
94
|
+
await regularBake(pizza, options.temp, options.time);
|
95
|
+
}
|
96
|
+
spinStop('✅ Pizza baked!');
|
97
|
+
|
98
|
+
spinStart('Slicing pizza...');
|
99
|
+
if (options.sliced) {
|
100
|
+
await slice(pizza);
|
101
|
+
}
|
102
|
+
spinStop('✅ Pizza sliced!');
|
103
|
+
},
|
104
|
+
};
|
105
|
+
```
|
106
|
+
|
107
|
+
# Reference
|
108
|
+
|
109
|
+
Bluebun comes with a number of built-in utilities that are useful. They're all exported from `bluebun` directly, so you can import them like this:
|
110
|
+
|
111
|
+
```typescript
|
112
|
+
import { inputKey } from 'bluebun';
|
113
|
+
```
|
114
|
+
|
115
|
+
Each of the following docs has usage examples and a Testing section that gives examples on how to write tests for them.
|
116
|
+
|
117
|
+
## CLI
|
118
|
+
|
119
|
+
- [run](https://github.com/jamonholmgren/bluebun/blob/main/docs/reference/run.md) - run the CLI and command
|
120
|
+
- [cli](https://github.com/jamonholmgren/bluebun/blob/main/docs/reference/cli.md) - start the CLI without running the command
|
121
|
+
- [commandHelp](https://github.com/jamonholmgren/bluebun/blob/main/docs/reference/commandHelp.md) - get a list of all commands and their descriptions
|
122
|
+
|
123
|
+
## User Interaction
|
124
|
+
|
125
|
+
- [ask](https://github.com/jamonholmgren/bluebun/blob/main/docs/reference/ask.md) - ask the user a question via a prompt
|
126
|
+
- [cursor](https://github.com/jamonholmgren/bluebun/blob/main/docs/reference/cursor.md) - manipulate the cursor
|
127
|
+
- [inputKey](https://github.com/jamonholmgren/bluebun/blob/main/docs/reference/inputKey.md) - wait for a single keypress
|
128
|
+
- [inputKeys](https://github.com/jamonholmgren/bluebun/blob/main/docs/reference/inputKeys.md) - wait for and handle multiple keypresses
|
129
|
+
|
130
|
+
## Output
|
131
|
+
|
132
|
+
- [print](https://github.com/jamonholmgren/bluebun/blob/main/docs/reference/print.md) - print a string to the terminal
|
133
|
+
- [spinner](https://github.com/jamonholmgren/bluebun/blob/main/docs/reference/spinner.md) - start and stop a spinner
|
134
|
+
- [progress](https://github.com/jamonholmgren/bluebun/blob/main/docs/reference/progress.md) - start, update, and stop a progress bar
|
135
|
+
- [styles and colors](https://github.com/jamonholmgren/bluebun/blob/main/docs/reference/styles.md) - style and colorize text
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { Props } from 'bluebun';
|
2
|
+
import { setupConfigWorker } from '../../utils/setupConfigWorker';
|
3
|
+
import { SyncOptions } from '../../utils/types';
|
4
|
+
|
5
|
+
interface SyncProps extends Props {
|
6
|
+
options: SyncOptions;
|
7
|
+
}
|
8
|
+
|
9
|
+
export default {
|
10
|
+
name: 'sync',
|
11
|
+
description: '🌈 Sync',
|
12
|
+
run: async ({ options }: SyncProps) => {
|
13
|
+
await setupConfigWorker({
|
14
|
+
...options,
|
15
|
+
onUpdate: ({ worker }) => {
|
16
|
+
if (!options.watch) {
|
17
|
+
worker.terminate();
|
18
|
+
}
|
19
|
+
},
|
20
|
+
});
|
21
|
+
},
|
22
|
+
};
|
@@ -0,0 +1,260 @@
|
|
1
|
+
import { EasJsonAccessor, EasJsonUtils, Platform } from '@expo/eas-json';
|
2
|
+
import { type Props, print } from 'bluebun';
|
3
|
+
import { $ } from 'bun';
|
4
|
+
|
5
|
+
export interface MobileProps extends Props {
|
6
|
+
options: {
|
7
|
+
profile: string;
|
8
|
+
platform: Platform.IOS | Platform.ANDROID;
|
9
|
+
jsEngine?: 'hermes' | 'jsc';
|
10
|
+
debug?: boolean;
|
11
|
+
};
|
12
|
+
}
|
13
|
+
|
14
|
+
async function needsBinary(lib: string) {
|
15
|
+
const whichLib = await $`which ${lib}`.text();
|
16
|
+
return whichLib.includes('not found');
|
17
|
+
}
|
18
|
+
|
19
|
+
async function needsBrewFormula(formula: string) {
|
20
|
+
return (await $`brew list --formula | grep ${formula} | wc -l`.text()).trim() === '0';
|
21
|
+
}
|
22
|
+
|
23
|
+
export async function setup({
|
24
|
+
props,
|
25
|
+
env: envOpts,
|
26
|
+
}: {
|
27
|
+
props: MobileProps;
|
28
|
+
env?: Partial<typeof Bun.env>;
|
29
|
+
}) {
|
30
|
+
const { profile, platform, jsEngine = 'hermes', debug = false } = props.options;
|
31
|
+
|
32
|
+
/* -------------------------------------------------------------------------- */
|
33
|
+
/* HOMEBREW SETUP */
|
34
|
+
/* -------------------------------------------------------------------------- */
|
35
|
+
const needsBrew = await needsBinary('brew');
|
36
|
+
if (needsBrew) {
|
37
|
+
console.log('Installing brew...');
|
38
|
+
await $`/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`;
|
39
|
+
console.log('Installing brew...Complete');
|
40
|
+
|
41
|
+
/**
|
42
|
+
* This portion of logic was ported from the homebrew installer script
|
43
|
+
* https://github.com/Homebrew/install/blob/master/install.sh#L153C5-L153C63.
|
44
|
+
* However, their script just alerts users to the fact that they need to add
|
45
|
+
* brew to their path, but doesn't do it for them. This logic attempts to do that
|
46
|
+
* so we can automatically proceed to the next steps of auto-installing
|
47
|
+
* the necessary dependencies for local development.
|
48
|
+
*/
|
49
|
+
const machineArch = await $`uname -m`.text();
|
50
|
+
const isLinux = (await $`uname`.text()) === 'Linux';
|
51
|
+
const shellType = await $`echo $SHELL`.text();
|
52
|
+
const homebrewPrefix = machineArch.includes('arm64') ? '/opt/homebrew' : '/usr/local';
|
53
|
+
let shellRcFile;
|
54
|
+
|
55
|
+
if (isLinux) {
|
56
|
+
shellRcFile = shellType.includes('zsh') ? '.zshrc' : '.bashrc';
|
57
|
+
} else {
|
58
|
+
shellRcFile = shellType.includes('zsh') ? '.zprofile' : '.bash_profile';
|
59
|
+
}
|
60
|
+
|
61
|
+
const shellRcPath = `${Bun.env.HOME}/${shellRcFile}`;
|
62
|
+
let shellRcContents = '';
|
63
|
+
try {
|
64
|
+
shellRcContents = await Bun.file(shellRcPath).text();
|
65
|
+
} catch (err) {
|
66
|
+
// Ignore if it doesn't exist. We create it below.
|
67
|
+
}
|
68
|
+
|
69
|
+
if (!shellRcContents.includes('homebrew')) {
|
70
|
+
console.log('Adding brew to $PATH...');
|
71
|
+
const newShellRcContents = `${shellRcContents}\neval "$(${homebrewPrefix}/bin/brew shellenv)"`;
|
72
|
+
await Bun.write(shellRcPath, newShellRcContents);
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
/* -------------------------------------------------------------------------- */
|
77
|
+
/* FASTLANE SETUP */
|
78
|
+
/* -------------------------------------------------------------------------- */
|
79
|
+
const needsFastlane = await needsBrewFormula('fastlane');
|
80
|
+
if (needsFastlane) {
|
81
|
+
console.log('Installing fastlane...');
|
82
|
+
await $`brew install fastlane`;
|
83
|
+
}
|
84
|
+
|
85
|
+
/* -------------------------------------------------------------------------- */
|
86
|
+
/* COCOAPODS SETUP */
|
87
|
+
/* -------------------------------------------------------------------------- */
|
88
|
+
const needsCocoapods = await needsBrewFormula('cocoapods');
|
89
|
+
if (needsCocoapods) {
|
90
|
+
console.log('Installing cocoapods...');
|
91
|
+
await $`brew install cocoapods`;
|
92
|
+
}
|
93
|
+
|
94
|
+
/* -------------------------------------------------------------------------- */
|
95
|
+
/* JAVA DEVELOPMENT KIT */
|
96
|
+
/* -------------------------------------------------------------------------- */
|
97
|
+
if (platform === 'android') {
|
98
|
+
const jdkPath = await $`brew info --cask zulu17`.text();
|
99
|
+
const needsJdk = jdkPath.includes('unavailable');
|
100
|
+
if (needsJdk) {
|
101
|
+
console.log('Installing Java Development Kit for Android...');
|
102
|
+
await $`brew install --cask zulu17`;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
/* -------------------------------------------------------------------------- */
|
107
|
+
/* EXPO SETUP */
|
108
|
+
/* -------------------------------------------------------------------------- */
|
109
|
+
const appDirectory = Bun.env.PWD;
|
110
|
+
const easJsonAccessor = EasJsonAccessor.fromProjectPath(appDirectory);
|
111
|
+
|
112
|
+
const easProfiles = await EasJsonUtils.getBuildProfileNamesAsync(easJsonAccessor);
|
113
|
+
|
114
|
+
if (!easProfiles.includes(profile)) {
|
115
|
+
const profileNames = easProfiles.join(', ');
|
116
|
+
const suggestion = `Please add one or use ${profileNames}.`;
|
117
|
+
|
118
|
+
if (!profile) {
|
119
|
+
print(`No profile name was provided. ${suggestion}`);
|
120
|
+
} else {
|
121
|
+
print(
|
122
|
+
`A profile with name ${profile} does not exist as a key in eas.json > build object.\n${suggestion}`,
|
123
|
+
);
|
124
|
+
}
|
125
|
+
process.exit(0);
|
126
|
+
}
|
127
|
+
|
128
|
+
const easJsonConfig = await EasJsonUtils.getBuildProfileAsync(easJsonAccessor, platform, profile);
|
129
|
+
|
130
|
+
const easCliConfig = await EasJsonUtils.getCliConfigAsync(easJsonAccessor);
|
131
|
+
const easCliVersion = easCliConfig?.version ?? 'latest';
|
132
|
+
|
133
|
+
/* -------------------------------------------------------------------------- */
|
134
|
+
/* EAS CLI SETUP */
|
135
|
+
/* -------------------------------------------------------------------------- */
|
136
|
+
const needsEasCli = await needsBinary('eas');
|
137
|
+
if (needsEasCli) {
|
138
|
+
await $`bun install eas-cli@${easCliVersion} -g`;
|
139
|
+
} else {
|
140
|
+
const currentEasCliVersion = await $`eas --version`.text();
|
141
|
+
if (currentEasCliVersion !== easCliVersion) {
|
142
|
+
await $`bun install eas-cli@${easCliVersion} -g`;
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
const {
|
147
|
+
APP_BUNDLE_IDENTIFIER,
|
148
|
+
APP_ANDROID_BUNDLE_IDENTIFIER: androidId = APP_BUNDLE_IDENTIFIER as string,
|
149
|
+
APP_APPLE_BUNDLE_IDENTIFIER: appleId = APP_BUNDLE_IDENTIFIER as string,
|
150
|
+
} = easJsonConfig.env ?? {};
|
151
|
+
|
152
|
+
// TODO: Add additional checks for ensuring this value adheres to Android formatting specs
|
153
|
+
if (platform === Platform.ANDROID && !androidId) {
|
154
|
+
throw new Error(`
|
155
|
+
APP_ANDROID_BUNDLE_IDENTIFIER must be defined in eas.json within the ${profile} > env config.
|
156
|
+
See https://docs.expo.dev/build-reference/variables/#setting-plaintext-environment-variables-in-easjson for information about env variables in eas.json
|
157
|
+
|
158
|
+
This env variable is used to populate the package key in your app.config.(js|ts) > android
|
159
|
+
The format of this env variable must use DNS notation unique name for your app, which is a valid Android Application ID.
|
160
|
+
|
161
|
+
For example you could use, com.company.app, where com.company is our domain and app is our app.
|
162
|
+
|
163
|
+
We recommend having the release build use the simplest identifier such as com.company.app and your debug variants
|
164
|
+
adding additional context such as com.company.app_debug. When publishing, the release identifier must be unique on the Play Store.
|
165
|
+
|
166
|
+
The name may only contain lowercase and uppercase letters (a-z, A-Z), numbers (0-9) and underscores (_),
|
167
|
+
separated by periods (.). Each component of the name should start with a lowercase letter.
|
168
|
+
|
169
|
+
These formatting rules only applies to Android. iOS has different requirements.
|
170
|
+
|
171
|
+
See https://docs.expo.dev/versions/latest/config/app/#package for more details on formatting.
|
172
|
+
See https://docs.expo.dev/build-reference/variants/ for information about build variants.
|
173
|
+
`);
|
174
|
+
}
|
175
|
+
|
176
|
+
// TODO: Add additional checks for ensuring this value adheres to Uniform Type Identifier
|
177
|
+
if (platform === Platform.IOS && !appleId) {
|
178
|
+
throw new Error(`
|
179
|
+
APP_APPLE_BUNDLE_IDENTIFIER must be defined in eas.json within the ${profile} > env config.
|
180
|
+
See https://docs.expo.dev/build-reference/variables/#setting-plaintext-environment-variables-in-easjson for information about env variables in eas.json
|
181
|
+
|
182
|
+
This env variable is used to populate the package key in your app.config.(js|ts) > ios
|
183
|
+
The format of this env variable must use DNS notation unique name for your app, which is a valid Android Application ID.
|
184
|
+
|
185
|
+
For example you could use, com.company.app, where com.company is our domain and app is our app.
|
186
|
+
|
187
|
+
We recommend having the release build use the simplest identifier such as com.company.app and your debug variants
|
188
|
+
adding additional context such as com.company.app-debug. When publishing, the release identifier must be unique to the App Store.
|
189
|
+
|
190
|
+
The string format should be Uniform Type Identifier(UTI), which is alphanumeric characters (A-Z,a-z,0-9), hyphen (-), and period (.)
|
191
|
+
|
192
|
+
These formatting rules only applies to iOS. Android has different requirements.
|
193
|
+
|
194
|
+
See https://docs.expo.dev/versions/latest/config/app/#bundleidentifier for more details on formatting.
|
195
|
+
See https://docs.expo.dev/build-reference/variants/ for information about build variants.
|
196
|
+
`);
|
197
|
+
}
|
198
|
+
|
199
|
+
const outputName = `${platform}-${profile}-${jsEngine}`;
|
200
|
+
// TODO: make this configurable
|
201
|
+
const prebuildsDir = `${appDirectory}/prebuilds`;
|
202
|
+
const outputDir = `${prebuildsDir}/${outputName}`;
|
203
|
+
const outputFileBase = `${outputDir}/${outputName}`;
|
204
|
+
|
205
|
+
let envVars = Bun.env;
|
206
|
+
|
207
|
+
envVars = {
|
208
|
+
...envVars,
|
209
|
+
APP_ANDROID_BUNDLE_IDENTIFIER: androidId,
|
210
|
+
APP_APPLE_BUNDLE_IDENTIFIER: appleId,
|
211
|
+
RCT_NO_LAUNCH_PACKAGER: '1',
|
212
|
+
EXPO_NO_TELEMETRY: '1',
|
213
|
+
EXPO_NO_WEB_SETUP: '1',
|
214
|
+
};
|
215
|
+
|
216
|
+
if (debug) {
|
217
|
+
envVars = {
|
218
|
+
...envVars,
|
219
|
+
DEBUG: '*',
|
220
|
+
EAS_LOCAL_BUILD_SKIP_CLEANUP: '1',
|
221
|
+
EXPO_PROFILE: '1',
|
222
|
+
};
|
223
|
+
}
|
224
|
+
|
225
|
+
if (envOpts) {
|
226
|
+
envVars = { ...envVars, ...envOpts };
|
227
|
+
}
|
228
|
+
|
229
|
+
$.env(envVars);
|
230
|
+
|
231
|
+
const output = {
|
232
|
+
name: outputName,
|
233
|
+
dir: outputDir,
|
234
|
+
prebuildsDir: prebuildsDir,
|
235
|
+
fileBase: outputFileBase,
|
236
|
+
artifact: platform === 'ios' ? `${outputFileBase}.tar.gz` : `${outputFileBase}.zip`,
|
237
|
+
app: platform === 'ios' ? `${outputFileBase}.app` : 'todo fix android',
|
238
|
+
get launchFile() {
|
239
|
+
return platform === 'ios' ? this.artifact : this.apk.signed;
|
240
|
+
},
|
241
|
+
apk: {
|
242
|
+
contents: `${outputFileBase}/build`,
|
243
|
+
rebuilt: `${outputFileBase}/binary-rebuilt.apk`,
|
244
|
+
rebuiltAligned: `${outputFileBase}/binary-rebuilt-aligned.apk`,
|
245
|
+
signed: `${outputFileBase}/binary.apk`,
|
246
|
+
test: `${outputFileBase}/testBinary.apk`,
|
247
|
+
},
|
248
|
+
};
|
249
|
+
|
250
|
+
return {
|
251
|
+
scheme: platform === 'ios' ? appleId : androidId,
|
252
|
+
channel: easJsonConfig.channel,
|
253
|
+
debug,
|
254
|
+
profile,
|
255
|
+
platform,
|
256
|
+
jsEngine,
|
257
|
+
appDirectory,
|
258
|
+
output,
|
259
|
+
};
|
260
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { $ } from 'bun';
|
2
|
+
import type { MobileProps } from './_setup';
|
3
|
+
import { setup } from './_setup';
|
4
|
+
|
5
|
+
export default {
|
6
|
+
name: 'build',
|
7
|
+
description: '🚀 Build',
|
8
|
+
run: async (props: MobileProps) => {
|
9
|
+
const { platform, profile, output } = await setup({
|
10
|
+
props,
|
11
|
+
});
|
12
|
+
|
13
|
+
await $`eas build --local --non-interactive --json --clear-cache --platform ${platform} --profile ${profile} --output ${output.artifact}`;
|
14
|
+
},
|
15
|
+
};
|
@@ -0,0 +1,79 @@
|
|
1
|
+
import { Props } from 'bluebun';
|
2
|
+
import { $ } from 'bun';
|
3
|
+
import { setup, type MobileProps } from './_setup';
|
4
|
+
|
5
|
+
interface MobileStartProps extends Props {
|
6
|
+
options: MobileProps['options'] & {
|
7
|
+
// Clear the cache when starting dev server
|
8
|
+
clear?: boolean;
|
9
|
+
};
|
10
|
+
}
|
11
|
+
|
12
|
+
type SimDevice = { udid: string; name: string; state: 'Booted' | 'Shutdown' };
|
13
|
+
type SimList = {
|
14
|
+
devices: {
|
15
|
+
['com.apple.CoreSimulator.SimRuntime.iOS-17-2']: SimDevice[];
|
16
|
+
};
|
17
|
+
};
|
18
|
+
|
19
|
+
export default {
|
20
|
+
name: 'dev',
|
21
|
+
description: '🚧 Dev',
|
22
|
+
run: async (props: MobileStartProps) => {
|
23
|
+
console.log('running dev');
|
24
|
+
const { platform, scheme, output } = await setup({
|
25
|
+
props,
|
26
|
+
env: {
|
27
|
+
EXPO_USE_METRO_WORKSPACE_ROOT: '1',
|
28
|
+
},
|
29
|
+
});
|
30
|
+
|
31
|
+
if (platform === 'ios') {
|
32
|
+
const xcodePath = await $`xcode-select -p`.text();
|
33
|
+
const xcodeExists = xcodePath.startsWith('/Applications');
|
34
|
+
|
35
|
+
if (xcodeExists) {
|
36
|
+
await $`open -a simulator`;
|
37
|
+
const deviceList = (await $`xcrun simctl list devices available -j -e`.json()) as SimList;
|
38
|
+
|
39
|
+
const devices = Object.values(deviceList?.devices).flatMap((item) => item);
|
40
|
+
|
41
|
+
if (devices.length === 0) {
|
42
|
+
throw new Error('No devices found');
|
43
|
+
} else {
|
44
|
+
const isBooted = devices.find((device: SimDevice) => device.state === 'Booted');
|
45
|
+
if (!isBooted) {
|
46
|
+
const iphone15Max = devices.find(
|
47
|
+
(device: SimDevice) => device.name === 'iPhone 15 Pro Max',
|
48
|
+
);
|
49
|
+
if (!iphone15Max) {
|
50
|
+
throw new Error('iPhone 15 Pro Max not found');
|
51
|
+
} else {
|
52
|
+
const udid = iphone15Max.udid;
|
53
|
+
await $`xcrun simctl boot ${udid}`;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
} else {
|
58
|
+
console.log(
|
59
|
+
'You must have XCode installed before continuing... Visit https://apps.apple.com/us/app/xcode/id497799835?mt=12 to download.',
|
60
|
+
);
|
61
|
+
throw new Error('XCode not installed');
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
await $`eas build:run --platform ${platform} --path ${output.launchFile}`;
|
66
|
+
|
67
|
+
const extraArgs = [];
|
68
|
+
|
69
|
+
if (props.options.clear) {
|
70
|
+
extraArgs.push('--clear');
|
71
|
+
}
|
72
|
+
|
73
|
+
const extrArgsString = extraArgs.join(' ');
|
74
|
+
|
75
|
+
console.log(`Starting metro server...`);
|
76
|
+
|
77
|
+
await $`expo start --${platform} --dev-client --localhost --scheme ${scheme} ${extrArgsString}`;
|
78
|
+
},
|
79
|
+
};
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import { type Props } from 'bluebun';
|
2
|
+
import { getCommandHelp } from '../../utils/getCommandHelp';
|
3
|
+
|
4
|
+
export default {
|
5
|
+
name: 'expo',
|
6
|
+
description: '',
|
7
|
+
run: async (props: Props) => {
|
8
|
+
switch (props?.first) {
|
9
|
+
case 'build':
|
10
|
+
return require('./build').default.run(props);
|
11
|
+
case 'dev':
|
12
|
+
return require('./dev').default.run(props);
|
13
|
+
case 'launch':
|
14
|
+
return require('./launch').default.run(props);
|
15
|
+
case 'update':
|
16
|
+
return require('./update').default.run(props);
|
17
|
+
default: {
|
18
|
+
await getCommandHelp(props);
|
19
|
+
break;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
},
|
23
|
+
};
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { $ } from 'bun';
|
2
|
+
import type { MobileProps } from './_setup';
|
3
|
+
import { setup } from './_setup';
|
4
|
+
|
5
|
+
export default {
|
6
|
+
name: 'launch',
|
7
|
+
description: '🚀 Launch',
|
8
|
+
run: async (props: MobileProps) => {
|
9
|
+
const { platform, output } = await setup({
|
10
|
+
props,
|
11
|
+
});
|
12
|
+
|
13
|
+
await $`eas build:run --platform ${platform} --path ${output.launchFile}`;
|
14
|
+
},
|
15
|
+
};
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { $ } from 'bun';
|
2
|
+
import type { MobileProps } from './_setup';
|
3
|
+
import { setup } from './_setup';
|
4
|
+
|
5
|
+
export default {
|
6
|
+
name: 'update',
|
7
|
+
description: '🚀 Update',
|
8
|
+
run: async (props: MobileProps) => {
|
9
|
+
const { channel } = await setup({
|
10
|
+
props,
|
11
|
+
});
|
12
|
+
|
13
|
+
await $`eas update --auto --channel ${channel}`;
|
14
|
+
await $`rm -rf dist`;
|
15
|
+
},
|
16
|
+
};
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { setupConfigWorker } from '../../utils/setupConfigWorker';
|
2
|
+
import { Props } from 'bluebun';
|
3
|
+
import { SyncOptions } from '../../utils/types';
|
4
|
+
import { $ } from 'bun';
|
5
|
+
|
6
|
+
interface DevProps extends Props {
|
7
|
+
options: SyncOptions;
|
8
|
+
}
|
9
|
+
|
10
|
+
export default {
|
11
|
+
name: 'dev',
|
12
|
+
description: '🚧 Dev',
|
13
|
+
run: async ({ options }: DevProps) => {
|
14
|
+
await setupConfigWorker(options);
|
15
|
+
await $`next dev`;
|
16
|
+
},
|
17
|
+
};
|
package/cli/env.d.ts
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
declare module 'bun' {
|
2
|
+
interface Env {
|
3
|
+
PWD: string;
|
4
|
+
APP_APPLE_BUNDLE_IDENTIFIER: string;
|
5
|
+
APP_ANDROID_BUNDLE_IDENTIFIER: string;
|
6
|
+
RCT_NO_LAUNCH_PACKAGER?: string;
|
7
|
+
EXPO_NO_TELEMETRY?: string;
|
8
|
+
EAS_LOCAL_BUILD_ARTIFACTS_DIR?: string;
|
9
|
+
EAS_LOCAL_BUILD_SKIP_CLEANUP?: string;
|
10
|
+
EXPO_PROFILE?: string;
|
11
|
+
EXPO_USE_METRO_WORKSPACE_ROOT?: string;
|
12
|
+
EXPO_BUNDLE_APP?: string;
|
13
|
+
ESLINT_USE_FLAT_CONFIG?: string;
|
14
|
+
}
|
15
|
+
}
|