1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const fs = require("fs-extra");
|
4 | const readJSON = require("load-json-file");
|
5 | const _ = require("lodash");
|
6 | const os = require("os");
|
7 | const path = require("path");
|
8 | const readPkg = require("read-pkg");
|
9 | const util_1 = require("util");
|
10 | const _pjson = require('../package.json');
|
11 | const _base = `${_pjson.name}@${_pjson.version}`;
|
12 | const debug = require('debug')('@anycli/config');
|
13 | class Config {
|
14 | constructor() {
|
15 | |
16 |
|
17 |
|
18 |
|
19 | this._base = _base;
|
20 | this.debug = 0;
|
21 | this.legacy = false;
|
22 | this.arch = (os.arch() === 'ia32' ? 'x86' : os.arch());
|
23 | this.platform = os.platform();
|
24 | this.windows = this.platform === 'win32';
|
25 | }
|
26 | async load(root, pjson, baseConfig) {
|
27 | const base = baseConfig || {};
|
28 | this.root = root;
|
29 | this.pjson = pjson;
|
30 | this.name = this.pjson.name;
|
31 | this.version = this.pjson.version;
|
32 | if (!this.pjson.anycli) {
|
33 | this.legacy = true;
|
34 | this.pjson.anycli = this.pjson['cli-engine'] || {};
|
35 | }
|
36 | this.bin = this.pjson.anycli.bin || base.bin || this.name;
|
37 | this.dirname = this.pjson.anycli.dirname || base.dirname || this.name;
|
38 | this.userAgent = `${this.name}/${this.version} (${this.platform}-${this.arch}) node-${process.version}`;
|
39 | this.shell = this._shell();
|
40 | this.debug = this._debug();
|
41 | this.home = process.env.HOME || (this.windows && this.windowsHome()) || os.homedir() || os.tmpdir();
|
42 | this.cacheDir = this.scopedEnvVar('CACHE_DIR') || this.macosCacheDir() || this.dir('cache');
|
43 | this.configDir = this.scopedEnvVar('CONFIG_DIR') || this.dir('config');
|
44 | this.dataDir = this.scopedEnvVar('DATA_DIR') || this.dir('data');
|
45 | this.errlog = path.join(this.cacheDir, 'error.log');
|
46 | this.tsconfig = await this._tsConfig();
|
47 | if (this.pjson.anycli.commands) {
|
48 | this.commandsDir = path.join(this.root, this.pjson.anycli.commands);
|
49 | this.commandsDirTS = await this._tsPath(this.pjson.anycli.commands);
|
50 | }
|
51 | this.hooks = _.mapValues(this.pjson.anycli.hooks || {}, h => _.castArray(h).map(h => path.join(this.root, h)));
|
52 | this.hooksTS = await this._hooks();
|
53 | if (typeof this.pjson.anycli.plugins === 'string') {
|
54 | this.pluginsModule = path.join(this.root, this.pjson.anycli.plugins);
|
55 | this.pluginsModuleTS = await this._tsPath(this.pjson.anycli.plugins);
|
56 | }
|
57 | this.npmRegistry = this.scopedEnvVar('NPM_REGISTRY') || this.pjson.anycli.npmRegistry || 'https://registry.yarnpkg.com';
|
58 | this.topics = topicsToArray(this.pjson.anycli.topics || {});
|
59 | return this;
|
60 | }
|
61 | scopedEnvVar(k) {
|
62 | return process.env[this.scopedEnvVarKey(k)];
|
63 | }
|
64 | scopedEnvVarTrue(k) {
|
65 | let v = process.env[this.scopedEnvVarKey(k)];
|
66 | return v === '1' || v === 'true';
|
67 | }
|
68 | scopedEnvVarKey(k) {
|
69 | return [this.bin, k]
|
70 | .map(p => p.replace(/-/g, '_'))
|
71 | .join('_')
|
72 | .toUpperCase();
|
73 | }
|
74 | _topics() {
|
75 | }
|
76 | dir(category) {
|
77 | const base = process.env[`XDG_${category.toUpperCase()}_HOME`]
|
78 | || (this.windows && process.env.LOCALAPPDATA)
|
79 | || path.join(this.home, category === 'data' ? '.local/share' : '.' + category);
|
80 | return path.join(base, this.dirname);
|
81 | }
|
82 | windowsHome() { return this.windowsHomedriveHome() || this.windowsUserprofileHome(); }
|
83 | windowsHomedriveHome() { return (process.env.HOMEDRIVE && process.env.HOMEPATH && path.join(process.env.HOMEDRIVE, process.env.HOMEPATH)); }
|
84 | windowsUserprofileHome() { return process.env.USERPROFILE; }
|
85 | macosCacheDir() { return this.platform === 'darwin' && path.join(this.home, 'Library', 'Caches', this.dirname) || undefined; }
|
86 | async _tsConfig() {
|
87 | try {
|
88 |
|
89 | if (!await fs.pathExists(path.join(this.root, '.git')))
|
90 | return;
|
91 | const tsconfigPath = path.join(this.root, 'tsconfig.json');
|
92 | const tsconfig = await readJSON(tsconfigPath);
|
93 | if (!tsconfig || !tsconfig.compilerOptions)
|
94 | return;
|
95 | return tsconfig;
|
96 | }
|
97 | catch (err) {
|
98 | if (err.code !== 'ENOENT')
|
99 | throw err;
|
100 | }
|
101 | }
|
102 | |
103 |
|
104 |
|
105 |
|
106 |
|
107 | async _tsPath(orig) {
|
108 | if (!orig || !this.tsconfig)
|
109 | return;
|
110 | orig = path.join(this.root, orig);
|
111 | let { rootDirs, outDir } = this.tsconfig.compilerOptions;
|
112 | if (!rootDirs || !rootDirs.length || !outDir)
|
113 | return;
|
114 | let rootDir = rootDirs[0];
|
115 | try {
|
116 |
|
117 | const lib = path.join(this.root, outDir);
|
118 | const src = path.join(this.root, rootDir);
|
119 | const relative = path.relative(lib, orig);
|
120 | const out = path.join(src, relative);
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 | if (await fs.pathExists(out) || await fs.pathExists(out + '.ts'))
|
127 | return out;
|
128 | return out;
|
129 | }
|
130 | catch (err) {
|
131 | debug(err);
|
132 | return;
|
133 | }
|
134 | }
|
135 | async _hooks() {
|
136 | const hooks = {};
|
137 | if (_.isEmpty(this.pjson.anycli.hooks))
|
138 | return;
|
139 | for (let [k, h] of Object.entries(this.pjson.anycli.hooks)) {
|
140 | hooks[k] = [];
|
141 | for (let m of _.castArray(h)) {
|
142 | const ts = await this._tsPath(m);
|
143 | if (!ts)
|
144 | return;
|
145 | hooks[k].push(ts);
|
146 | }
|
147 | }
|
148 | return hooks;
|
149 | }
|
150 | _shell() {
|
151 | let shellPath;
|
152 | const { SHELL, COMSPEC } = process.env;
|
153 | if (SHELL) {
|
154 | shellPath = SHELL.split('/');
|
155 | }
|
156 | else if (this.windows && COMSPEC) {
|
157 | shellPath = COMSPEC.split(/\\|\//);
|
158 | }
|
159 | else {
|
160 | shellPath = ['unknown'];
|
161 | }
|
162 | return shellPath[shellPath.length - 1];
|
163 | }
|
164 | _debug() {
|
165 | try {
|
166 | const { enabled } = require('debug')(this.bin);
|
167 | if (enabled)
|
168 | return 1;
|
169 | if (this.scopedEnvVarTrue('DEBUG'))
|
170 | return 1;
|
171 | return 0;
|
172 |
|
173 | }
|
174 | catch (err) {
|
175 | return 0;
|
176 | }
|
177 | }
|
178 | }
|
179 | exports.Config = Config;
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 | async function findPkg(name, root) {
|
188 |
|
189 | function* up(from) {
|
190 | while (path.dirname(from) !== from) {
|
191 | yield from;
|
192 | from = path.dirname(from);
|
193 | }
|
194 | yield from;
|
195 | }
|
196 | for (let next of up(root)) {
|
197 | let cur;
|
198 | if (name) {
|
199 | cur = path.join(next, 'node_modules', name, 'package.json');
|
200 | }
|
201 | else {
|
202 | cur = path.join(next, 'package.json');
|
203 | }
|
204 | if (await fs.pathExists(cur))
|
205 | return cur;
|
206 | }
|
207 | }
|
208 |
|
209 |
|
210 |
|
211 | function isIConfig(o) {
|
212 | return !!o._base;
|
213 | }
|
214 | exports.isIConfig = isIConfig;
|
215 |
|
216 |
|
217 |
|
218 | async function read(opts = {}) {
|
219 | let root = opts.root || (module.parent && module.parent.parent && module.parent.parent.filename) || __dirname;
|
220 | const pkgPath = await findPkg(opts.name, root);
|
221 | if (!pkgPath)
|
222 | throw new Error(`could not find package.json with ${util_1.inspect(opts)}`);
|
223 | debug('reading plugin %s', path.dirname(pkgPath));
|
224 | const pkg = await readPkg(pkgPath);
|
225 | const config = new Config();
|
226 | await config.load(path.dirname(pkgPath), pkg, opts.baseConfig);
|
227 | return config;
|
228 | }
|
229 | exports.read = read;
|
230 | function topicsToArray(input, base) {
|
231 | if (!input)
|
232 | return [];
|
233 | base = base ? `${base}:` : '';
|
234 | if (Array.isArray(input)) {
|
235 | return input.concat(_.flatMap(input, t => topicsToArray(t.subtopics, `${base}${t.name}`)));
|
236 | }
|
237 | return _.flatMap(Object.keys(input), k => {
|
238 | return [Object.assign({}, input[k], { name: `${base}${k}` })].concat(topicsToArray(input[k].subtopics, `${base}${input[k].name}`));
|
239 | });
|
240 | }
|