Skip to content
File

Blob: src/workerd/api/node/util.h

cpp269 lines
1// Copyright (c) 2023 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4#pragma once
5 
6#include <workerd/api/performance.h>
7#include <workerd/jsg/jsg.h>
8#include <workerd/util/mimetype.h>
9 
10namespace workerd::api::node {
11 
12// Originally implemented by Node.js contributors.
13// Available at https://github.com/nodejs/node/blob/b7b96282b212a2274b9db605ac29d388246754de/src/node_buffer.h#L75
14// This is verbose to be explicit with inline commenting
15static constexpr bool IsWithinBounds(size_t off, size_t len, size_t max) noexcept {
16 // Asking to seek too far into the buffer
17 // check to avoid wrapping in subsequent subtraction
18 if (off > max) return false;
19 
20 // Asking for more than is left over in the buffer
21 if (max - off < len) return false;
22 
23 // Otherwise we're in bounds
24 return true;
25}
26 
27class MIMEType;
28 
29class MIMEParams final: public jsg::Object {
30 private:
31 template <typename T>
32 struct IteratorState final {
33 kj::Array<T> values;
34 uint index = 0;
35 };
36 
37 public:
38 MIMEParams(kj::Maybe<MimeType&> mimeType = kj::none);
39 
40 static jsg::Ref<MIMEParams> constructor(jsg::Lock& js);
41 
42 void delete_(kj::String name);
43 kj::Maybe<kj::StringPtr> get(kj::String name);
44 bool has(kj::String name);
45 void set(kj::String name, kj::String value);
46 kj::String toString();
47 
48 JSG_ITERATOR(EntryIterator,
49 entries,
50 kj::Array<kj::String>,
51 IteratorState<kj::Array<kj::String>>,
52 iteratorNext<kj::Array<kj::String>>);
53 JSG_ITERATOR(KeyIterator, keys, kj::String, IteratorState<kj::String>, iteratorNext<kj::String>);
54 JSG_ITERATOR(
55 ValueIterator, values, kj::String, IteratorState<kj::String>, iteratorNext<kj::String>);
56 
57 JSG_RESOURCE_TYPE(MIMEParams) {
58 JSG_METHOD_NAMED(delete, delete_);
59 JSG_METHOD(get);
60 JSG_METHOD(has);
61 JSG_METHOD(set);
62 JSG_METHOD(entries);
63 JSG_METHOD(keys);
64 JSG_METHOD(values);
65 JSG_METHOD(toString);
66 JSG_METHOD_NAMED(toJSON, toString);
67 JSG_ITERABLE(entries);
68 }
69 
70 private:
71 template <typename T>
72 static kj::Maybe<T> iteratorNext(jsg::Lock& js, IteratorState<T>& state) {
73 if (state.index >= state.values.size()) {
74 return kj::none;
75 }
76 auto& item = state.values[state.index++];
77 if constexpr (kj::isSameType<T, kj::Array<kj::String>>()) {
78 return KJ_MAP(i, item) { return kj::str(i); };
79 } else {
80 static_assert(kj::isSameType<T, kj::String>());
81 return kj::str(item);
82 }
83 KJ_UNREACHABLE;
84 }
85 
86 kj::Maybe<MimeType&> mimeType;
87 friend class MIMEType;
88};
89 
90class MIMEType final: public jsg::Object {
91 public:
92 explicit MIMEType(jsg::Lock& js, MimeType inner);
93 ~MIMEType() noexcept(false);
94 static jsg::Ref<MIMEType> constructor(jsg::Lock& js, kj::String input);
95 
96 kj::StringPtr getType();
97 void setType(kj::String type);
98 kj::StringPtr getSubtype();
99 void setSubtype(kj::String subtype);
100 kj::String getEssence();
101 jsg::Ref<MIMEParams> getParams();
102 kj::String toString();
103 
104 JSG_RESOURCE_TYPE(MIMEType) {
105 JSG_PROTOTYPE_PROPERTY(type, getType, setType);
106 JSG_PROTOTYPE_PROPERTY(subtype, getSubtype, setSubtype);
107 JSG_READONLY_PROTOTYPE_PROPERTY(essence, getEssence);
108 JSG_READONLY_PROTOTYPE_PROPERTY(params, getParams);
109 JSG_METHOD(toString);
110 JSG_METHOD_NAMED(toJSON, toString);
111 }
112 
113 private:
114 workerd::MimeType inner;
115 jsg::Ref<MIMEParams> params;
116};
117 
118#define JS_UTIL_IS_TYPES(V) \
119 V(ArrayBufferView) \
120 V(ArgumentsObject) \
121 V(ArrayBuffer) \
122 V(AsyncFunction) \
123 V(BigInt64Array) \
124 V(BigIntObject) \
125 V(BigUint64Array) \
126 V(BooleanObject) \
127 V(DataView) \
128 V(Date) \
129 V(External) \
130 V(Float16Array) \
131 V(Float32Array) \
132 V(Float64Array) \
133 V(GeneratorFunction) \
134 V(GeneratorObject) \
135 V(Int8Array) \
136 V(Int16Array) \
137 V(Int32Array) \
138 V(Map) \
139 V(MapIterator) \
140 V(ModuleNamespaceObject) \
141 V(NativeError) \
142 V(NumberObject) \
143 V(Promise) \
144 V(Proxy) \
145 V(RegExp) \
146 V(Set) \
147 V(SetIterator) \
148 V(SharedArrayBuffer) \
149 V(StringObject) \
150 V(SymbolObject) \
151 V(TypedArray) \
152 V(Uint8Array) \
153 V(Uint8ClampedArray) \
154 V(Uint16Array) \
155 V(Uint32Array) \
156 V(WeakMap) \
157 V(WeakSet)
158 
159class UtilModule final: public jsg::Object {
160 public:
161 UtilModule() = default;
162 UtilModule(jsg::Lock&, const jsg::Url&) {}
163 
164 jsg::Name getResourceTypeInspect(jsg::Lock& js);
165 
166 // `getOwnNonIndexProperties()` `filter`s
167 static constexpr int ALL_PROPERTIES = jsg::PropertyFilter::ALL_PROPERTIES;
168 static constexpr int ONLY_ENUMERABLE = jsg::PropertyFilter::ONLY_ENUMERABLE;
169 
170 jsg::JsArray getOwnNonIndexProperties(jsg::Lock& js, jsg::JsObject value, int filter);
171 
172 // `PromiseDetails` `state`s
173 static constexpr int kPending = jsg::PromiseState::PENDING;
174 static constexpr int kFulfilled = jsg::PromiseState::FULFILLED;
175 static constexpr int kRejected = jsg::PromiseState::REJECTED;
176 
177 struct PromiseDetails {
178 int state; // TODO: can we make this a `jsg::PromiseState`
179 jsg::Optional<jsg::JsRef<jsg::JsValue>> result;
180 
181 JSG_STRUCT(state, result);
182 };
183 jsg::Optional<PromiseDetails> getPromiseDetails(jsg::Lock& js, jsg::JsValue value);
184 
185 struct ProxyDetails {
186 jsg::JsRef<jsg::JsValue> target;
187 jsg::JsRef<jsg::JsValue> handler;
188 
189 JSG_STRUCT(target, handler);
190 };
191 jsg::Optional<ProxyDetails> getProxyDetails(jsg::Lock& js, jsg::JsValue value);
192 
193 struct PreviewedEntries {
194 jsg::JsRef<jsg::JsArray> entries;
195 bool isKeyValue;
196 
197 JSG_STRUCT(entries, isKeyValue);
198 };
199 jsg::Optional<PreviewedEntries> previewEntries(jsg::Lock& js, jsg::JsValue value);
200 
201 jsg::JsString getConstructorName(jsg::Lock& js, jsg::JsObject value);
202 
203 struct CallSiteEntry {
204 kj::String functionName;
205 kj::String scriptName;
206 int lineNumber;
207 // Node.js originally introduced the API with the name `getCallSite()` as an experimental
208 // API but then renamed it to `getCallSites()` soon after. We had already implemented the
209 // API with the original name in a release. To avoid the possibility of breaking, we export
210 // the function using both names.
211 int columnNumber;
212 int column;
213 
214 JSG_STRUCT(functionName, scriptName, lineNumber, columnNumber, column);
215 };
216 kj::Array<CallSiteEntry> getCallSites(jsg::Lock& js, jsg::Optional<int> frames);
217 
218#define V(Type) bool is##Type(jsg::JsValue value);
219 JS_UTIL_IS_TYPES(V)
220#undef V
221 bool isAnyArrayBuffer(jsg::JsValue value);
222 bool isBoxedPrimitive(jsg::JsValue value);
223 
224 JSG_RESOURCE_TYPE(UtilModule) {
225 JSG_NESTED_TYPE(MIMEType);
226 JSG_NESTED_TYPE(MIMEParams);
227 
228 JSG_READONLY_INSTANCE_PROPERTY(kResourceTypeInspect, getResourceTypeInspect);
229 
230 JSG_STATIC_CONSTANT(ALL_PROPERTIES);
231 JSG_STATIC_CONSTANT(ONLY_ENUMERABLE);
232 JSG_METHOD(getOwnNonIndexProperties);
233 
234 JSG_STATIC_CONSTANT(kPending);
235 JSG_STATIC_CONSTANT(kFulfilled);
236 JSG_STATIC_CONSTANT(kRejected);
237 JSG_METHOD(getPromiseDetails);
238 
239 JSG_METHOD(getProxyDetails);
240 JSG_METHOD(previewEntries);
241 JSG_METHOD(getConstructorName);
242 JSG_METHOD(getCallSites);
243 
244 JSG_NESTED_TYPE(Performance);
245 JSG_NESTED_TYPE(PerformanceEntry);
246 JSG_NESTED_TYPE(PerformanceMeasure);
247 JSG_NESTED_TYPE(PerformanceMark);
248 JSG_NESTED_TYPE(PerformanceObserver);
249 JSG_NESTED_TYPE(PerformanceObserverEntryList);
250 JSG_NESTED_TYPE(PerformanceResourceTiming);
251 
252#define V(Type) JSG_METHOD(is##Type);
253 JS_UTIL_IS_TYPES(V)
254#undef V
255 JSG_METHOD(isAnyArrayBuffer);
256 JSG_METHOD(isBoxedPrimitive);
257 }
258};
259 
260#define EW_NODE_UTIL_ISOLATE_TYPES \
261 api::node::UtilModule, api::node::UtilModule::PromiseDetails, \
262 api::node::UtilModule::ProxyDetails, api::node::UtilModule::PreviewedEntries, \
263 api::node::MIMEType, api::node::MIMEParams, api::node::MIMEParams::EntryIterator, \
264 api::node::MIMEParams::ValueIterator, api::node::MIMEParams::KeyIterator, \
265 api::node::MIMEParams::EntryIterator::Next, api::node::MIMEParams::ValueIterator::Next, \
266 api::node::MIMEParams::KeyIterator::Next, api::node::UtilModule::CallSiteEntry
267 
268} // namespace workerd::api::node