blob: 5cde7bc783e6c2b951a86188c1a2e1bca3fad944 [file] [log] [blame]
Leo Repp58b9f112021-11-22 11:57:47 +01001'use strict';
2const fs = require('fs');
3const path = require('path');
4const types = require('./types');
5
6// https://github.com/npm/npm/blob/latest/lib/config/core.js#L409-L423
7const envReplace = str => {
8 if (typeof str !== 'string' || !str) {
9 return str;
10 }
11
12 // Replace any ${ENV} values with the appropriate environment
13 const regex = /(\\*)\$\{([^}]+)\}/g;
14
15 return str.replace(regex, (orig, esc, name) => {
16 esc = esc.length > 0 && esc.length % 2;
17
18 if (esc) {
19 return orig;
20 }
21
22 if (process.env[name] === undefined) {
23 throw new Error(`Failed to replace env in config: ${orig}`);
24 }
25
26 return process.env[name];
27 });
28};
29
30// https://github.com/npm/npm/blob/latest/lib/config/core.js#L362-L407
31const parseField = (field, key) => {
32 if (typeof field !== 'string') {
33 return field;
34 }
35
36 const typeList = [].concat(types[key]);
37 const isPath = typeList.indexOf(path) !== -1;
38 const isBool = typeList.indexOf(Boolean) !== -1;
39 const isString = typeList.indexOf(String) !== -1;
40 const isNumber = typeList.indexOf(Number) !== -1;
41
42 field = `${field}`.trim();
43
44 if (/^".*"$/.test(field)) {
45 try {
46 field = JSON.parse(field);
47 } catch (err) {
48 throw new Error(`Failed parsing JSON config key ${key}: ${field}`);
49 }
50 }
51
52 if (isBool && !isString && field === '') {
53 return true;
54 }
55
56 switch (field) { // eslint-disable-line default-case
57 case 'true': {
58 return true;
59 }
60
61 case 'false': {
62 return false;
63 }
64
65 case 'null': {
66 return null;
67 }
68
69 case 'undefined': {
70 return undefined;
71 }
72 }
73
74 field = envReplace(field);
75
76 if (isPath) {
77 const regex = process.platform === 'win32' ? /^~(\/|\\)/ : /^~\//;
78
79 if (regex.test(field) && process.env.HOME) {
80 field = path.resolve(process.env.HOME, field.substr(2));
81 }
82
83 field = path.resolve(field);
84 }
85
86 if (isNumber && !field.isNan()) {
87 field = Number(field);
88 }
89
90 return field;
91};
92
93// https://github.com/npm/npm/blob/latest/lib/config/find-prefix.js
94const findPrefix = name => {
95 name = path.resolve(name);
96
97 let walkedUp = false;
98
99 while (path.basename(name) === 'node_modules') {
100 name = path.dirname(name);
101 walkedUp = true;
102 }
103
104 if (walkedUp) {
105 return name;
106 }
107
108 const find = (name, original) => {
109 const regex = /^[a-zA-Z]:(\\|\/)?$/;
110
111 if (name === '/' || (process.platform === 'win32' && regex.test(name))) {
112 return original;
113 }
114
115 try {
116 const files = fs.readdirSync(name);
117
118 if (files.indexOf('node_modules') !== -1 || files.indexOf('package.json') !== -1) {
119 return name;
120 }
121
122 const dirname = path.dirname(name);
123
124 if (dirname === name) {
125 return original;
126 }
127
128 return find(dirname, original);
129 } catch (err) {
130 if (name === original) {
131 if (err.code === 'ENOENT') {
132 return original;
133 }
134
135 throw err;
136 }
137
138 return original;
139 }
140 };
141
142 return find(name, name);
143};
144
145exports.envReplace = envReplace;
146exports.findPrefix = findPrefix;
147exports.parseField = parseField;