pob 35.7.0 → 36.1.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.
@@ -20,10 +20,10 @@ export const appIgnorePaths = {
20
20
  storybook: (config) => ["/.storybook/storybook.requires.ts"],
21
21
  expo: (config) => [
22
22
  "/.expo/",
23
- "/src/tamagui-web.css",
24
23
  "/android/",
25
24
  "/ios/",
26
25
  "/dist/",
26
+ "/dist-native/",
27
27
  "*.jks",
28
28
  "*.p8",
29
29
  "*.p12",
@@ -409,6 +409,12 @@ export default class CommonFormatLintGenerator extends Generator {
409
409
  };
410
410
  })();
411
411
 
412
+ const isMonorepoRoot =
413
+ this.options.monorepo || Boolean(inMonorepo && inMonorepo.root);
414
+ if (isMonorepoRoot && useTypescript) {
415
+ flatCascade.push("...pobConfig(import.meta.url).configs.monorepo");
416
+ }
417
+
412
418
  const eslintrcBadPath = this.destinationPath(".eslintrc");
413
419
  this.fs.delete(eslintrcBadPath);
414
420
  this.fs.delete(`${eslintrcBadPath}.yml`);
@@ -55,7 +55,7 @@ jobs:
55
55
  version: 11
56
56
  <% } -%>
57
57
 
58
- - uses: actions/setup-node@v6
58
+ - uses: actions/setup-node@v7
59
59
  with:
60
60
  node-version: <%= nodeLatestMajorVersion %>
61
61
  registry-url: "https://registry.npmjs.org"
@@ -259,21 +259,28 @@ export default class CommonTestingGenerator extends Generator {
259
259
  }
260
260
  const experimentalTestCoverage =
261
261
  pkg.name === "check-package-dependencies";
262
- return `TZ=UTC ${
263
- coverage && !experimentalTestCoverage
264
- ? `npx c8${
265
- coverage === "generate"
266
- ? ` --reporter=${coverage === "generate" ? "json" : "lcov"}`
267
- : ""
268
- } --all --src ./${this.options.srcDirectory} `
269
- : ""
270
- }node ${
271
- this.options.typescript
272
- ? `${tsTestLoaderOption ? `${tsTestLoaderOption} ` : ""}`
273
- : ""
274
- }${this.fs.exists("src/test-setup.ts") ? "--import ./src/test-setup.ts " : ""}--test${experimentalTestCoverage && coverage ? ` --experimental-test-coverage${coverage === "generate" ? " --test-reporter=spec --test-reporter-destination=stdout --test-reporter=lcov --test-reporter-destination=docs/coverage.lcov" : ""} --test-coverage-include="${this.options.srcDirectory}/**/*.ts"` : ""} '${this.options.monorepo ? `${workspacesPattern}/*/` : ""}${`${
275
- hasTestFolder ? "test/*" : `${this.options.srcDirectory}/**/*.test`
276
- }.${this.options.typescript ? "ts" : "js"}`}'`;
262
+ return [
263
+ experimentalTestCoverage && coverage === "generate"
264
+ ? "mkdir -p docs && "
265
+ : "",
266
+ `TZ=UTC ${
267
+ coverage && !experimentalTestCoverage
268
+ ? `npx c8${
269
+ coverage === "generate"
270
+ ? ` --reporter=${coverage === "generate" ? "json" : "lcov"}`
271
+ : ""
272
+ } --all --src ./${this.options.srcDirectory} `
273
+ : ""
274
+ }node ${
275
+ this.options.typescript
276
+ ? `${tsTestLoaderOption ? `${tsTestLoaderOption} ` : ""}`
277
+ : ""
278
+ }${this.fs.exists("src/test-setup.ts") ? "--import ./src/test-setup.ts " : ""}--test${experimentalTestCoverage && coverage ? ` --experimental-test-coverage${coverage === "generate" ? " --test-reporter=spec --test-reporter-destination=stdout --test-reporter=lcov --test-reporter-destination=docs/coverage.lcov" : ""} --test-coverage-include="${this.options.srcDirectory}/**/*.ts"` : ""} '${this.options.monorepo ? `${workspacesPattern}/*/` : ""}${`${
279
+ hasTestFolder
280
+ ? "test/*"
281
+ : `${this.options.srcDirectory}/**/*.test`
282
+ }.${this.options.typescript ? "ts" : "js"}`}'`,
283
+ ].join("");
277
284
  }
278
285
  case "bun": {
279
286
  if (this.options.packageManager !== "bun") {
@@ -27,7 +27,7 @@ jobs:
27
27
  version: 11
28
28
 
29
29
  <% } -%>
30
- - uses: actions/setup-node@v6
30
+ - uses: actions/setup-node@v7
31
31
  with:
32
32
  node-version: <%= nodeLatestMajorVersion %>
33
33
 
@@ -28,7 +28,7 @@ jobs:
28
28
  version: 11
29
29
 
30
30
  <% } -%>
31
- - uses: actions/setup-node@v6
31
+ - uses: actions/setup-node@v7
32
32
  with:
33
33
  node-version: <%= nodeLatestMajorVersion %>
34
34
 
@@ -73,7 +73,7 @@ jobs:
73
73
  version: 11
74
74
 
75
75
  <% } -%>
76
- - uses: actions/setup-node@v6
76
+ - uses: actions/setup-node@v7
77
77
  with:
78
78
  node-version: <%= nodeLatestMajorVersion %>
79
79
 
@@ -120,7 +120,7 @@ jobs:
120
120
  version: 11
121
121
 
122
122
  <% } -%>
123
- - uses: actions/setup-node@v6
123
+ - uses: actions/setup-node@v7
124
124
  with:
125
125
  node-version: <%= nodeLatestMajorVersion %>
126
126
 
@@ -178,7 +178,7 @@ jobs:
178
178
  version: 11
179
179
 
180
180
  <% } -%>
181
- - uses: actions/setup-node@v6
181
+ - uses: actions/setup-node@v7
182
182
  with:
183
183
  node-version: ${{ matrix.node-version }}
184
184
 
@@ -249,7 +249,7 @@ jobs:
249
249
  version: 11
250
250
 
251
251
  <% } -%>
252
- - uses: actions/setup-node@v6
252
+ - uses: actions/setup-node@v7
253
253
  with:
254
254
  node-version: ${{ matrix.node-version }}
255
255
 
@@ -280,7 +280,7 @@ jobs:
280
280
  steps:
281
281
  - uses: actions/checkout@v7
282
282
 
283
- - uses: actions/setup-node@v6
283
+ - uses: actions/setup-node@v7
284
284
  with:
285
285
  node-version: <%= nodeLatestMajorVersion %>
286
286
 
@@ -32,7 +32,7 @@ jobs:
32
32
 
33
33
  <% } -%>
34
34
  - name: Use Node.js ${{ matrix.node-version }}
35
- uses: actions/setup-node@v6
35
+ uses: actions/setup-node@v7
36
36
  with:
37
37
  node-version: ${{ matrix.node-version }}
38
38
  registry-url: 'https://registry.npmjs.org'
@@ -1,11 +1,6 @@
1
1
  import Generator from "yeoman-generator";
2
2
  import { writeAndFormatJson } from "../../../utils/writeAndFormat.js";
3
3
 
4
- const claudePostToolUseHook = {
5
- matcher: "Edit|Write|MultiEdit",
6
- hooks: [{ type: "command", command: "pob-claude-run-lint-staged" }],
7
- };
8
-
9
4
  export default class CoreClaudeGenerator extends Generator {
10
5
  constructor(args, opts) {
11
6
  super(args, opts);
@@ -34,22 +29,19 @@ export default class CoreClaudeGenerator extends Generator {
34
29
  "/settings.local.json\n/skills/local.*\n",
35
30
  );
36
31
 
32
+ const command =
33
+ pkg.name === "pob-monorepo"
34
+ ? "node ./@pob/root/bin/pob-claude-run-lint-staged.js"
35
+ : "./node_modules/.bin/pob-claude-run-lint-staged";
36
+
37
+ const claudePostToolUseHook = {
38
+ matcher: "Edit|Write|MultiEdit",
39
+ hooks: [{ type: "command", command }],
40
+ };
41
+
37
42
  const existing = this.fs.readJSON(claudeSettingsPath, {
38
43
  hooks: {
39
- PostToolUse: [
40
- {
41
- matcher: "Edit|Write|MultiEdit",
42
- hooks: [
43
- {
44
- type: "command",
45
- command:
46
- pkg.name === "pob-monorepo"
47
- ? "node ./@pob/root/bin/pob-claude-run-lint-staged.js"
48
- : "./node_modules/.bin/pob-claude-run-lint-staged",
49
- },
50
- ],
51
- },
52
- ],
44
+ PostToolUse: [claudePostToolUseHook],
53
45
  },
54
46
  });
55
47
 
@@ -221,28 +221,29 @@ export default class CorePackageGenerator extends Generator {
221
221
  fs.unlinkSync(this.destinationPath("yarn-error.log"));
222
222
  }
223
223
 
224
- if (this.options.inMonorepo && !this.options.isRoot) {
225
- packageUtils.removeScripts(pkg, ["checks"]);
224
+ if (pkg.name !== "@pob/root") {
226
225
  packageUtils.removeDevDependencies(pkg, ["check-package-dependencies"]);
227
- } else if (this.options.isMonorepo && this.options.isRoot) {
228
- const doesMjsCheckPackagesExists = this.fs.exists(
229
- this.destinationPath("scripts/check-packages.mjs"),
230
- );
231
- const doesJsCheckPackagesExists = this.fs.exists(
232
- this.destinationPath("scripts/check-packages.js"),
233
- );
226
+ }
227
+ if (this.fs.exists(this.destinationPath("scripts/check-packages.mjs"))) {
228
+ this.fs.delete(this.destinationPath("scripts/check-packages.mjs"));
229
+ }
230
+ if (this.fs.exists(this.destinationPath("scripts/check-packages.js"))) {
231
+ this.fs.delete(this.destinationPath("scripts/check-packages.js"));
232
+ }
234
233
 
235
- if (doesJsCheckPackagesExists || doesMjsCheckPackagesExists) {
236
- packageUtils.addDevDependencies(pkg, ["check-package-dependencies"]);
234
+ if (this.options.inMonorepo && !this.options.isRoot) {
235
+ packageUtils.removeScripts(pkg, ["checks"]);
236
+ } else if (this.options.isRoot) {
237
+ const checksScript = pkg.scripts?.checks;
238
+ if (checksScript && checksScript.includes("node scripts/check-package")) {
239
+ pkg.scripts.checks = checksScript.replace(
240
+ /( && )?node scripts\/check-package\.(mjs|js)( && )?/,
241
+ "",
242
+ );
243
+ if (pkg.scripts.checks === "") {
244
+ delete pkg.scripts.checks;
245
+ }
237
246
  }
238
-
239
- packageUtils.addOrRemoveScripts(
240
- pkg,
241
- doesMjsCheckPackagesExists || doesJsCheckPackagesExists,
242
- {
243
- checks: `node scripts/check-packages.${doesMjsCheckPackagesExists ? "mjs" : "js"}`,
244
- },
245
- );
246
247
  } else if (inMonorepo && !inMonorepo.root) {
247
248
  if (this.fs.exists("scripts/check-package.js")) {
248
249
  this.fs.delete("scripts/check-package.js");
@@ -251,50 +252,6 @@ export default class CorePackageGenerator extends Generator {
251
252
  this.fs.delete("scripts/check-package.mjs");
252
253
  }
253
254
  packageUtils.removeScripts(pkg, ["checks"]);
254
- } else {
255
- const doesMjsCheckPackageExists = this.fs.exists(
256
- this.destinationPath("scripts/check-package.mjs"),
257
- );
258
- let doesJsCheckPackageExists = this.fs.exists(
259
- this.destinationPath("scripts/check-package.js"),
260
- );
261
- const doesTsCheckPackageExists = this.fs.exists(
262
- this.destinationPath("scripts/check-package.ts"),
263
- );
264
-
265
- if (pkg.type === "module") {
266
- if (!doesJsCheckPackageExists && !doesTsCheckPackageExists) {
267
- doesJsCheckPackageExists = true;
268
- this.fs.copyTpl(
269
- this.templatePath("check-package.js.ejs"),
270
- this.destinationPath("scripts/check-package.ts"),
271
- {
272
- isLibrary: pkg.private !== true,
273
- },
274
- );
275
- }
276
- }
277
- if (
278
- doesJsCheckPackageExists ||
279
- doesMjsCheckPackageExists ||
280
- doesTsCheckPackageExists
281
- ) {
282
- packageUtils.addDevDependencies(pkg, ["check-package-dependencies"]);
283
- }
284
-
285
- packageUtils.addOrRemoveScripts(
286
- pkg,
287
- doesMjsCheckPackageExists ||
288
- doesJsCheckPackageExists ||
289
- doesTsCheckPackageExists,
290
- {
291
- checks: `node scripts/check-package.${(() => {
292
- if (doesMjsCheckPackageExists) return "mjs";
293
- if (doesTsCheckPackageExists) return "ts";
294
- return "js";
295
- })()}`,
296
- },
297
- );
298
255
  }
299
256
 
300
257
  if (!pkg.authors) {
@@ -1,5 +1,5 @@
1
1
  import sortObject from "@pob/sort-object";
2
- import yml from "js-yaml";
2
+ import { FAILSAFE_SCHEMA, dump, loadAll } from "js-yaml";
3
3
  import { lt } from "semver";
4
4
  import Generator from "yeoman-generator";
5
5
  import { writeAndFormat } from "../../../utils/writeAndFormat.js";
@@ -47,10 +47,10 @@ export default class CorePnpmGenerator extends Generator {
47
47
  this.destinationPath("pnpm-workspace.yaml"),
48
48
  { defaults: "" },
49
49
  );
50
- const config =
51
- yml.load(configString, {
52
- schema: yml.FAILSAFE_SCHEMA,
53
- }) || {};
50
+ const [loadedConfig] = loadAll(configString, {
51
+ schema: FAILSAFE_SCHEMA,
52
+ });
53
+ const config = loadedConfig ?? {};
54
54
 
55
55
  if (config.allowBuilds) {
56
56
  config.allowBuilds = Object.fromEntries(
@@ -70,11 +70,12 @@ export default class CorePnpmGenerator extends Generator {
70
70
  config.minimumReleaseAge = 1440 * 3; // 3 days in minutes
71
71
  config.minimumReleaseAgeExclude = minimumReleaseAgeExcludePackages;
72
72
  config.dedupePeerDependents = true;
73
+ config.nodeLinker = "hoisted";
73
74
 
74
75
  await writeAndFormat(
75
76
  this.fs,
76
77
  this.destinationPath("pnpm-workspace.yaml"),
77
- yml.dump(sortObject(config), { lineWidth: 9999, noCompatMode: true }),
78
+ dump(sortObject(config), { lineWidth: 9999 }),
78
79
  );
79
80
  } else {
80
81
  if (pkg.packageManager?.startsWith("pnpm@")) {
@@ -1,7 +1,7 @@
1
1
  import fs from "node:fs";
2
2
  import { isDeepStrictEqual } from "node:util";
3
3
  import sortObject from "@pob/sort-object";
4
- import yml from "js-yaml";
4
+ import { FAILSAFE_SCHEMA, dump, loadAll } from "js-yaml";
5
5
  import { lt } from "semver";
6
6
  import Generator from "yeoman-generator";
7
7
  import { ensureJsonFileFormatted } from "../../../utils/ensureJsonFileFormatted.js";
@@ -154,11 +154,11 @@ export default class CoreYarnGenerator extends Generator {
154
154
 
155
155
  // must be done after plugins installed
156
156
  const configString = this.fs.read(".yarnrc.yml", { defaults: "" });
157
- const config =
158
- yml.load(configString, {
159
- schema: yml.FAILSAFE_SCHEMA,
160
- json: true,
161
- }) || {};
157
+ const [loadedConfig] = loadAll(configString, {
158
+ schema: FAILSAFE_SCHEMA,
159
+ json: true,
160
+ });
161
+ const config = loadedConfig ?? {};
162
162
  if (config.enableScripts === "true") {
163
163
  config.enableScripts = true;
164
164
  }
@@ -204,7 +204,7 @@ export default class CoreYarnGenerator extends Generator {
204
204
  await writeAndFormat(
205
205
  this.fs,
206
206
  ".yarnrc.yml",
207
- yml.dump(sortObject(config), {
207
+ dump(sortObject(config), {
208
208
  lineWidth: 9999,
209
209
  }),
210
210
  );
@@ -61,11 +61,7 @@ const hasData = (packages, configs) =>
61
61
  const hasTamagui = (packages, configs) =>
62
62
  packages.some(
63
63
  (pkg) =>
64
- !!(
65
- pkg.dependencies?.tamagui ||
66
- pkg.dependencies?.["@tamagui/core"] ||
67
- pkg.dependencies?.alouette
68
- ),
64
+ !!(pkg.dependencies?.tamagui || pkg.dependencies?.["@tamagui/core"]),
69
65
  );
70
66
 
71
67
  export default class PobMonorepoGenerator extends Generator {
@@ -269,9 +265,13 @@ export default class PobMonorepoGenerator extends Generator {
269
265
  `${this.pobLernaConfig.e2eTesting === "." || this.pobLernaConfig.e2eTesting === true ? "" : `/${this.pobLernaConfig.e2eTesting}`}/test-results/`,
270
266
  ].filter(Boolean);
271
267
 
272
- const gitignorePaths = [
273
- hasTamagui(this.packages, this.packageConfigs) && ".tamagui",
274
- ].filter(Boolean);
268
+ if (hasTamagui(this.packages, this.packageConfigs)) {
269
+ throw new Error(
270
+ "Tamagui is no longer supported. Please migrate to native-wind.",
271
+ );
272
+ }
273
+
274
+ const gitignorePaths = [].filter(Boolean);
275
275
 
276
276
  this.composeWith("pob:common:format-lint", {
277
277
  monorepo: true,
@@ -1,8 +1,22 @@
1
+ import { readdirSync } from "node:fs";
1
2
  import Generator from "yeoman-generator";
3
+ import { latestLTS } from "../../../utils/nodeVersions.js";
2
4
  import * as packageUtils from "../../../utils/package.js";
3
5
  import { packageManagerRun } from "../../../utils/packageManagerUtils.js";
4
6
  import { copyAndFormatTpl } from "../../../utils/writeAndFormat.js";
5
7
 
8
+ const rootConfigExtensionsRegex = /\.config\.(?:ts|mts|cts)$/;
9
+
10
+ const hasRootConfigFiles = (rootPath) => {
11
+ try {
12
+ return readdirSync(rootPath).some((name) =>
13
+ rootConfigExtensionsRegex.test(name),
14
+ );
15
+ } catch {
16
+ return false;
17
+ }
18
+ };
19
+
6
20
  export default class MonorepoTypescriptGenerator extends Generator {
7
21
  constructor(args, opts) {
8
22
  super(args, opts);
@@ -121,15 +135,36 @@ export default class MonorepoTypescriptGenerator extends Generator {
121
135
  const tsconfigCheckPath = this.destinationPath("tsconfig.check.json");
122
136
  const tsconfigBuildPath = this.destinationPath("tsconfig.build.json");
123
137
  const tsconfigTestPath = this.destinationPath("tsconfig.test.json");
138
+ const tsconfigRootConfigsPath = this.destinationPath(
139
+ "tsconfig.root-configs.json",
140
+ );
124
141
  this.fs.delete(tsconfigTestPath);
125
142
 
126
143
  if (!this.options.enable) {
127
144
  this.fs.delete(tsconfigPath);
128
145
  this.fs.delete(tsconfigCheckPath);
129
146
  this.fs.delete(tsconfigBuildPath);
147
+ this.fs.delete(tsconfigRootConfigsPath);
130
148
  } else {
131
149
  const packagePaths = JSON.parse(this.options.packagePaths);
132
150
 
151
+ // root config files written in typescript (e.g. vitest.config.ts) are not
152
+ // part of any package tsconfig, so they need a dedicated project for
153
+ // type-aware linting and tsc -b
154
+ const hasRootConfigs = hasRootConfigFiles(this.destinationPath());
155
+ if (hasRootConfigs) {
156
+ await copyAndFormatTpl(
157
+ this.fs,
158
+ this.templatePath("tsconfig.root-configs.json.ejs"),
159
+ tsconfigRootConfigsPath,
160
+ {
161
+ nodeVersion: latestLTS,
162
+ },
163
+ );
164
+ } else {
165
+ this.fs.delete(tsconfigRootConfigsPath);
166
+ }
167
+
133
168
  await copyAndFormatTpl(
134
169
  this.fs,
135
170
  this.templatePath("tsconfig.json.ejs"),
@@ -137,6 +172,7 @@ export default class MonorepoTypescriptGenerator extends Generator {
137
172
  {
138
173
  packagePaths,
139
174
  tsConfigSuffix: false,
175
+ hasRootConfigs,
140
176
  },
141
177
  );
142
178
 
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "files": [],
3
3
  "references": [
4
+ <% if (hasRootConfigs) { -%>
5
+ { "path": "tsconfig.root-configs.json" }<%= packagePaths.length > 0 ? ',' : '' %>
6
+ <% } -%>
4
7
  <% packagePaths.forEach((packagePath, index) => { -%>
5
8
  { "path": "<%= packagePath %>/tsconfig<%= tsConfigSuffix ? `.${tsConfigSuffix}` : '' %>.json" }<%= index === packagePaths.length -1 ? '' : ',' %>
6
9
  <% }) -%>
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": [
3
+ "@pob/root/tsconfigs/strict.json",
4
+ "@pob/root/tsconfigs/targets/node-<%= nodeVersion %>.json"
5
+ ],
6
+ "include": ["*.config.ts", "*.config.mts", "*.config.cts"],
7
+ "compilerOptions": {
8
+ "noEmit": true,
9
+ "tsBuildInfoFile": "node_modules/.cache/tsc/tsbuildinfo-root-configs",
10
+ "incremental": true,
11
+ "resolveJsonModule": true
12
+ }
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pob",
3
- "version": "35.7.0",
3
+ "version": "36.1.0",
4
4
  "description": "Pile of bones, library generator with git/babel/typescript/typedoc/readme/vitest",
5
5
  "keywords": [
6
6
  "skeleton"
@@ -28,16 +28,13 @@
28
28
  "./package.json": "./package.json"
29
29
  },
30
30
  "dependencies": {
31
- "@pob/eslint-config": "65.6.0",
32
- "@pob/eslint-config-typescript-react": "65.6.0",
33
31
  "@types/inquirer": "9.0.10",
34
32
  "@yeoman/adapter": "4.0.2",
35
- "@yeoman/types": "1.11.1",
36
33
  "eslint": "10.7.0",
37
34
  "findup-sync": "^5.0.0",
38
35
  "git-remote-url": "^1.0.1",
39
36
  "github-username": "^9.0.0",
40
- "js-yaml": "^4.1.1",
37
+ "js-yaml": "^5.2.1",
41
38
  "json5": "^2.2.3",
42
39
  "lodash.camelcase": "^4.3.0",
43
40
  "lodash.kebabcase": "^4.1.1",
@@ -51,13 +48,16 @@
51
48
  "validate-npm-package-name": "^8.0.0",
52
49
  "yeoman-environment": "6.1.0",
53
50
  "yeoman-generator": "8.2.2",
51
+ "@pob/eslint-config-typescript-react": "65.8.0",
52
+ "@pob/eslint-config": "65.7.0",
53
+ "@pob/sort-pkg": "13.1.2",
54
54
  "@pob/sort-object": "11.1.1",
55
- "pob-dependencies": "24.4.0",
56
- "@pob/sort-pkg": "13.1.2"
55
+ "pob-dependencies": "25.1.0"
57
56
  },
58
57
  "devDependencies": {
59
58
  "@types/node": "24.13.3",
60
- "@pob/root": "24.7.0"
59
+ "@yeoman/types": "1.11.1",
60
+ "@pob/root": "25.1.0"
61
61
  },
62
62
  "engines": {
63
63
  "node": ">=22.18.0"
@@ -1,3 +0,0 @@
1
- import { createCheckPackage } from 'check-package-dependencies';
2
-
3
- await createCheckPackage({ isLibrary: <%= isLibrary ? 'true' : 'false' %> }).checkRecommended({}).run();
@@ -1,7 +0,0 @@
1
- import { createCheckPackageWithWorkspaces } from 'check-package-dependencies';
2
-
3
- await createCheckPackageWithWorkspaces({
4
- isLibrary: () => true,
5
- })
6
- .checkRecommended()
7
- .run();