@graphcommerce/cli 1.0.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/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # @graphcommerce/cli
2
+
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#1399](https://github.com/graphcommerce-org/graphcommerce/pull/1399) [`fb277d8e1`](https://github.com/graphcommerce-org/graphcommerce/commit/fb277d8e1e3612c5e9cf890a30d19cfd1ff70542) Thanks [@paales](https://github.com/paales)! - Now using [@graphql-yoga](https://github.com/dotansimha/graphql-yoga) for GraphQL which has full support for [envelop](https://www.envelop.dev/) plugins.
8
+
9
+ * [#1399](https://github.com/graphcommerce-org/graphcommerce/pull/1399) [`fb277d8e1`](https://github.com/graphcommerce-org/graphcommerce/commit/fb277d8e1e3612c5e9cf890a30d19cfd1ff70542) Thanks [@paales](https://github.com/paales)! - Added a new @graphcommerce/cli package to generate the mesh so it can be generated _inside_ the @graphcommerce/graphql-mesh package to allow for better future extensibility.
10
+
11
+ ### Patch Changes
12
+
13
+ - [#1399](https://github.com/graphcommerce-org/graphcommerce/pull/1399) [`da0ae7d02`](https://github.com/graphcommerce-org/graphcommerce/commit/da0ae7d0236e4908ba0bf0fa16656be516e841d4) Thanks [@paales](https://github.com/paales)! - Updated dependencies
package/README.md ADDED
@@ -0,0 +1,8 @@
1
+ # GraphCommerce CLI
2
+
3
+ Commands:
4
+
5
+ ```
6
+ # https://www.graphql-mesh.com/docs/getting-started/deploy-mesh-gateway
7
+ yarn mesh build
8
+ ```
package/bin/codegen.ts ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { runCli, cliError } from '@graphql-codegen/cli'
4
+
5
+ const [, , cmd] = process.argv
6
+
7
+ // console.log(process.argv)
8
+
9
+ runCli(cmd)
10
+ .then(() => {
11
+ process.exit(0)
12
+ })
13
+ .catch((error) => {
14
+ cliError(error)
15
+ })
package/bin/mesh.ts ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable import/no-extraneous-dependencies */
3
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
4
+ import fs, { read } from 'fs'
5
+ import path from 'path'
6
+ import { exit } from 'process'
7
+ import { graphqlMesh, DEFAULT_CLI_PARAMS } from '@graphql-mesh/cli'
8
+ import { Logger, YamlConfig } from '@graphql-mesh/types'
9
+ import { DefaultLogger } from '@graphql-mesh/utils'
10
+ import dotenv from 'dotenv'
11
+ import yaml from 'yaml'
12
+ import { findConfig } from '../mesh/findConfig'
13
+
14
+ dotenv.config()
15
+
16
+ export function handleFatalError(e: Error, logger: Logger = new DefaultLogger('◈')) {
17
+ logger.error(e.stack || e.message)
18
+ // eslint-disable-next-line no-console
19
+ console.log(e)
20
+ if (process.env.JEST == null) exit(1)
21
+ }
22
+
23
+ const root = process.cwd()
24
+ const meshDir = path.dirname(require.resolve('@graphcommerce/graphql-mesh'))
25
+
26
+ const relativePath = path.join(path.relative(meshDir, root), '/')
27
+
28
+ const isMonoRepo = relativePath.startsWith('../../examples')
29
+
30
+ const main = async () => {
31
+ const conf = (await findConfig({})) as YamlConfig.Config
32
+
33
+ conf.additionalResolvers = conf.additionalResolvers ?? []
34
+
35
+ // Rewrite string directives
36
+ conf.additionalResolvers = conf.additionalResolvers.map((additionalResolver) => {
37
+ if (typeof additionalResolver === 'string') return `${relativePath}${additionalResolver}`
38
+ return additionalResolver
39
+ })
40
+
41
+ if (!conf.additionalTypeDefs) conf.additionalTypeDefs = []
42
+ // Add additionalTypeDefs
43
+ conf.additionalTypeDefs = Array.isArray(conf.additionalTypeDefs)
44
+ ? conf.additionalTypeDefs
45
+ : [conf.additionalTypeDefs]
46
+
47
+ conf.additionalTypeDefs.push('**/*.graphqls')
48
+ if (isMonoRepo) {
49
+ conf.additionalTypeDefs.push('../../packages/magento-*/**/*.graphqls')
50
+ conf.additionalTypeDefs.push('../../packagesDev/**/*.graphqls')
51
+ } else {
52
+ conf.additionalTypeDefs.push('node_modules/@graphcommerce/**/*.graphqls')
53
+ }
54
+
55
+ fs.writeFileSync(path.join(meshDir, '.meshrc.yml'), yaml.stringify(conf))
56
+
57
+ graphqlMesh(DEFAULT_CLI_PARAMS, undefined, `${meshDir}/`).catch((e) =>
58
+ handleFatalError(e, new DefaultLogger(DEFAULT_CLI_PARAMS.initialLoggerPrefix)),
59
+ )
60
+ }
61
+
62
+ main().catch(console.error)
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ var cli_1 = require("@graphql-codegen/cli");
5
+ var _a = process.argv, cmd = _a[2];
6
+ // console.log(process.argv)
7
+ (0, cli_1.runCli)(cmd)
8
+ .then(function () {
9
+ process.exit(0);
10
+ })
11
+ .catch(function (error) {
12
+ (0, cli_1.cliError)(error);
13
+ });
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
12
+ var __generator = (this && this.__generator) || function (thisArg, body) {
13
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
14
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
15
+ function verb(n) { return function (v) { return step([n, v]); }; }
16
+ function step(op) {
17
+ if (f) throw new TypeError("Generator is already executing.");
18
+ while (_) try {
19
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
20
+ if (y = 0, t) op = [op[0] & 2, t.value];
21
+ switch (op[0]) {
22
+ case 0: case 1: t = op; break;
23
+ case 4: _.label++; return { value: op[1], done: false };
24
+ case 5: _.label++; y = op[1]; op = [0]; continue;
25
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
26
+ default:
27
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
28
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
29
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
30
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
31
+ if (t[2]) _.ops.pop();
32
+ _.trys.pop(); continue;
33
+ }
34
+ op = body.call(thisArg, _);
35
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
36
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
37
+ }
38
+ };
39
+ var __importDefault = (this && this.__importDefault) || function (mod) {
40
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.handleFatalError = void 0;
44
+ /* eslint-disable import/no-extraneous-dependencies */
45
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
46
+ var fs_1 = __importDefault(require("fs"));
47
+ var path_1 = __importDefault(require("path"));
48
+ var process_1 = require("process");
49
+ var cli_1 = require("@graphql-mesh/cli");
50
+ var utils_1 = require("@graphql-mesh/utils");
51
+ var dotenv_1 = __importDefault(require("dotenv"));
52
+ var yaml_1 = __importDefault(require("yaml"));
53
+ var findConfig_1 = require("../mesh/findConfig");
54
+ dotenv_1.default.config();
55
+ function handleFatalError(e, logger) {
56
+ if (logger === void 0) { logger = new utils_1.DefaultLogger('◈'); }
57
+ logger.error(e.stack || e.message);
58
+ // eslint-disable-next-line no-console
59
+ console.log(e);
60
+ if (process.env.JEST == null)
61
+ (0, process_1.exit)(1);
62
+ }
63
+ exports.handleFatalError = handleFatalError;
64
+ var root = process.cwd();
65
+ var meshDir = path_1.default.dirname(require.resolve('@graphcommerce/graphql-mesh'));
66
+ var relativePath = path_1.default.join(path_1.default.relative(meshDir, root), '/');
67
+ var isMonoRepo = relativePath.startsWith('../../examples');
68
+ var main = function () { return __awaiter(void 0, void 0, void 0, function () {
69
+ var conf;
70
+ var _a;
71
+ return __generator(this, function (_b) {
72
+ switch (_b.label) {
73
+ case 0: return [4 /*yield*/, (0, findConfig_1.findConfig)({})];
74
+ case 1:
75
+ conf = (_b.sent());
76
+ conf.additionalResolvers = (_a = conf.additionalResolvers) !== null && _a !== void 0 ? _a : [];
77
+ // Rewrite string directives
78
+ conf.additionalResolvers = conf.additionalResolvers.map(function (additionalResolver) {
79
+ if (typeof additionalResolver === 'string')
80
+ return "".concat(relativePath).concat(additionalResolver);
81
+ return additionalResolver;
82
+ });
83
+ if (!conf.additionalTypeDefs)
84
+ conf.additionalTypeDefs = [];
85
+ // Add additionalTypeDefs
86
+ conf.additionalTypeDefs = Array.isArray(conf.additionalTypeDefs)
87
+ ? conf.additionalTypeDefs
88
+ : [conf.additionalTypeDefs];
89
+ conf.additionalTypeDefs.push('**/*.graphqls');
90
+ if (isMonoRepo) {
91
+ conf.additionalTypeDefs.push('../../packages/magento-*/**/*.graphqls');
92
+ conf.additionalTypeDefs.push('../../packagesDev/**/*.graphqls');
93
+ }
94
+ else {
95
+ conf.additionalTypeDefs.push('node_modules/@graphcommerce/**/*.graphqls');
96
+ }
97
+ fs_1.default.writeFileSync(path_1.default.join(meshDir, '.meshrc.yml'), yaml_1.default.stringify(conf));
98
+ (0, cli_1.graphqlMesh)(cli_1.DEFAULT_CLI_PARAMS, undefined, "".concat(meshDir, "/")).catch(function (e) {
99
+ return handleFatalError(e, new utils_1.DefaultLogger(cli_1.DEFAULT_CLI_PARAMS.initialLoggerPrefix));
100
+ });
101
+ return [2 /*return*/];
102
+ }
103
+ });
104
+ }); };
105
+ main().catch(console.error);
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (_) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.findConfig = void 0;
43
+ /* eslint-disable import/no-extraneous-dependencies */
44
+ var path_1 = __importDefault(require("path"));
45
+ var utils_1 = require("@graphql-mesh/utils");
46
+ var cosmiconfig_1 = require("cosmiconfig");
47
+ function customLoader(ext, importFn) {
48
+ if (importFn === void 0) { importFn = utils_1.defaultImportFn; }
49
+ // eslint-disable-next-line consistent-return
50
+ function loader(filepath, content) {
51
+ if (process.env) {
52
+ // eslint-disable-next-line no-param-reassign
53
+ content = content.replace(/\$\{(.*?)\}/g, function (_, variable) {
54
+ var varName = variable;
55
+ var defaultValue = '';
56
+ if (variable.includes(':')) {
57
+ var spl = variable.split(':');
58
+ varName = spl.shift();
59
+ defaultValue = spl.join(':');
60
+ }
61
+ return process.env[varName] || defaultValue;
62
+ });
63
+ }
64
+ if (ext === 'json') {
65
+ return cosmiconfig_1.defaultLoaders['.json'](filepath, content);
66
+ }
67
+ if (ext === 'yaml') {
68
+ return (0, utils_1.loadYaml)(filepath, content);
69
+ }
70
+ if (ext === 'js') {
71
+ return importFn(filepath);
72
+ }
73
+ }
74
+ return loader;
75
+ }
76
+ function findConfig(options) {
77
+ return __awaiter(this, void 0, void 0, function () {
78
+ var _a, _b, configName, _c, configDir, dir, explorer, results, config;
79
+ return __generator(this, function (_d) {
80
+ switch (_d.label) {
81
+ case 0:
82
+ _a = options || {}, _b = _a.configName, configName = _b === void 0 ? 'mesh' : _b, _c = _a.dir, configDir = _c === void 0 ? '' : _c;
83
+ dir = path_1.default.isAbsolute(configDir) ? configDir : path_1.default.join(process.cwd(), configDir);
84
+ explorer = (0, cosmiconfig_1.cosmiconfig)(configName, {
85
+ searchPlaces: [
86
+ 'package.json',
87
+ ".".concat(configName, "rc"),
88
+ ".".concat(configName, "rc.json"),
89
+ ".".concat(configName, "rc.yaml"),
90
+ ".".concat(configName, "rc.yml"),
91
+ ".".concat(configName, "rc.js"),
92
+ ".".concat(configName, "rc.ts"),
93
+ ".".concat(configName, "rc.cjs"),
94
+ "".concat(configName, ".config.js"),
95
+ "".concat(configName, ".config.cjs"),
96
+ ],
97
+ loaders: {
98
+ '.json': customLoader('json', options === null || options === void 0 ? void 0 : options.importFn),
99
+ '.yaml': customLoader('yaml', options === null || options === void 0 ? void 0 : options.importFn),
100
+ '.yml': customLoader('yaml', options === null || options === void 0 ? void 0 : options.importFn),
101
+ '.js': customLoader('js', options === null || options === void 0 ? void 0 : options.importFn),
102
+ '.ts': customLoader('js', options === null || options === void 0 ? void 0 : options.importFn),
103
+ noExt: customLoader('yaml', options === null || options === void 0 ? void 0 : options.importFn),
104
+ },
105
+ });
106
+ return [4 /*yield*/, explorer.search(dir)];
107
+ case 1:
108
+ results = _d.sent();
109
+ if (!results) {
110
+ throw new Error("No ".concat(configName, " config file found in \"").concat(dir, "\"!"));
111
+ }
112
+ config = results.config;
113
+ return [2 /*return*/, config];
114
+ }
115
+ });
116
+ });
117
+ }
118
+ exports.findConfig = findConfig;
@@ -0,0 +1,77 @@
1
+ /* eslint-disable import/no-extraneous-dependencies */
2
+ import path from 'path'
3
+ import { ConfigProcessOptions } from '@graphql-mesh/config'
4
+ import { defaultImportFn, loadYaml } from '@graphql-mesh/utils'
5
+ import { cosmiconfig, defaultLoaders } from 'cosmiconfig'
6
+
7
+ function customLoader(ext: 'json' | 'yaml' | 'js', importFn = defaultImportFn) {
8
+ // eslint-disable-next-line consistent-return
9
+ function loader(filepath: string, content: string) {
10
+ if (process.env) {
11
+ // eslint-disable-next-line no-param-reassign
12
+ content = content.replace(/\$\{(.*?)\}/g, (_, variable) => {
13
+ let varName = variable
14
+ let defaultValue = ''
15
+
16
+ if (variable.includes(':')) {
17
+ const spl = variable.split(':')
18
+ varName = spl.shift()
19
+ defaultValue = spl.join(':')
20
+ }
21
+
22
+ return process.env[varName] || defaultValue
23
+ })
24
+ }
25
+
26
+ if (ext === 'json') {
27
+ return defaultLoaders['.json'](filepath, content)
28
+ }
29
+
30
+ if (ext === 'yaml') {
31
+ return loadYaml(filepath, content)
32
+ }
33
+
34
+ if (ext === 'js') {
35
+ return importFn(filepath)
36
+ }
37
+ }
38
+
39
+ return loader
40
+ }
41
+
42
+ export async function findConfig(
43
+ options?: Pick<ConfigProcessOptions, 'configName' | 'dir' | 'importFn'>,
44
+ ) {
45
+ const { configName = 'mesh', dir: configDir = '' } = options || {}
46
+ const dir = path.isAbsolute(configDir) ? configDir : path.join(process.cwd(), configDir)
47
+ const explorer = cosmiconfig(configName, {
48
+ searchPlaces: [
49
+ 'package.json',
50
+ `.${configName}rc`,
51
+ `.${configName}rc.json`,
52
+ `.${configName}rc.yaml`,
53
+ `.${configName}rc.yml`,
54
+ `.${configName}rc.js`,
55
+ `.${configName}rc.ts`,
56
+ `.${configName}rc.cjs`,
57
+ `${configName}.config.js`,
58
+ `${configName}.config.cjs`,
59
+ ],
60
+ loaders: {
61
+ '.json': customLoader('json', options?.importFn),
62
+ '.yaml': customLoader('yaml', options?.importFn),
63
+ '.yml': customLoader('yaml', options?.importFn),
64
+ '.js': customLoader('js', options?.importFn),
65
+ '.ts': customLoader('js', options?.importFn),
66
+ noExt: customLoader('yaml', options?.importFn),
67
+ },
68
+ })
69
+ const results = await explorer.search(dir)
70
+
71
+ if (!results) {
72
+ throw new Error(`No ${configName} config file found in "${dir}"!`)
73
+ }
74
+
75
+ const { config } = results
76
+ return config
77
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@graphcommerce/cli",
3
+ "homepage": "https://www.graphcommerce.org/",
4
+ "repository": "github:graphcommerce-org/graphcommerce",
5
+ "version": "1.0.0",
6
+ "author": "",
7
+ "license": "MIT",
8
+ "scripts": {
9
+ "dev": "tsc --preserveWatchOutput --watch --sourceMap --outDir dist",
10
+ "build": "tsc --target es5 --outDir dist",
11
+ "prepack": "yarn build"
12
+ },
13
+ "bin": {
14
+ "mesh": "dist/bin/mesh.js",
15
+ "gql-mesh": "dist/bin/mesh.js",
16
+ "graphql-mesh": "dist/bin/mesh.js",
17
+ "gql-gen": "dist/bin/codegen.js",
18
+ "graphql-codegen": "dist/bin/codegen.js",
19
+ "graphql-code-generator": "dist/bin/codegen.js"
20
+ },
21
+ "dependencies": {
22
+ "@graphql-codegen/cli": "2.6.2",
23
+ "@graphql-mesh/cli": "0.67.4",
24
+ "@graphql-mesh/types": "0.70.5",
25
+ "@graphql-mesh/utils": "0.33.5"
26
+ },
27
+ "devDependencies": {
28
+ "@graphcommerce/eslint-config-pwa": "^4.1.5",
29
+ "@graphcommerce/prettier-config-pwa": "^4.0.6",
30
+ "@graphcommerce/typescript-config-pwa": "^4.0.2",
31
+ "@playwright/test": "^1.21.1",
32
+ "typescript": "4.6.3"
33
+ },
34
+ "sideEffects": false,
35
+ "prettier": "@graphcommerce/prettier-config-pwa",
36
+ "eslint": {
37
+ "extends": "@graphcommerce/eslint-config-pwa"
38
+ },
39
+ "eslintConfig": {
40
+ "extends": "@graphcommerce/eslint-config-pwa",
41
+ "parserOptions": {
42
+ "project": "./tsconfig.json"
43
+ }
44
+ }
45
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "exclude": ["**/node_modules", "**/.*/"],
3
+ "include": ["**/*.ts", "**/*.tsx"],
4
+ "extends": "@graphcommerce/typescript-config-pwa/node.json",
5
+ "compilerOptions": {
6
+ "noEmit": false,
7
+ "outDir": "dist"
8
+ }
9
+ }