@yahoo/uds 0.1.11 → 0.1.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. package/cli/README.md +135 -0
  2. package/cli/commands/config/config.ts +10 -0
  3. package/cli/commands/config/sync.ts +22 -0
  4. package/cli/commands/expo/_setup.ts +260 -0
  5. package/cli/commands/expo/build.ts +15 -0
  6. package/cli/commands/expo/dev.ts +79 -0
  7. package/cli/commands/expo/expo.ts +23 -0
  8. package/cli/commands/expo/launch.ts +15 -0
  9. package/cli/commands/expo/update.ts +16 -0
  10. package/cli/commands/nextjs/dev.ts +17 -0
  11. package/cli/commands/nextjs/nextjs.ts +10 -0
  12. package/cli/commands/uds.ts +10 -0
  13. package/cli/commands/version.ts +11 -0
  14. package/cli/env.d.ts +15 -0
  15. package/cli/eslint.config.mjs +8 -0
  16. package/cli/tsconfig.json +10 -0
  17. package/cli/uds-cli +7 -0
  18. package/cli/utils/configWorker.ts +9 -0
  19. package/cli/utils/getCommandHelp.ts +65 -0
  20. package/cli/utils/setupConfigWorker.ts +81 -0
  21. package/cli/utils/sortKeys.ts +27 -0
  22. package/cli/utils/types.ts +13 -0
  23. package/dist/chunk-3I3D5S54.js +1 -0
  24. package/dist/chunk-74YHFBTD.js +1 -0
  25. package/dist/chunk-AWTLI4D3.js +1 -0
  26. package/dist/chunk-D4K3CXV6.js +0 -0
  27. package/dist/chunk-M346JMQS.js +0 -0
  28. package/dist/chunk-MBOOJIH7.js +1 -0
  29. package/dist/chunk-MFA2Y7DA.js +1 -0
  30. package/dist/chunk-P7GR6E3K.js +1 -0
  31. package/dist/chunk-PQBOZFJV.js +1 -0
  32. package/dist/chunk-WYDHNV42.js +1 -0
  33. package/dist/fixtures/index.cjs +1 -0
  34. package/dist/fixtures/index.d.cts +141 -0
  35. package/dist/fixtures/index.d.ts +141 -0
  36. package/dist/fixtures/index.js +1 -0
  37. package/dist/index.cjs +1 -1
  38. package/dist/index.d.cts +62 -93
  39. package/dist/index.d.ts +62 -93
  40. package/dist/index.js +1 -1
  41. package/dist/index.native-3ww4C4UV.d.cts +15 -0
  42. package/dist/index.native-9kYJrUPa.d.ts +15 -0
  43. package/dist/index.native.cjs +1 -0
  44. package/dist/index.native.d.cts +1493 -0
  45. package/dist/index.native.d.ts +1493 -0
  46. package/dist/index.native.js +1 -0
  47. package/dist/tailwindPlugin.cjs +1 -1
  48. package/dist/tailwindPlugin.d.cts +2 -1
  49. package/dist/tailwindPlugin.d.ts +2 -1
  50. package/dist/tailwindPlugin.js +1 -1
  51. package/dist/tokens/index.cjs +1 -0
  52. package/dist/tokens/index.d.cts +39 -0
  53. package/dist/tokens/index.d.ts +39 -0
  54. package/dist/tokens/index.js +1 -0
  55. package/dist/tokens/index.native.cjs +1 -0
  56. package/dist/tokens/index.native.d.cts +3 -0
  57. package/dist/tokens/index.native.d.ts +3 -0
  58. package/dist/tokens/index.native.js +1 -0
  59. package/dist/tokens/parseTokens.cjs +1 -0
  60. package/dist/tokens/parseTokens.d.cts +85 -0
  61. package/dist/tokens/parseTokens.d.ts +85 -0
  62. package/dist/tokens/parseTokens.js +1 -0
  63. package/dist/tokens/parseTokens.native.cjs +1 -0
  64. package/dist/tokens/parseTokens.native.d.cts +416 -0
  65. package/dist/tokens/parseTokens.native.d.ts +416 -0
  66. package/dist/tokens/parseTokens.native.js +1 -0
  67. package/dist/types-J4DLS6Xj.d.cts +38 -0
  68. package/dist/types-J4DLS6Xj.d.ts +38 -0
  69. package/dist/types-hirL9Qk5.d.cts +510 -0
  70. package/dist/types-hirL9Qk5.d.ts +510 -0
  71. package/fonts/mobile.cjs +29 -0
  72. package/fonts/mobile.d.ts +3 -0
  73. package/fonts/yahoo-icons.ttf +0 -0
  74. package/fonts/yahoo-sans-beta-bold.otf +0 -0
  75. package/fonts/yahoo-sans-beta-medium.otf +0 -0
  76. package/fonts/yahoo-sans-beta-regular.otf +0 -0
  77. package/fonts/yahoo-sans-black.otf +0 -0
  78. package/fonts/yahoo-sans-bold.otf +0 -0
  79. package/fonts/yahoo-sans-condensed-black.otf +0 -0
  80. package/fonts/yahoo-sans-condensed-bold.otf +0 -0
  81. package/fonts/yahoo-sans-condensed-light.otf +0 -0
  82. package/fonts/yahoo-sans-condensed-medium.otf +0 -0
  83. package/fonts/yahoo-sans-condensed-regular.otf +0 -0
  84. package/fonts/yahoo-sans-extrabold.otf +0 -0
  85. package/fonts/yahoo-sans-extralight.otf +0 -0
  86. package/fonts/yahoo-sans-italic.otf +0 -0
  87. package/fonts/yahoo-sans-light.otf +0 -0
  88. package/fonts/yahoo-sans-medium.otf +0 -0
  89. package/fonts/yahoo-sans-regular.otf +0 -0
  90. package/fonts/yahoo-sans-semibold.otf +0 -0
  91. package/fonts/yahoo-serif-display-black.otf +0 -0
  92. package/fonts/yahoo-serif-display-bold.otf +0 -0
  93. package/fonts/yahoo-serif-display-extrabold.otf +0 -0
  94. package/fonts/yahoo-serif-display-light.otf +0 -0
  95. package/fonts/yahoo-serif-display-regular.otf +0 -0
  96. package/fonts/yahoo-serif-text-bold.otf +0 -0
  97. package/fonts/yahoo-serif-text-italic.otf +0 -0
  98. package/fonts/yahoo-serif-text-regular.otf +0 -0
  99. package/package.json +130 -35
  100. package/bin/uds +0 -0
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,10 @@
1
+ import { type Props } from 'bluebun';
2
+ import { getCommandHelp } from '../../utils/getCommandHelp';
3
+
4
+ export default {
5
+ name: 'config',
6
+ description: '',
7
+ run: async (props: Props) => {
8
+ await getCommandHelp(props);
9
+ },
10
+ };
@@ -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
+ };
@@ -0,0 +1,10 @@
1
+ import { type Props } from 'bluebun';
2
+ import { getCommandHelp } from '../../utils/getCommandHelp';
3
+
4
+ export default {
5
+ name: 'nextjs',
6
+ description: '',
7
+ run: async (props: Props) => {
8
+ await getCommandHelp(props);
9
+ },
10
+ };
@@ -0,0 +1,10 @@
1
+ import { type Props } from 'bluebun';
2
+ import { getCommandHelp } from '../utils/getCommandHelp';
3
+
4
+ export default {
5
+ name: 'uds',
6
+ description: '',
7
+ run: async (props: Props) => {
8
+ await getCommandHelp(props);
9
+ },
10
+ };
@@ -0,0 +1,11 @@
1
+ import { print } from 'bluebun';
2
+
3
+ import packageJson from '../../package.json';
4
+
5
+ export default {
6
+ name: 'version',
7
+ description: `💾 ${packageJson.version}`,
8
+ run: async () => {
9
+ print(packageJson.version);
10
+ },
11
+ };
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
+ }
@@ -0,0 +1,8 @@
1
+ import { defineFlatConfig, nodeConfig } from 'eslint-config-custom';
2
+
3
+ export default defineFlatConfig(
4
+ nodeConfig.map((config) => ({
5
+ ...config,
6
+ files: ['**/*.{ts,tsx}'],
7
+ })),
8
+ );
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "tsconfig/bun.json",
3
+ "include": ["."],
4
+ "compilerOptions": {
5
+ "paths": {
6
+ "@yahoo/uds/*": ["../src/*"],
7
+ "root/*": ["../../*"],
8
+ },
9
+ },
10
+ }