eslint 8.5.0 → 8.9.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/README.md +6 -6
- package/bin/eslint.js +7 -1
- package/lib/cli-engine/cli-engine.js +10 -1
- package/lib/config/flat-config-array.js +5 -1
- package/lib/config/flat-config-helpers.js +37 -1
- package/lib/config/rule-validator.js +5 -35
- package/lib/eslint/eslint.js +6 -0
- package/lib/linter/apply-disable-directives.js +55 -60
- package/lib/linter/linter.js +90 -27
- package/lib/rule-tester/flat-rule-tester.js +1039 -0
- package/lib/rule-tester/rule-tester.js +5 -5
- package/lib/rules/camelcase.js +7 -1
- package/lib/rules/function-paren-newline.js +5 -1
- package/lib/rules/id-match.js +12 -1
- package/lib/rules/keyword-spacing.js +32 -0
- package/lib/rules/no-constant-condition.js +23 -4
- package/lib/rules/no-invalid-this.js +50 -53
- package/lib/rules/no-restricted-exports.js +9 -3
- package/lib/rules/no-restricted-imports.js +24 -7
- package/lib/rules/no-restricted-modules.js +2 -1
- package/lib/rules/no-self-assign.js +1 -1
- package/lib/rules/no-useless-rename.js +8 -4
- package/lib/rules/quotes.js +12 -1
- package/lib/rules/utils/ast-utils.js +21 -1
- package/lib/shared/types.js +15 -0
- package/messages/no-config-found.js +1 -1
- package/package.json +9 -9
- package/lib/init/autoconfig.js +0 -351
- package/lib/init/config-file.js +0 -144
- package/lib/init/config-initializer.js +0 -709
- package/lib/init/config-rule.js +0 -316
- package/lib/init/npm-utils.js +0 -179
- package/lib/init/source-code-utils.js +0 -110
package/lib/init/autoconfig.js
DELETED
@@ -1,351 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* @fileoverview Used for creating a suggested configuration based on project code.
|
3
|
-
* @author Ian VanSchooten
|
4
|
-
*/
|
5
|
-
|
6
|
-
"use strict";
|
7
|
-
|
8
|
-
//------------------------------------------------------------------------------
|
9
|
-
// Requirements
|
10
|
-
//------------------------------------------------------------------------------
|
11
|
-
|
12
|
-
const equal = require("fast-deep-equal"),
|
13
|
-
recConfig = require("../../conf/eslint-recommended"),
|
14
|
-
{
|
15
|
-
Legacy: {
|
16
|
-
ConfigOps
|
17
|
-
}
|
18
|
-
} = require("@eslint/eslintrc"),
|
19
|
-
{ Linter } = require("../linter"),
|
20
|
-
configRule = require("./config-rule");
|
21
|
-
|
22
|
-
const debug = require("debug")("eslint:autoconfig");
|
23
|
-
const linter = new Linter();
|
24
|
-
|
25
|
-
//------------------------------------------------------------------------------
|
26
|
-
// Data
|
27
|
-
//------------------------------------------------------------------------------
|
28
|
-
|
29
|
-
const MAX_CONFIG_COMBINATIONS = 17, // 16 combinations + 1 for severity only
|
30
|
-
RECOMMENDED_CONFIG_NAME = "eslint:recommended";
|
31
|
-
|
32
|
-
//------------------------------------------------------------------------------
|
33
|
-
// Private
|
34
|
-
//------------------------------------------------------------------------------
|
35
|
-
|
36
|
-
/**
|
37
|
-
* Information about a rule configuration, in the context of a Registry.
|
38
|
-
* @typedef {Object} registryItem
|
39
|
-
* @property {ruleConfig} config A valid configuration for the rule
|
40
|
-
* @property {number} specificity The number of elements in the ruleConfig array
|
41
|
-
* @property {number} errorCount The number of errors encountered when linting with the config
|
42
|
-
*/
|
43
|
-
|
44
|
-
/**
|
45
|
-
* This callback is used to measure execution status in a progress bar
|
46
|
-
* @callback progressCallback
|
47
|
-
* @param {number} The total number of times the callback will be called.
|
48
|
-
*/
|
49
|
-
|
50
|
-
/**
|
51
|
-
* Create registryItems for rules
|
52
|
-
* @param {rulesConfig} rulesConfig Hash of rule names and arrays of ruleConfig items
|
53
|
-
* @returns {Object} registryItems for each rule in provided rulesConfig
|
54
|
-
*/
|
55
|
-
function makeRegistryItems(rulesConfig) {
|
56
|
-
return Object.keys(rulesConfig).reduce((accumulator, ruleId) => {
|
57
|
-
accumulator[ruleId] = rulesConfig[ruleId].map(config => ({
|
58
|
-
config,
|
59
|
-
specificity: config.length || 1,
|
60
|
-
errorCount: void 0
|
61
|
-
}));
|
62
|
-
return accumulator;
|
63
|
-
}, {});
|
64
|
-
}
|
65
|
-
|
66
|
-
/**
|
67
|
-
* Creates an object in which to store rule configs and error counts
|
68
|
-
*
|
69
|
-
* Unless a rulesConfig is provided at construction, the registry will not contain
|
70
|
-
* any rules, only methods. This will be useful for building up registries manually.
|
71
|
-
*
|
72
|
-
* Registry class
|
73
|
-
*/
|
74
|
-
class Registry {
|
75
|
-
|
76
|
-
/**
|
77
|
-
* @param {rulesConfig} [rulesConfig] Hash of rule names and arrays of possible configurations
|
78
|
-
*/
|
79
|
-
constructor(rulesConfig) {
|
80
|
-
this.rules = (rulesConfig) ? makeRegistryItems(rulesConfig) : {};
|
81
|
-
}
|
82
|
-
|
83
|
-
/**
|
84
|
-
* Populate the registry with core rule configs.
|
85
|
-
*
|
86
|
-
* It will set the registry's `rule` property to an object having rule names
|
87
|
-
* as keys and an array of registryItems as values.
|
88
|
-
* @returns {void}
|
89
|
-
*/
|
90
|
-
populateFromCoreRules() {
|
91
|
-
const rulesConfig = configRule.createCoreRuleConfigs(/* noDeprecated = */ true);
|
92
|
-
|
93
|
-
this.rules = makeRegistryItems(rulesConfig);
|
94
|
-
}
|
95
|
-
|
96
|
-
/**
|
97
|
-
* Creates sets of rule configurations which can be used for linting
|
98
|
-
* and initializes registry errors to zero for those configurations (side effect).
|
99
|
-
*
|
100
|
-
* This combines as many rules together as possible, such that the first sets
|
101
|
-
* in the array will have the highest number of rules configured, and later sets
|
102
|
-
* will have fewer and fewer, as not all rules have the same number of possible
|
103
|
-
* configurations.
|
104
|
-
*
|
105
|
-
* The length of the returned array will be <= MAX_CONFIG_COMBINATIONS.
|
106
|
-
* @returns {Object[]} "rules" configurations to use for linting
|
107
|
-
*/
|
108
|
-
buildRuleSets() {
|
109
|
-
let idx = 0;
|
110
|
-
const ruleIds = Object.keys(this.rules),
|
111
|
-
ruleSets = [];
|
112
|
-
|
113
|
-
/**
|
114
|
-
* Add a rule configuration from the registry to the ruleSets
|
115
|
-
*
|
116
|
-
* This is broken out into its own function so that it doesn't need to be
|
117
|
-
* created inside of the while loop.
|
118
|
-
* @param {string} rule The ruleId to add.
|
119
|
-
* @returns {void}
|
120
|
-
*/
|
121
|
-
const addRuleToRuleSet = function(rule) {
|
122
|
-
|
123
|
-
/*
|
124
|
-
* This check ensures that there is a rule configuration and that
|
125
|
-
* it has fewer than the max combinations allowed.
|
126
|
-
* If it has too many configs, we will only use the most basic of
|
127
|
-
* the possible configurations.
|
128
|
-
*/
|
129
|
-
const hasFewCombos = (this.rules[rule].length <= MAX_CONFIG_COMBINATIONS);
|
130
|
-
|
131
|
-
if (this.rules[rule][idx] && (hasFewCombos || this.rules[rule][idx].specificity <= 2)) {
|
132
|
-
|
133
|
-
/*
|
134
|
-
* If the rule has too many possible combinations, only take
|
135
|
-
* simple ones, avoiding objects.
|
136
|
-
*/
|
137
|
-
if (!hasFewCombos && typeof this.rules[rule][idx].config[1] === "object") {
|
138
|
-
return;
|
139
|
-
}
|
140
|
-
|
141
|
-
ruleSets[idx] = ruleSets[idx] || {};
|
142
|
-
ruleSets[idx][rule] = this.rules[rule][idx].config;
|
143
|
-
|
144
|
-
/*
|
145
|
-
* Initialize errorCount to zero, since this is a config which
|
146
|
-
* will be linted.
|
147
|
-
*/
|
148
|
-
this.rules[rule][idx].errorCount = 0;
|
149
|
-
}
|
150
|
-
}.bind(this);
|
151
|
-
|
152
|
-
while (ruleSets.length === idx) {
|
153
|
-
ruleIds.forEach(addRuleToRuleSet);
|
154
|
-
idx += 1;
|
155
|
-
}
|
156
|
-
|
157
|
-
return ruleSets;
|
158
|
-
}
|
159
|
-
|
160
|
-
/**
|
161
|
-
* Remove all items from the registry with a non-zero number of errors
|
162
|
-
*
|
163
|
-
* Note: this also removes rule configurations which were not linted
|
164
|
-
* (meaning, they have an undefined errorCount).
|
165
|
-
* @returns {void}
|
166
|
-
*/
|
167
|
-
stripFailingConfigs() {
|
168
|
-
const ruleIds = Object.keys(this.rules),
|
169
|
-
newRegistry = new Registry();
|
170
|
-
|
171
|
-
newRegistry.rules = Object.assign({}, this.rules);
|
172
|
-
ruleIds.forEach(ruleId => {
|
173
|
-
const errorFreeItems = newRegistry.rules[ruleId].filter(registryItem => (registryItem.errorCount === 0));
|
174
|
-
|
175
|
-
if (errorFreeItems.length > 0) {
|
176
|
-
newRegistry.rules[ruleId] = errorFreeItems;
|
177
|
-
} else {
|
178
|
-
delete newRegistry.rules[ruleId];
|
179
|
-
}
|
180
|
-
});
|
181
|
-
|
182
|
-
return newRegistry;
|
183
|
-
}
|
184
|
-
|
185
|
-
/**
|
186
|
-
* Removes rule configurations which were not included in a ruleSet
|
187
|
-
* @returns {void}
|
188
|
-
*/
|
189
|
-
stripExtraConfigs() {
|
190
|
-
const ruleIds = Object.keys(this.rules),
|
191
|
-
newRegistry = new Registry();
|
192
|
-
|
193
|
-
newRegistry.rules = Object.assign({}, this.rules);
|
194
|
-
ruleIds.forEach(ruleId => {
|
195
|
-
newRegistry.rules[ruleId] = newRegistry.rules[ruleId].filter(registryItem => (typeof registryItem.errorCount !== "undefined"));
|
196
|
-
});
|
197
|
-
|
198
|
-
return newRegistry;
|
199
|
-
}
|
200
|
-
|
201
|
-
/**
|
202
|
-
* Creates a registry of rules which had no error-free configs.
|
203
|
-
* The new registry is intended to be analyzed to determine whether its rules
|
204
|
-
* should be disabled or set to warning.
|
205
|
-
* @returns {Registry} A registry of failing rules.
|
206
|
-
*/
|
207
|
-
getFailingRulesRegistry() {
|
208
|
-
const ruleIds = Object.keys(this.rules),
|
209
|
-
failingRegistry = new Registry();
|
210
|
-
|
211
|
-
ruleIds.forEach(ruleId => {
|
212
|
-
const failingConfigs = this.rules[ruleId].filter(registryItem => (registryItem.errorCount > 0));
|
213
|
-
|
214
|
-
if (failingConfigs && failingConfigs.length === this.rules[ruleId].length) {
|
215
|
-
failingRegistry.rules[ruleId] = failingConfigs;
|
216
|
-
}
|
217
|
-
});
|
218
|
-
|
219
|
-
return failingRegistry;
|
220
|
-
}
|
221
|
-
|
222
|
-
/**
|
223
|
-
* Create an eslint config for any rules which only have one configuration
|
224
|
-
* in the registry.
|
225
|
-
* @returns {Object} An eslint config with rules section populated
|
226
|
-
*/
|
227
|
-
createConfig() {
|
228
|
-
const ruleIds = Object.keys(this.rules),
|
229
|
-
config = { rules: {} };
|
230
|
-
|
231
|
-
ruleIds.forEach(ruleId => {
|
232
|
-
if (this.rules[ruleId].length === 1) {
|
233
|
-
config.rules[ruleId] = this.rules[ruleId][0].config;
|
234
|
-
}
|
235
|
-
});
|
236
|
-
|
237
|
-
return config;
|
238
|
-
}
|
239
|
-
|
240
|
-
/**
|
241
|
-
* Return a cloned registry containing only configs with a desired specificity
|
242
|
-
* @param {number} specificity Only keep configs with this specificity
|
243
|
-
* @returns {Registry} A registry of rules
|
244
|
-
*/
|
245
|
-
filterBySpecificity(specificity) {
|
246
|
-
const ruleIds = Object.keys(this.rules),
|
247
|
-
newRegistry = new Registry();
|
248
|
-
|
249
|
-
newRegistry.rules = Object.assign({}, this.rules);
|
250
|
-
ruleIds.forEach(ruleId => {
|
251
|
-
newRegistry.rules[ruleId] = this.rules[ruleId].filter(registryItem => (registryItem.specificity === specificity));
|
252
|
-
});
|
253
|
-
|
254
|
-
return newRegistry;
|
255
|
-
}
|
256
|
-
|
257
|
-
/**
|
258
|
-
* Lint SourceCodes against all configurations in the registry, and record results
|
259
|
-
* @param {Object[]} sourceCodes SourceCode objects for each filename
|
260
|
-
* @param {Object} config ESLint config object
|
261
|
-
* @param {progressCallback} [cb] Optional callback for reporting execution status
|
262
|
-
* @returns {Registry} New registry with errorCount populated
|
263
|
-
*/
|
264
|
-
lintSourceCode(sourceCodes, config, cb) {
|
265
|
-
let lintedRegistry = new Registry();
|
266
|
-
|
267
|
-
lintedRegistry.rules = Object.assign({}, this.rules);
|
268
|
-
|
269
|
-
const ruleSets = lintedRegistry.buildRuleSets();
|
270
|
-
|
271
|
-
lintedRegistry = lintedRegistry.stripExtraConfigs();
|
272
|
-
|
273
|
-
debug("Linting with all possible rule combinations");
|
274
|
-
|
275
|
-
const filenames = Object.keys(sourceCodes);
|
276
|
-
const totalFilesLinting = filenames.length * ruleSets.length;
|
277
|
-
|
278
|
-
filenames.forEach(filename => {
|
279
|
-
debug(`Linting file: ${filename}`);
|
280
|
-
|
281
|
-
let ruleSetIdx = 0;
|
282
|
-
|
283
|
-
ruleSets.forEach(ruleSet => {
|
284
|
-
const lintConfig = Object.assign({}, config, { rules: ruleSet });
|
285
|
-
const lintResults = linter.verify(sourceCodes[filename], lintConfig);
|
286
|
-
|
287
|
-
lintResults.forEach(result => {
|
288
|
-
|
289
|
-
/*
|
290
|
-
* It is possible that the error is from a configuration comment
|
291
|
-
* in a linted file, in which case there may not be a config
|
292
|
-
* set in this ruleSetIdx.
|
293
|
-
* (https://github.com/eslint/eslint/issues/5992)
|
294
|
-
* (https://github.com/eslint/eslint/issues/7860)
|
295
|
-
*/
|
296
|
-
if (
|
297
|
-
lintedRegistry.rules[result.ruleId] &&
|
298
|
-
lintedRegistry.rules[result.ruleId][ruleSetIdx]
|
299
|
-
) {
|
300
|
-
lintedRegistry.rules[result.ruleId][ruleSetIdx].errorCount += 1;
|
301
|
-
}
|
302
|
-
});
|
303
|
-
|
304
|
-
ruleSetIdx += 1;
|
305
|
-
|
306
|
-
if (cb) {
|
307
|
-
cb(totalFilesLinting); // eslint-disable-line node/callback-return -- End of function
|
308
|
-
}
|
309
|
-
});
|
310
|
-
|
311
|
-
// Deallocate for GC
|
312
|
-
sourceCodes[filename] = null;
|
313
|
-
});
|
314
|
-
|
315
|
-
return lintedRegistry;
|
316
|
-
}
|
317
|
-
}
|
318
|
-
|
319
|
-
/**
|
320
|
-
* Extract rule configuration into eslint:recommended where possible.
|
321
|
-
*
|
322
|
-
* This will return a new config with `["extends": [ ..., "eslint:recommended"]` and
|
323
|
-
* only the rules which have configurations different from the recommended config.
|
324
|
-
* @param {Object} config config object
|
325
|
-
* @returns {Object} config object using `"extends": ["eslint:recommended"]`
|
326
|
-
*/
|
327
|
-
function extendFromRecommended(config) {
|
328
|
-
const newConfig = Object.assign({}, config);
|
329
|
-
|
330
|
-
ConfigOps.normalizeToStrings(newConfig);
|
331
|
-
|
332
|
-
const recRules = Object.keys(recConfig.rules).filter(ruleId => ConfigOps.isErrorSeverity(recConfig.rules[ruleId]));
|
333
|
-
|
334
|
-
recRules.forEach(ruleId => {
|
335
|
-
if (equal(recConfig.rules[ruleId], newConfig.rules[ruleId])) {
|
336
|
-
delete newConfig.rules[ruleId];
|
337
|
-
}
|
338
|
-
});
|
339
|
-
newConfig.extends.unshift(RECOMMENDED_CONFIG_NAME);
|
340
|
-
return newConfig;
|
341
|
-
}
|
342
|
-
|
343
|
-
|
344
|
-
//------------------------------------------------------------------------------
|
345
|
-
// Public Interface
|
346
|
-
//------------------------------------------------------------------------------
|
347
|
-
|
348
|
-
module.exports = {
|
349
|
-
Registry,
|
350
|
-
extendFromRecommended
|
351
|
-
};
|
package/lib/init/config-file.js
DELETED
@@ -1,144 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* @fileoverview Helper to locate and load configuration files.
|
3
|
-
* @author Nicholas C. Zakas
|
4
|
-
*/
|
5
|
-
|
6
|
-
"use strict";
|
7
|
-
|
8
|
-
//------------------------------------------------------------------------------
|
9
|
-
// Requirements
|
10
|
-
//------------------------------------------------------------------------------
|
11
|
-
|
12
|
-
const fs = require("fs"),
|
13
|
-
path = require("path"),
|
14
|
-
stringify = require("json-stable-stringify-without-jsonify");
|
15
|
-
|
16
|
-
const debug = require("debug")("eslint:config-file");
|
17
|
-
|
18
|
-
//------------------------------------------------------------------------------
|
19
|
-
// Helpers
|
20
|
-
//------------------------------------------------------------------------------
|
21
|
-
|
22
|
-
/**
|
23
|
-
* Determines sort order for object keys for json-stable-stringify
|
24
|
-
*
|
25
|
-
* see: https://github.com/samn/json-stable-stringify#cmp
|
26
|
-
* @param {Object} a The first comparison object ({key: akey, value: avalue})
|
27
|
-
* @param {Object} b The second comparison object ({key: bkey, value: bvalue})
|
28
|
-
* @returns {number} 1 or -1, used in stringify cmp method
|
29
|
-
*/
|
30
|
-
function sortByKey(a, b) {
|
31
|
-
return a.key > b.key ? 1 : -1;
|
32
|
-
}
|
33
|
-
|
34
|
-
//------------------------------------------------------------------------------
|
35
|
-
// Private
|
36
|
-
//------------------------------------------------------------------------------
|
37
|
-
|
38
|
-
/**
|
39
|
-
* Writes a configuration file in JSON format.
|
40
|
-
* @param {Object} config The configuration object to write.
|
41
|
-
* @param {string} filePath The filename to write to.
|
42
|
-
* @returns {void}
|
43
|
-
* @private
|
44
|
-
*/
|
45
|
-
function writeJSONConfigFile(config, filePath) {
|
46
|
-
debug(`Writing JSON config file: ${filePath}`);
|
47
|
-
|
48
|
-
const content = `${stringify(config, { cmp: sortByKey, space: 4 })}\n`;
|
49
|
-
|
50
|
-
fs.writeFileSync(filePath, content, "utf8");
|
51
|
-
}
|
52
|
-
|
53
|
-
/**
|
54
|
-
* Writes a configuration file in YAML format.
|
55
|
-
* @param {Object} config The configuration object to write.
|
56
|
-
* @param {string} filePath The filename to write to.
|
57
|
-
* @returns {void}
|
58
|
-
* @private
|
59
|
-
*/
|
60
|
-
function writeYAMLConfigFile(config, filePath) {
|
61
|
-
debug(`Writing YAML config file: ${filePath}`);
|
62
|
-
|
63
|
-
// lazy load YAML to improve performance when not used
|
64
|
-
const yaml = require("js-yaml");
|
65
|
-
|
66
|
-
const content = yaml.dump(config, { sortKeys: true });
|
67
|
-
|
68
|
-
fs.writeFileSync(filePath, content, "utf8");
|
69
|
-
}
|
70
|
-
|
71
|
-
/**
|
72
|
-
* Writes a configuration file in JavaScript format.
|
73
|
-
* @param {Object} config The configuration object to write.
|
74
|
-
* @param {string} filePath The filename to write to.
|
75
|
-
* @throws {Error} If an error occurs linting the config file contents.
|
76
|
-
* @returns {void}
|
77
|
-
* @private
|
78
|
-
*/
|
79
|
-
function writeJSConfigFile(config, filePath) {
|
80
|
-
debug(`Writing JS config file: ${filePath}`);
|
81
|
-
|
82
|
-
let contentToWrite;
|
83
|
-
const stringifiedContent = `module.exports = ${stringify(config, { cmp: sortByKey, space: 4 })};\n`;
|
84
|
-
|
85
|
-
try {
|
86
|
-
const { CLIEngine } = require("../cli-engine");
|
87
|
-
const linter = new CLIEngine({
|
88
|
-
baseConfig: config,
|
89
|
-
fix: true,
|
90
|
-
useEslintrc: false
|
91
|
-
});
|
92
|
-
const report = linter.executeOnText(stringifiedContent);
|
93
|
-
|
94
|
-
contentToWrite = report.results[0].output || stringifiedContent;
|
95
|
-
} catch (e) {
|
96
|
-
debug("Error linting JavaScript config file, writing unlinted version");
|
97
|
-
const errorMessage = e.message;
|
98
|
-
|
99
|
-
contentToWrite = stringifiedContent;
|
100
|
-
e.message = "An error occurred while generating your JavaScript config file. ";
|
101
|
-
e.message += "A config file was still generated, but the config file itself may not follow your linting rules.";
|
102
|
-
e.message += `\nError: ${errorMessage}`;
|
103
|
-
throw e;
|
104
|
-
} finally {
|
105
|
-
fs.writeFileSync(filePath, contentToWrite, "utf8");
|
106
|
-
}
|
107
|
-
}
|
108
|
-
|
109
|
-
/**
|
110
|
-
* Writes a configuration file.
|
111
|
-
* @param {Object} config The configuration object to write.
|
112
|
-
* @param {string} filePath The filename to write to.
|
113
|
-
* @returns {void}
|
114
|
-
* @throws {Error} When an unknown file type is specified.
|
115
|
-
* @private
|
116
|
-
*/
|
117
|
-
function write(config, filePath) {
|
118
|
-
switch (path.extname(filePath)) {
|
119
|
-
case ".js":
|
120
|
-
case ".cjs":
|
121
|
-
writeJSConfigFile(config, filePath);
|
122
|
-
break;
|
123
|
-
|
124
|
-
case ".json":
|
125
|
-
writeJSONConfigFile(config, filePath);
|
126
|
-
break;
|
127
|
-
|
128
|
-
case ".yaml":
|
129
|
-
case ".yml":
|
130
|
-
writeYAMLConfigFile(config, filePath);
|
131
|
-
break;
|
132
|
-
|
133
|
-
default:
|
134
|
-
throw new Error("Can't write to unknown file type.");
|
135
|
-
}
|
136
|
-
}
|
137
|
-
|
138
|
-
//------------------------------------------------------------------------------
|
139
|
-
// Public Interface
|
140
|
-
//------------------------------------------------------------------------------
|
141
|
-
|
142
|
-
module.exports = {
|
143
|
-
write
|
144
|
-
};
|