-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.js
More file actions
122 lines (109 loc) · 3.32 KB
/
utils.js
File metadata and controls
122 lines (109 loc) · 3.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
const is = require('is-type-of');
const { file } = require('ys-utils');
exports.getProperties = getProperties;
exports.getExports = getExports;
exports.defaultCamelize = defaultCamelize;
exports.getInstance = getInstance;
class ClassLoader {
constructor(options) {
if (!options.ctx) {
throw new Error('options.ctx is required');
}
const properties = options.properties;
this._cache = new Map();
this._ctx = options.ctx;
for (const property in properties) {
this.defineProperty(property, properties[property], options.runtime);
}
}
defineProperty(property, values, runtime) {
Object.defineProperty(this, property, {
get() {
let instance = this._cache.get(property);
if (!instance) {
instance = getInstance(values, this._ctx, runtime);
this._cache.set(property, instance);
}
return instance;
},
});
}
}
function getExports(fullpath, { initializer, call, inject }, pathName) {
let result = file.load(fullpath);
if (initializer) {
result = initializer(result, { path: fullpath, pathName });
}
if (is.class(result) || is.generatorFunction(result) || is.asyncFunction(result)) {
return result;
}
if (call && is.function(result)) {
result = result(inject);
if (result != null) {
return result;
}
}
return result;
}
function getProperties(filepath, { caseStyle, lowercaseFirst }) {
// if caseStyle is function, return the result of function
if (typeof caseStyle === 'function') {
const result = caseStyle(filepath);
if (!Array.isArray(result)) {
throw new Error(`caseStyle expect an array, but got ${result}`);
}
return result;
}
// use default camelize
return defaultCamelize(filepath, caseStyle, lowercaseFirst);
}
function defaultCamelize(filepath, caseStyle, lowercaseFirst) {
const properties = filepath.substring(0, filepath.lastIndexOf('.')).split('/');
return properties.map(property => {
if (!/^[a-z][a-z0-9_-]*$/i.test(property)) {
throw new Error(`${property} is not match 'a-z0-9_-' in ${filepath}`);
}
// use default camelize, will capitalize the first letter
// foo_bar.js > FooBar
// fooBar.js > FooBar
// FooBar.js > FooBar
// FooBar.js > FooBar
// FooBar.js > fooBar (if lowercaseFirst is true)
property = property.replace(/[_-][a-z]/ig, s => s.substring(1).toUpperCase());
let first = property[0];
switch (caseStyle) {
case 'lower':
first = first.toLowerCase();
break;
case 'upper':
first = first.toUpperCase();
break;
case 'camel':
default:
}
if (lowercaseFirst) first = first.toLowerCase();
return first + property.substring(1);
});
}
function getInstance(values, ctx, runtime) {
// it's a directory when it has no exports
// then use ClassLoader
const Class = values.EXPORTS ? values : null;
let instance;
if (Class) {
if (is.class(Class)) {
instance = runtime(Class, ctx);
} else {
// it's just an object
instance = Class;
}
// Can't set property to primitive, so check again
// e.x. module.exports = 1;
} else if (is.primitive(values)) {
instance = values;
} else {
instance = new ClassLoader({ ctx, properties: values, runtime });
}
return instance;
}
exports.ClassLoader = ClassLoader;