GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/module_wrap.cc Lines: 658 781 84.3 %
Date: 2019-10-05 22:32:21 Branches: 366 563 65.0 %

Line Branch Exec Source
1
#include "module_wrap.h"
2
3
#include "env.h"
4
#include "memory_tracker-inl.h"
5
#include "node_errors.h"
6
#include "node_url.h"
7
#include "util-inl.h"
8
#include "node_contextify.h"
9
#include "node_watchdog.h"
10
11
#include <sys/stat.h>  // S_IFDIR
12
13
#include <algorithm>
14
#include <climits>  // PATH_MAX
15
16
namespace node {
17
namespace loader {
18
19
using errors::TryCatchScope;
20
21
using node::contextify::ContextifyContext;
22
using node::url::URL;
23
using node::url::URL_FLAGS_FAILED;
24
using v8::Array;
25
using v8::Context;
26
using v8::Function;
27
using v8::FunctionCallbackInfo;
28
using v8::FunctionTemplate;
29
using v8::Global;
30
using v8::HandleScope;
31
using v8::Integer;
32
using v8::IntegrityLevel;
33
using v8::Isolate;
34
using v8::Just;
35
using v8::Local;
36
using v8::Maybe;
37
using v8::MaybeLocal;
38
using v8::Module;
39
using v8::Nothing;
40
using v8::Number;
41
using v8::Object;
42
using v8::PrimitiveArray;
43
using v8::Promise;
44
using v8::ScriptCompiler;
45
using v8::ScriptOrigin;
46
using v8::String;
47
using v8::Undefined;
48
using v8::Value;
49
50
static const char* const EXTENSIONS[] = {
51
  ".mjs",
52
  ".cjs",
53
  ".js",
54
  ".json",
55
  ".node"
56
};
57
58
719
ModuleWrap::ModuleWrap(Environment* env,
59
                       Local<Object> object,
60
                       Local<Module> module,
61
                       Local<String> url) :
62
  BaseObject(env, object),
63
2876
  id_(env->get_next_module_id()) {
64
719
  module_.Reset(env->isolate(), module);
65
719
  url_.Reset(env->isolate(), url);
66
719
  env->id_to_module_map.emplace(id_, this);
67
719
}
68
69
4176
ModuleWrap::~ModuleWrap() {
70
696
  HandleScope scope(env()->isolate());
71
1392
  Local<Module> module = module_.Get(env()->isolate());
72
696
  env()->id_to_module_map.erase(id_);
73
696
  auto range = env()->hash_to_module_map.equal_range(module->GetIdentityHash());
74
696
  for (auto it = range.first; it != range.second; ++it) {
75
696
    if (it->second == this) {
76
696
      env()->hash_to_module_map.erase(it);
77
696
      break;
78
    }
79
696
  }
80
1392
}
81
82
371
ModuleWrap* ModuleWrap::GetFromModule(Environment* env,
83
                                      Local<Module> module) {
84
371
  auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash());
85
371
  for (auto it = range.first; it != range.second; ++it) {
86
742
    if (it->second->module_ == module) {
87
371
      return it->second;
88
    }
89
  }
90
  return nullptr;
91
}
92
93
39
ModuleWrap* ModuleWrap::GetFromID(Environment* env, uint32_t id) {
94
39
  auto module_wrap_it = env->id_to_module_map.find(id);
95
39
  if (module_wrap_it == env->id_to_module_map.end()) {
96
    return nullptr;
97
  }
98
39
  return module_wrap_it->second;
99
}
100
101
725
void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
102
725
  Environment* env = Environment::GetCurrent(args);
103
725
  Isolate* isolate = env->isolate();
104
105
725
  CHECK(args.IsConstructCall());
106
725
  Local<Object> that = args.This();
107
108
725
  const int argc = args.Length();
109
725
  CHECK_GE(argc, 2);
110
111
2175
  CHECK(args[0]->IsString());
112
1450
  Local<String> source_text = args[0].As<String>();
113
114
2175
  CHECK(args[1]->IsString());
115
1450
  Local<String> url = args[1].As<String>();
116
117
  Local<Context> context;
118
  Local<Integer> line_offset;
119
  Local<Integer> column_offset;
120
121
725
  if (argc == 5) {
122
    // new ModuleWrap(source, url, context?, lineOffset, columnOffset)
123
162
    if (args[2]->IsUndefined()) {
124
47
      context = that->CreationContext();
125
    } else {
126
14
      CHECK(args[2]->IsObject());
127
      ContextifyContext* sandbox =
128
          ContextifyContext::ContextFromContextifiedSandbox(
129
14
              env, args[2].As<Object>());
130
7
      CHECK_NOT_NULL(sandbox);
131
7
      context = sandbox->context();
132
    }
133
134
108
    CHECK(args[3]->IsNumber());
135
108
    line_offset = args[3].As<Integer>();
136
137
108
    CHECK(args[4]->IsNumber());
138
108
    column_offset = args[4].As<Integer>();
139
  } else {
140
    // new ModuleWrap(source, url)
141
671
    context = that->CreationContext();
142
671
    line_offset = Integer::New(isolate, 0);
143
671
    column_offset = Integer::New(isolate, 0);
144
  }
145
146
725
  ShouldNotAbortOnUncaughtScope no_abort_scope(env);
147
1444
  TryCatchScope try_catch(env);
148
  Local<Module> module;
149
150
  Local<PrimitiveArray> host_defined_options =
151
725
      PrimitiveArray::New(isolate, HostDefinedOptions::kLength);
152
  host_defined_options->Set(isolate, HostDefinedOptions::kType,
153
1450
                            Number::New(isolate, ScriptType::kModule));
154
155
  // compile
156
  {
157
    ScriptOrigin origin(url,
158
                        line_offset,                          // line offset
159
                        column_offset,                        // column offset
160
                        True(isolate),                        // is cross origin
161
                        Local<Integer>(),                     // script id
162
                        Local<Value>(),                       // source map URL
163
                        False(isolate),                       // is opaque (?)
164
                        False(isolate),                       // is WASM
165
                        True(isolate),                        // is ES Module
166
725
                        host_defined_options);
167
    Context::Scope context_scope(context);
168
719
    ScriptCompiler::Source source(source_text, origin);
169
1450
    if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) {
170

6
      if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
171
12
        CHECK(!try_catch.Message().IsEmpty());
172
12
        CHECK(!try_catch.Exception().IsEmpty());
173
        AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
174
6
                            ErrorHandlingMode::MODULE_ERROR);
175
6
        try_catch.ReThrow();
176
      }
177
6
      return;
178
719
    }
179
  }
180
181
2876
  if (!that->Set(context, env->url_string(), url).FromMaybe(false)) {
182
    return;
183
  }
184
185
719
  ModuleWrap* obj = new ModuleWrap(env, that, module, url);
186
719
  obj->context_.Reset(isolate, context);
187
188
719
  env->hash_to_module_map.emplace(module->GetIdentityHash(), obj);
189
190
  host_defined_options->Set(isolate, HostDefinedOptions::kID,
191
1438
                            Number::New(isolate, obj->id()));
192
193
719
  that->SetIntegrityLevel(context, IntegrityLevel::kFrozen);
194
2157
  args.GetReturnValue().Set(that);
195
}
196
197
410
void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
198
410
  Environment* env = Environment::GetCurrent(args);
199
410
  Isolate* isolate = args.GetIsolate();
200
201
410
  CHECK_EQ(args.Length(), 1);
202
820
  CHECK(args[0]->IsFunction());
203
204
410
  Local<Object> that = args.This();
205
206
  ModuleWrap* obj;
207
412
  ASSIGN_OR_RETURN_UNWRAP(&obj, that);
208
209
410
  if (obj->linked_)
210
2
    return;
211
408
  obj->linked_ = true;
212
213
816
  Local<Function> resolver_arg = args[0].As<Function>();
214
215
816
  Local<Context> mod_context = obj->context_.Get(isolate);
216
816
  Local<Module> module = obj->module_.Get(isolate);
217
218
  Local<Array> promises = Array::New(isolate,
219
408
                                     module->GetModuleRequestsLength());
220
221
  // call the dependency resolve callbacks
222
1224
  for (int i = 0; i < module->GetModuleRequestsLength(); i++) {
223
204
    Local<String> specifier = module->GetModuleRequest(i);
224
204
    Utf8Value specifier_utf8(env->isolate(), specifier);
225
408
    std::string specifier_std(*specifier_utf8, specifier_utf8.length());
226
227
    Local<Value> argv[] = {
228
      specifier
229
408
    };
230
231
    MaybeLocal<Value> maybe_resolve_return_value =
232
204
        resolver_arg->Call(mod_context, that, 1, argv);
233
204
    if (maybe_resolve_return_value.IsEmpty()) {
234
      return;
235
    }
236
    Local<Value> resolve_return_value =
237
204
        maybe_resolve_return_value.ToLocalChecked();
238
204
    if (!resolve_return_value->IsPromise()) {
239
      env->ThrowError("linking error, expected resolver to return a promise");
240
    }
241
204
    Local<Promise> resolve_promise = resolve_return_value.As<Promise>();
242
204
    obj->resolve_cache_[specifier_std].Reset(env->isolate(), resolve_promise);
243
244
612
    promises->Set(mod_context, i, resolve_promise).Check();
245
204
  }
246
247
816
  args.GetReturnValue().Set(promises);
248
}
249
250
141
void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
251
141
  Environment* env = Environment::GetCurrent(args);
252
141
  Isolate* isolate = args.GetIsolate();
253
  ModuleWrap* obj;
254
144
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
255
282
  Local<Context> context = obj->context_.Get(isolate);
256
282
  Local<Module> module = obj->module_.Get(isolate);
257
141
  TryCatchScope try_catch(env);
258
141
  USE(module->InstantiateModule(context, ResolveCallback));
259
260
  // clear resolve cache on instantiate
261
141
  obj->resolve_cache_.clear();
262
263

141
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
264
6
    CHECK(!try_catch.Message().IsEmpty());
265
6
    CHECK(!try_catch.Exception().IsEmpty());
266
    AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
267
3
                        ErrorHandlingMode::MODULE_ERROR);
268
3
    try_catch.ReThrow();
269
3
    return;
270
138
  }
271
}
272
273
143
void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
274
143
  Environment* env = Environment::GetCurrent(args);
275
143
  Isolate* isolate = env->isolate();
276
  ModuleWrap* obj;
277
155
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
278
286
  Local<Context> context = obj->context_.Get(isolate);
279
286
  Local<Module> module = obj->module_.Get(isolate);
280
281
  // module.evaluate(timeout, breakOnSigint)
282
143
  CHECK_EQ(args.Length(), 2);
283
284
286
  CHECK(args[0]->IsNumber());
285
572
  int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
286
287
286
  CHECK(args[1]->IsBoolean());
288
286
  bool break_on_sigint = args[1]->IsTrue();
289
290
143
  ShouldNotAbortOnUncaughtScope no_abort_scope(env);
291
273
  TryCatchScope try_catch(env);
292
293
143
  bool timed_out = false;
294
143
  bool received_signal = false;
295
  MaybeLocal<Value> result;
296

143
  if (break_on_sigint && timeout != -1) {
297
    Watchdog wd(isolate, timeout, &timed_out);
298
    SigintWatchdog swd(isolate, &received_signal);
299
    result = module->Evaluate(context);
300
143
  } else if (break_on_sigint) {
301
    SigintWatchdog swd(isolate, &received_signal);
302
    result = module->Evaluate(context);
303
143
  } else if (timeout != -1) {
304
1
    Watchdog wd(isolate, timeout, &timed_out);
305
1
    result = module->Evaluate(context);
306
  } else {
307
142
    result = module->Evaluate(context);
308
  }
309
310
  // Convert the termination exception into a regular exception.
311

142
  if (timed_out || received_signal) {
312

1
    if (!env->is_main_thread() && env->is_stopping())
313
      return;
314
1
    env->isolate()->CancelTerminateExecution();
315
    // It is possible that execution was terminated by another timeout in
316
    // which this timeout is nested, so check whether one of the watchdogs
317
    // from this invocation is responsible for termination.
318
1
    if (timed_out) {
319
1
      THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
320
    } else if (received_signal) {
321
      THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
322
    }
323
  }
324
325
142
  if (try_catch.HasCaught()) {
326
12
    if (!try_catch.HasTerminated())
327
11
      try_catch.ReThrow();
328
12
    return;
329
  }
330
331
390
  args.GetReturnValue().Set(result.ToLocalChecked());
332
}
333
334
121
void ModuleWrap::GetNamespace(const FunctionCallbackInfo<Value>& args) {
335
121
  Environment* env = Environment::GetCurrent(args);
336
121
  Isolate* isolate = args.GetIsolate();
337
  ModuleWrap* obj;
338
121
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
339
340
242
  Local<Module> module = obj->module_.Get(isolate);
341
342
121
  switch (module->GetStatus()) {
343
    default:
344
      return env->ThrowError(
345
          "cannot get namespace, Module has not been instantiated");
346
    case v8::Module::Status::kInstantiated:
347
    case v8::Module::Status::kEvaluating:
348
    case v8::Module::Status::kEvaluated:
349
121
      break;
350
  }
351
352
121
  Local<Value> result = module->GetModuleNamespace();
353
242
  args.GetReturnValue().Set(result);
354
}
355
356
96
void ModuleWrap::GetStatus(const FunctionCallbackInfo<Value>& args) {
357
96
  Isolate* isolate = args.GetIsolate();
358
  ModuleWrap* obj;
359
192
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
360
361
192
  Local<Module> module = obj->module_.Get(isolate);
362
363
288
  args.GetReturnValue().Set(module->GetStatus());
364
}
365
366
2
void ModuleWrap::GetStaticDependencySpecifiers(
367
    const FunctionCallbackInfo<Value>& args) {
368
2
  Environment* env = Environment::GetCurrent(args);
369
  ModuleWrap* obj;
370
4
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
371
372
4
  Local<Module> module = obj->module_.Get(env->isolate());
373
374
2
  int count = module->GetModuleRequestsLength();
375
376
2
  Local<Array> specifiers = Array::New(env->isolate(), count);
377
378
3
  for (int i = 0; i < count; i++)
379
4
    specifiers->Set(env->context(), i, module->GetModuleRequest(i)).Check();
380
381
4
  args.GetReturnValue().Set(specifiers);
382
}
383
384
1
void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
385
1
  Isolate* isolate = args.GetIsolate();
386
  ModuleWrap* obj;
387
2
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
388
389
2
  Local<Module> module = obj->module_.Get(isolate);
390
3
  args.GetReturnValue().Set(module->GetException());
391
}
392
393
195
MaybeLocal<Module> ModuleWrap::ResolveCallback(Local<Context> context,
394
                                               Local<String> specifier,
395
                                               Local<Module> referrer) {
396
195
  Environment* env = Environment::GetCurrent(context);
397
195
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
398
195
  Isolate* isolate = env->isolate();
399
400
195
  ModuleWrap* dependent = GetFromModule(env, referrer);
401
195
  if (dependent == nullptr) {
402
    env->ThrowError("linking error, null dep");
403
    return MaybeLocal<Module>();
404
  }
405
406
195
  Utf8Value specifier_utf8(isolate, specifier);
407
390
  std::string specifier_std(*specifier_utf8, specifier_utf8.length());
408
409
195
  if (dependent->resolve_cache_.count(specifier_std) != 1) {
410
    env->ThrowError("linking error, not in local cache");
411
    return MaybeLocal<Module>();
412
  }
413
414
  Local<Promise> resolve_promise =
415
390
      dependent->resolve_cache_[specifier_std].Get(isolate);
416
417
195
  if (resolve_promise->State() != Promise::kFulfilled) {
418
    env->ThrowError("linking error, dependency promises must be resolved on "
419
                    "instantiate");
420
    return MaybeLocal<Module>();
421
  }
422
423
390
  Local<Object> module_object = resolve_promise->Result().As<Object>();
424

390
  if (module_object.IsEmpty() || !module_object->IsObject()) {
425
    env->ThrowError("linking error, expected a valid module object from "
426
                    "resolver");
427
    return MaybeLocal<Module>();
428
  }
429
430
  ModuleWrap* module;
431
195
  ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Module>());
432
585
  return module->module_.Get(isolate);
433
}
434
435
namespace {
436
437
// Tests whether a path starts with /, ./ or ../
438
// In WhatWG terminology, the alternative case is called a "bare" specifier
439
// (e.g. in `import "jquery"`).
440
236
inline bool ShouldBeTreatedAsRelativeOrAbsolutePath(
441
    const std::string& specifier) {
442
236
  size_t len = specifier.length();
443
236
  if (len == 0)
444
    return false;
445
236
  if (specifier[0] == '/') {
446
    return true;
447
236
  } else if (specifier[0] == '.') {
448

108
    if (len == 1 || specifier[1] == '/')
449
32
      return true;
450
76
    if (specifier[1] == '.') {
451

76
      if (len == 2 || specifier[2] == '/')
452
76
        return true;
453
    }
454
  }
455
128
  return false;
456
}
457
458
19
std::string ReadFile(uv_file file) {
459
19
  std::string contents;
460
  uv_fs_t req;
461
  char buffer_memory[4096];
462
19
  uv_buf_t buf = uv_buf_init(buffer_memory, sizeof(buffer_memory));
463
464
  do {
465
    const int r = uv_fs_read(nullptr,
466
                             &req,
467
                             file,
468
                             &buf,
469
                             1,
470
38
                             contents.length(),  // offset
471
38
                             nullptr);
472
38
    uv_fs_req_cleanup(&req);
473
474
38
    if (r <= 0)
475
19
      break;
476
19
    contents.append(buf.base, r);
477
  } while (true);
478
19
  return contents;
479
}
480
481
enum DescriptorType {
482
  FILE,
483
  DIRECTORY,
484
  NONE
485
};
486
487
// When DescriptorType cache is added, this can also return
488
// Nothing for the "null" cache entries.
489
1179
inline Maybe<uv_file> OpenDescriptor(const std::string& path) {
490
  uv_fs_t fs_req;
491
#ifdef _WIN32
492
  std::string pth = "\\\\.\\" + path;
493
  uv_file fd = uv_fs_open(nullptr, &fs_req, pth.c_str(), O_RDONLY, 0, nullptr);
494
#else
495
1179
  uv_file fd = uv_fs_open(nullptr, &fs_req, path.c_str(), O_RDONLY, 0, nullptr);
496
#endif
497
1179
  uv_fs_req_cleanup(&fs_req);
498
1179
  if (fd < 0) return Nothing<uv_file>();
499
252
  return Just(fd);
500
}
501
502
252
inline void CloseDescriptor(uv_file fd) {
503
  uv_fs_t fs_req;
504
252
  CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, fd, nullptr));
505
252
  uv_fs_req_cleanup(&fs_req);
506
252
}
507
508
252
inline DescriptorType CheckDescriptorAtFile(uv_file fd) {
509
  uv_fs_t fs_req;
510
252
  int rc = uv_fs_fstat(nullptr, &fs_req, fd, nullptr);
511
252
  if (rc == 0) {
512
252
    uint64_t is_directory = fs_req.statbuf.st_mode & S_IFDIR;
513
252
    uv_fs_req_cleanup(&fs_req);
514
252
    return is_directory ? DIRECTORY : FILE;
515
  }
516
  uv_fs_req_cleanup(&fs_req);
517
  return NONE;
518
}
519
520
// TODO(@guybedford): Add a DescriptorType cache layer here.
521
// Should be directory based -> if path/to/dir doesn't exist
522
// then the cache should early-fail any path/to/dir/file check.
523
316
DescriptorType CheckDescriptorAtPath(const std::string& path) {
524
316
  Maybe<uv_file> fd = OpenDescriptor(path);
525
316
  if (fd.IsNothing()) return NONE;
526
233
  DescriptorType type = CheckDescriptorAtFile(fd.FromJust());
527
233
  CloseDescriptor(fd.FromJust());
528
233
  return type;
529
}
530
531
863
Maybe<std::string> ReadIfFile(const std::string& path) {
532
863
  Maybe<uv_file> fd = OpenDescriptor(path);
533
863
  if (fd.IsNothing()) return Nothing<std::string>();
534
19
  DescriptorType type = CheckDescriptorAtFile(fd.FromJust());
535
19
  if (type != FILE) return Nothing<std::string>();
536
19
  std::string source = ReadFile(fd.FromJust());
537
19
  CloseDescriptor(fd.FromJust());
538
19
  return Just(source);
539
}
540
541
using Exists = PackageConfig::Exists;
542
using IsValid = PackageConfig::IsValid;
543
using HasMain = PackageConfig::HasMain;
544
using PackageType = PackageConfig::PackageType;
545
546
1715
Maybe<const PackageConfig*> GetPackageConfig(Environment* env,
547
                                             const std::string& path,
548
                                             const URL& base) {
549
1715
  auto existing = env->package_json_cache.find(path);
550
1715
  if (existing != env->package_json_cache.end()) {
551
852
    const PackageConfig* pcfg = &existing->second;
552
852
    if (pcfg->is_valid == IsValid::No) {
553
      std::string msg = "Invalid JSON in " + path +
554
        " imported from " + base.ToFilePath();
555
      node::THROW_ERR_INVALID_PACKAGE_CONFIG(env, msg.c_str());
556
      return Nothing<const PackageConfig*>();
557
    }
558
852
    return Just(pcfg);
559
  }
560
561
863
  Maybe<std::string> source = ReadIfFile(path);
562
563
863
  if (source.IsNothing()) {
564
    auto entry = env->package_json_cache.emplace(path,
565
        PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "",
566
1688
                        PackageType::None, Global<Value>() });
567
844
    return Just(&entry.first->second);
568
  }
569
570
19
  std::string pkg_src = source.FromJust();
571
572
19
  Isolate* isolate = env->isolate();
573
38
  v8::HandleScope handle_scope(isolate);
574
575
  Local<Object> pkg_json;
576
  {
577
    Local<Value> src;
578
    Local<Value> pkg_json_v;
579
19
    Local<Context> context = env->context();
580
581

114
    if (!ToV8Value(context, pkg_src).ToLocal(&src) ||
582

152
        !v8::JSON::Parse(context, src.As<String>()).ToLocal(&pkg_json_v) ||
583
57
        !pkg_json_v->ToObject(context).ToLocal(&pkg_json)) {
584
      env->package_json_cache.emplace(path,
585
          PackageConfig { Exists::Yes, IsValid::No, HasMain::No, "",
586
                          PackageType::None, Global<Value>() });
587
      std::string msg = "Invalid JSON in " + path +
588
          " imported from " + base.ToFilePath();
589
      node::THROW_ERR_INVALID_PACKAGE_CONFIG(env, msg.c_str());
590
      return Nothing<const PackageConfig*>();
591
    }
592
  }
593
594
  Local<Value> pkg_main;
595
19
  HasMain has_main = HasMain::No;
596
38
  std::string main_std;
597
76
  if (pkg_json->Get(env->context(), env->main_string()).ToLocal(&pkg_main)) {
598
38
    if (pkg_main->IsString()) {
599
14
      has_main = HasMain::Yes;
600
    }
601
19
    Utf8Value main_utf8(isolate, pkg_main);
602
19
    main_std.assign(std::string(*main_utf8, main_utf8.length()));
603
  }
604
605
19
  PackageType pkg_type = PackageType::None;
606
  Local<Value> type_v;
607
76
  if (pkg_json->Get(env->context(), env->type_string()).ToLocal(&type_v)) {
608
38
    if (type_v->StrictEquals(env->module_string())) {
609
6
      pkg_type = PackageType::Module;
610
26
    } else if (type_v->StrictEquals(env->commonjs_string())) {
611
4
      pkg_type = PackageType::CommonJS;
612
    }
613
    // ignore unknown types for forwards compatibility
614
  }
615
616
  Local<Value> exports_v;
617

114
  if (env->options()->experimental_exports &&
618
      pkg_json->Get(env->context(),
619


152
      env->exports_string()).ToLocal(&exports_v) &&
620
38
      !exports_v->IsNullOrUndefined()) {
621
    Global<Value> exports;
622
2
    exports.Reset(env->isolate(), exports_v);
623
624
    auto entry = env->package_json_cache.emplace(path,
625
        PackageConfig { Exists::Yes, IsValid::Yes, has_main, main_std,
626
4
                        pkg_type, std::move(exports) });
627
2
    return Just(&entry.first->second);
628
  }
629
630
  auto entry = env->package_json_cache.emplace(path,
631
      PackageConfig { Exists::Yes, IsValid::Yes, has_main, main_std,
632
34
                      pkg_type, Global<Value>() });
633
880
  return Just(&entry.first->second);
634
}
635
636
199
Maybe<const PackageConfig*> GetPackageScopeConfig(Environment* env,
637
                                                  const URL& resolved,
638
                                                  const URL& base) {
639
199
  URL pjson_url("./package.json", &resolved);
640
  while (true) {
641
1688
    std::string pjson_url_path = pjson_url.path();
642

6254
    if (pjson_url_path.length() > 25 &&
643
5258
        pjson_url_path.substr(pjson_url_path.length() - 25, 25) ==
644
        "node_modules/package.json") {
645
2
      break;
646
    }
647
    Maybe<const PackageConfig*> pkg_cfg =
648
1686
        GetPackageConfig(env, pjson_url.ToFilePath(), base);
649
1686
    if (pkg_cfg.IsNothing()) return pkg_cfg;
650
1686
    if (pkg_cfg.FromJust()->exists == Exists::Yes) return pkg_cfg;
651
652
3144
    URL last_pjson_url = pjson_url;
653
1655
    pjson_url = URL("../package.json", pjson_url);
654
655
    // Terminates at root where ../package.json equals ../../package.json
656
    // (can't just check "/package.json" for Windows support).
657

1655
    if (pjson_url.path() == last_pjson_url.path()) break;
658
1489
  }
659
  auto entry = env->package_json_cache.emplace(pjson_url.ToFilePath(),
660
  PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "",
661
336
                  PackageType::None, Global<Value>() });
662
168
  const PackageConfig* pcfg = &entry.first->second;
663
168
  return Just(pcfg);
664
}
665
666
/*
667
 * Legacy CommonJS main resolution:
668
 * 1. let M = pkg_url + (json main field)
669
 * 2. TRY(M, M.js, M.json, M.node)
670
 * 3. TRY(M/index.js, M/index.json, M/index.node)
671
 * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
672
 * 5. NOT_FOUND
673
 */
674
56
inline bool FileExists(const URL& url) {
675
56
  return CheckDescriptorAtPath(url.ToFilePath()) == FILE;
676
}
677
Maybe<URL> LegacyMainResolve(const URL& pjson_url,
678
                             const PackageConfig& pcfg) {
679
  URL guess;
680
  if (pcfg.has_main == HasMain::Yes) {
681
    // Note: fs check redundances will be handled by Descriptor cache here.
682
    if (FileExists(guess = URL("./" + pcfg.main, pjson_url))) {
683
      return Just(guess);
684
    }
685
    if (FileExists(guess = URL("./" + pcfg.main + ".js", pjson_url))) {
686
      return Just(guess);
687
    }
688
    if (FileExists(guess = URL("./" + pcfg.main + ".json", pjson_url))) {
689
      return Just(guess);
690
    }
691
    if (FileExists(guess = URL("./" + pcfg.main + ".node", pjson_url))) {
692
      return Just(guess);
693
    }
694
    if (FileExists(guess = URL("./" + pcfg.main + "/index.js", pjson_url))) {
695
      return Just(guess);
696
    }
697
    // Such stat.
698
    if (FileExists(guess = URL("./" + pcfg.main + "/index.json", pjson_url))) {
699
      return Just(guess);
700
    }
701
    if (FileExists(guess = URL("./" + pcfg.main + "/index.node", pjson_url))) {
702
      return Just(guess);
703
    }
704
    // Fallthrough.
705
  }
706
  if (FileExists(guess = URL("./index.js", pjson_url))) {
707
    return Just(guess);
708
  }
709
  // So fs.
710
  if (FileExists(guess = URL("./index.json", pjson_url))) {
711
    return Just(guess);
712
  }
713
  if (FileExists(guess = URL("./index.node", pjson_url))) {
714
    return Just(guess);
715
  }
716
  // Not found.
717
  return Nothing<URL>();
718
}
719
720
enum ResolveExtensionsOptions {
721
  TRY_EXACT_NAME,
722
  ONLY_VIA_EXTENSIONS
723
};
724
725
template <ResolveExtensionsOptions options>
726
22
Maybe<URL> ResolveExtensions(const URL& search) {
727
  if (options == TRY_EXACT_NAME) {
728
17
    if (FileExists(search)) {
729
9
      return Just(search);
730
    }
731
  }
732
733

45
  for (const char* extension : EXTENSIONS) {
734
39
    URL guess(search.path() + extension, &search);
735

39
    if (FileExists(guess)) {
736

7
      return Just(guess);
737
    }
738
  }
739
740
6
  return Nothing<URL>();
741
}
742
743
5
inline Maybe<URL> ResolveIndex(const URL& search) {
744
5
  return ResolveExtensions<ONLY_VIA_EXTENSIONS>(URL("index", search));
745
}
746
747
213
Maybe<URL> FinalizeResolution(Environment* env,
748
                              const URL& resolved,
749
                              const URL& base) {
750
213
  if (env->options()->es_module_specifier_resolution == "node") {
751
17
    Maybe<URL> file = ResolveExtensions<TRY_EXACT_NAME>(resolved);
752
17
    if (!file.IsNothing()) {
753
12
      return file;
754
    }
755
5
    if (resolved.path().back() != '/') {
756
4
      file = ResolveIndex(URL(resolved.path() + "/", &base));
757
    } else {
758
1
      file = ResolveIndex(resolved);
759
    }
760
5
    if (!file.IsNothing()) {
761
4
      return file;
762
    }
763
2
    std::string msg = "Cannot find module " + resolved.path() +
764
4
        " imported from " + base.ToFilePath();
765
1
    node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
766
18
    return Nothing<URL>();
767
  }
768
769
196
  const std::string& path = resolved.ToFilePath();
770
196
  if (CheckDescriptorAtPath(path) != FILE) {
771
30
    std::string msg = "Cannot find module " +
772
45
        (path.length() != 0 ? path : resolved.path()) +
773
45
        " imported from " + base.ToFilePath();
774
15
    node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
775
15
    return Nothing<URL>();
776
  }
777
778
181
  return Just(resolved);
779
}
780
781
2
void ThrowExportsNotFound(Environment* env,
782
                          const std::string& subpath,
783
                          const URL& pjson_url,
784
                          const URL& base) {
785
4
  const std::string msg = "Package exports for " +
786
4
      pjson_url.ToFilePath() + " do not define a '" + subpath +
787
6
      "' subpath, imported from " + base.ToFilePath();
788
2
  node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
789
2
}
790
791
18
void ThrowExportsInvalid(Environment* env,
792
                         const std::string& subpath,
793
                         const std::string& target,
794
                         const URL& pjson_url,
795
                         const URL& base) {
796
36
  const std::string msg = "Cannot resolve package exports target '" + target +
797
72
      "' matched for '" + subpath + "' in " + pjson_url.ToFilePath() +
798
54
      ", imported from " + base.ToFilePath();
799
18
  node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
800
18
}
801
802
8
void ThrowExportsInvalid(Environment* env,
803
                         const std::string& subpath,
804
                         Local<Value> target,
805
                         const URL& pjson_url,
806
                         const URL& base) {
807
  Local<String> target_string;
808
24
  if (target->ToString(env->context()).ToLocal(&target_string)) {
809
8
    Utf8Value target_utf8(env->isolate(), target_string);
810
16
    std::string target_str(*target_utf8, target_utf8.length());
811
8
    if (target->IsArray()) {
812
1
      target_str = '[' + target_str + ']';
813
    }
814
16
    ThrowExportsInvalid(env, subpath, target_str, pjson_url, base);
815
  }
816
8
}
817
818
19
Maybe<URL> ResolveExportsTarget(Environment* env,
819
                                const std::string& target,
820
                                const std::string& subpath,
821
                                const std::string& match,
822
                                const URL& pjson_url,
823
                                const URL& base,
824
                                bool throw_invalid = true) {
825
19
  if (target.substr(0, 2) != "./") {
826
8
    if (throw_invalid) {
827
5
      ThrowExportsInvalid(env, match, target, pjson_url, base);
828
    }
829
8
    return Nothing<URL>();
830
  }
831

11
  if (subpath.length() > 0 && target.back() != '/') {
832
1
    if (throw_invalid) {
833
      ThrowExportsInvalid(env, match, target, pjson_url, base);
834
    }
835
1
    return Nothing<URL>();
836
  }
837
10
  URL resolved(target, pjson_url);
838
20
  std::string resolved_path = resolved.path();
839
20
  std::string pkg_path = URL(".", pjson_url).path();
840

20
  if (resolved_path.find(pkg_path) != 0 ||
841
10
      resolved_path.find("/node_modules/", pkg_path.length() - 1) !=
842
      std::string::npos) {
843
1
    if (throw_invalid) {
844
1
      ThrowExportsInvalid(env, match, target, pjson_url, base);
845
    }
846
1
    return Nothing<URL>();
847
  }
848
9
  if (subpath.length() == 0) return Just(resolved);
849
10
  URL subpath_resolved(subpath, resolved);
850
10
  std::string subpath_resolved_path = subpath_resolved.path();
851

9
  if (subpath_resolved_path.find(resolved_path) != 0 ||
852
4
      subpath_resolved_path.find("/node_modules/", pkg_path.length() - 1)
853
      != std::string::npos) {
854
1
    if (throw_invalid) {
855
1
      ThrowExportsInvalid(env, match, target + subpath, pjson_url, base);
856
    }
857
1
    return Nothing<URL>();
858
  }
859
14
  return Just(subpath_resolved);
860
}
861
862
6
Maybe<URL> PackageMainResolve(Environment* env,
863
                              const URL& pjson_url,
864
                              const PackageConfig& pcfg,
865
                              const URL& base) {
866
6
  if (pcfg.exists == Exists::Yes) {
867
6
    Isolate* isolate = env->isolate();
868
6
    Local<Context> context = env->context();
869
12
    if (!pcfg.exports.IsEmpty()) {
870
2
      Local<Value> exports = pcfg.exports.Get(isolate);
871


3
      if (exports->IsString() || exports->IsObject() || exports->IsArray()) {
872
        Local<Value> target;
873
1
        if (!exports->IsObject()) {
874
          target = exports;
875
        } else {
876
1
          Local<Object> exports_obj = exports.As<Object>();
877
          Local<String> dot_string = String::NewFromUtf8(env->isolate(), ".",
878
2
              v8::NewStringType::kNormal).ToLocalChecked();
879
          target =
880
3
              exports_obj->Get(env->context(), dot_string).ToLocalChecked();
881
        }
882
2
        if (target->IsString()) {
883
1
          Utf8Value target_utf8(isolate, target.As<v8::String>());
884
2
          std::string target(*target_utf8, target_utf8.length());
885
          Maybe<URL> resolved = ResolveExportsTarget(env, target, "", ".",
886
2
              pjson_url, base);
887
1
          if (resolved.IsNothing()) {
888
            ThrowExportsInvalid(env, ".", target, pjson_url, base);
889
            return Nothing<URL>();
890
          }
891
2
          return FinalizeResolution(env, resolved.FromJust(), base);
892
        } else if (target->IsArray()) {
893
          Local<Array> target_arr = target.As<Array>();
894
          const uint32_t length = target_arr->Length();
895
          if (length == 0) {
896
            ThrowExportsInvalid(env, ".", target, pjson_url, base);
897
            return Nothing<URL>();
898
          }
899
          for (uint32_t i = 0; i < length; i++) {
900
            auto target_item = target_arr->Get(context, i).ToLocalChecked();
901
            if (target_item->IsString()) {
902
              Utf8Value target_utf8(isolate, target_item.As<v8::String>());
903
              std::string target_str(*target_utf8, target_utf8.length());
904
              Maybe<URL> resolved = ResolveExportsTarget(env, target_str, "",
905
                  ".", pjson_url, base, false);
906
              if (resolved.IsNothing()) continue;
907
              return FinalizeResolution(env, resolved.FromJust(), base);
908
            }
909
          }
910
          auto invalid = target_arr->Get(context, length - 1).ToLocalChecked();
911
          if (!invalid->IsString()) {
912
            ThrowExportsInvalid(env, ".", invalid, pjson_url, base);
913
            return Nothing<URL>();
914
          }
915
          Utf8Value invalid_utf8(isolate, invalid.As<v8::String>());
916
          std::string invalid_str(*invalid_utf8, invalid_utf8.length());
917
          Maybe<URL> resolved = ResolveExportsTarget(env, invalid_str, "",
918
                                                    ".", pjson_url, base);
919
          CHECK(resolved.IsNothing());
920
          return Nothing<URL>();
921
        } else {
922
          ThrowExportsInvalid(env, ".", target, pjson_url, base);
923
          return Nothing<URL>();
924
        }
925
      }
926
    }
927
5
    if (pcfg.has_main == HasMain::Yes) {
928
5
      URL resolved(pcfg.main, pjson_url);
929
8
      const std::string& path = resolved.ToFilePath();
930
5
      if (CheckDescriptorAtPath(path) == FILE) {
931
2
        return Just(resolved);
932
3
      }
933
    }
934
3
    if (env->options()->es_module_specifier_resolution == "node") {
935
3
      if (pcfg.has_main == HasMain::Yes) {
936
3
        return FinalizeResolution(env, URL(pcfg.main, pjson_url), base);
937
      } else {
938
        return FinalizeResolution(env, URL("index", pjson_url), base);
939
      }
940
    }
941
    if (pcfg.type != PackageType::Module) {
942
      Maybe<URL> resolved = LegacyMainResolve(pjson_url, pcfg);
943
      if (!resolved.IsNothing()) {
944
        return resolved;
945
      }
946
    }
947
  }
948
  std::string msg = "Cannot find main entry point for " +
949
      URL(".", pjson_url).ToFilePath() + " imported from " +
950
      base.ToFilePath();
951
  node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
952
  return Nothing<URL>();
953
}
954
955
21
Maybe<URL> PackageExportsResolve(Environment* env,
956
                                 const URL& pjson_url,
957
                                 const std::string& pkg_subpath,
958
                                 const PackageConfig& pcfg,
959
                                 const URL& base) {
960
21
  CHECK(env->options()->experimental_exports);
961
21
  Isolate* isolate = env->isolate();
962
21
  Local<Context> context = env->context();
963
42
  Local<Value> exports = pcfg.exports.Get(isolate);
964
21
  if (!exports->IsObject()) {
965
1
    ThrowExportsNotFound(env, pkg_subpath, pjson_url, base);
966
1
    return Nothing<URL>();
967
  }
968
20
  Local<Object> exports_obj = exports.As<Object>();
969
  Local<String> subpath = String::NewFromUtf8(isolate,
970
40
      pkg_subpath.c_str(), v8::NewStringType::kNormal).ToLocalChecked();
971
972
40
  if (exports_obj->HasOwnProperty(context, subpath).FromJust()) {
973
24
    Local<Value> target = exports_obj->Get(context, subpath).ToLocalChecked();
974
24
    if (target->IsString()) {
975
5
      Utf8Value target_utf8(isolate, target.As<v8::String>());
976
10
      std::string target_str(*target_utf8, target_utf8.length());
977
      Maybe<URL> resolved = ResolveExportsTarget(env, target_str, "",
978
10
          pkg_subpath, pjson_url, base);
979
5
      if (resolved.IsNothing()) {
980
3
        ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
981
3
        return Nothing<URL>();
982
      }
983
7
      return FinalizeResolution(env, resolved.FromJust(), base);
984
7
    } else if (target->IsArray()) {
985
3
      Local<Array> target_arr = target.As<Array>();
986
3
      const uint32_t length = target_arr->Length();
987
3
      if (length == 0) {
988
1
        ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
989
1
        return Nothing<URL>();
990
      }
991
9
      for (uint32_t i = 0; i < length; i++) {
992
16
        auto target_item = target_arr->Get(context, i).ToLocalChecked();
993
16
        if (target_item->IsString()) {
994
3
          Utf8Value target_utf8(isolate, target_item.As<v8::String>());
995
3
          std::string target(*target_utf8, target_utf8.length());
996
          Maybe<URL> resolved = ResolveExportsTarget(env, target, "",
997
3
              pkg_subpath, pjson_url, base, false);
998
3
          if (resolved.IsNothing()) continue;
999

1
          return FinalizeResolution(env, resolved.FromJust(), base);
1000
        }
1001
      }
1002
3
      auto invalid = target_arr->Get(context, length - 1).ToLocalChecked();
1003
2
      if (!invalid->IsString()) {
1004
        ThrowExportsInvalid(env, pkg_subpath, invalid, pjson_url, base);
1005
        return Nothing<URL>();
1006
      }
1007
1
      Utf8Value invalid_utf8(isolate, invalid.As<v8::String>());
1008
2
      std::string invalid_str(*invalid_utf8, invalid_utf8.length());
1009
      Maybe<URL> resolved = ResolveExportsTarget(env, invalid_str, "",
1010
2
                                                 pkg_subpath, pjson_url, base);
1011
1
      CHECK(resolved.IsNothing());
1012
2
      return Nothing<URL>();
1013
    } else {
1014
4
      ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
1015
4
      return Nothing<URL>();
1016
    }
1017
  }
1018
1019
  Local<String> best_match;
1020
8
  std::string best_match_str = "";
1021
  Local<Array> keys =
1022
16
      exports_obj->GetOwnPropertyNames(context).ToLocalChecked();
1023
288
  for (uint32_t i = 0; i < keys->Length(); ++i) {
1024
408
    Local<String> key = keys->Get(context, i).ToLocalChecked().As<String>();
1025
136
    Utf8Value key_utf8(isolate, key);
1026
168
    std::string key_str(*key_utf8, key_utf8.length());
1027
136
    if (key_str.back() != '/') continue;
1028


39
    if (pkg_subpath.substr(0, key_str.length()) == key_str &&
1029
7
        key_str.length() > best_match_str.length()) {
1030
7
      best_match = key;
1031
7
      best_match_str = key_str;
1032
    }
1033
32
  }
1034
1035
8
  if (best_match_str.length() > 0) {
1036
14
    auto target = exports_obj->Get(context, best_match).ToLocalChecked();
1037
7
    std::string subpath = pkg_subpath.substr(best_match_str.length());
1038
14
    if (target->IsString()) {
1039
6
      Utf8Value target_utf8(isolate, target.As<v8::String>());
1040
12
      std::string target(*target_utf8, target_utf8.length());
1041
      Maybe<URL> resolved = ResolveExportsTarget(env, target, subpath,
1042
12
          pkg_subpath, pjson_url, base);
1043
6
      if (resolved.IsNothing()) {
1044
3
        ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
1045
3
        return Nothing<URL>();
1046
      }
1047
9
      return FinalizeResolution(env, URL(subpath, resolved.FromJust()), base);
1048
1
    } else if (target->IsArray()) {
1049
1
      Local<Array> target_arr = target.As<Array>();
1050
1
      const uint32_t length = target_arr->Length();
1051
1
      if (length == 0) {
1052
        ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
1053
        return Nothing<URL>();
1054
      }
1055
6
      for (uint32_t i = 0; i < length; i++) {
1056
12
        auto target_item = target_arr->Get(context, i).ToLocalChecked();
1057
12
        if (target_item->IsString()) {
1058
3
          Utf8Value target_utf8(isolate, target_item.As<v8::String>());
1059
3
          std::string target_str(*target_utf8, target_utf8.length());
1060
          Maybe<URL> resolved = ResolveExportsTarget(env, target_str, subpath,
1061
3
              pkg_subpath, pjson_url, base, false);
1062
3
          if (resolved.IsNothing()) continue;
1063

1
          return FinalizeResolution(env, resolved.FromJust(), base);
1064
        }
1065
      }
1066
      auto invalid = target_arr->Get(context, length - 1).ToLocalChecked();
1067
      if (!invalid->IsString()) {
1068
        ThrowExportsInvalid(env, pkg_subpath, invalid, pjson_url, base);
1069
        return Nothing<URL>();
1070
      }
1071
      Utf8Value invalid_utf8(isolate, invalid.As<v8::String>());
1072
      std::string invalid_str(*invalid_utf8, invalid_utf8.length());
1073
      Maybe<URL> resolved = ResolveExportsTarget(env, invalid_str, subpath,
1074
                                                 pkg_subpath, pjson_url, base);
1075
      CHECK(resolved.IsNothing());
1076
      return Nothing<URL>();
1077
    } else {
1078
      ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
1079
      return Nothing<URL>();
1080
7
    }
1081
  }
1082
1083
1
  ThrowExportsNotFound(env, pkg_subpath, pjson_url, base);
1084
1
  return Nothing<URL>();
1085
}
1086
1087
36
Maybe<URL> PackageResolve(Environment* env,
1088
                          const std::string& specifier,
1089
                          const URL& base) {
1090
36
  size_t sep_index = specifier.find('/');
1091
36
  bool valid_package_name = true;
1092
36
  bool scope = false;
1093
36
  if (specifier[0] == '@') {
1094
1
    scope = true;
1095

1
    if (sep_index == std::string::npos || specifier.length() == 0) {
1096
1
      valid_package_name = false;
1097
    } else {
1098
      sep_index = specifier.find('/', sep_index + 1);
1099
    }
1100
35
  } else if (specifier[0] == '.') {
1101
    valid_package_name = false;
1102
  }
1103
  std::string pkg_name = specifier.substr(0,
1104
36
      sep_index == std::string::npos ? std::string::npos : sep_index);
1105
  // Package name cannot have leading . and cannot have percent-encoding or
1106
  // separators.
1107
379
  for (size_t i = 0; i < pkg_name.length(); i++) {
1108
346
    char c = pkg_name[i];
1109

346
    if (c == '%' || c == '\\') {
1110
3
      valid_package_name = false;
1111
3
      break;
1112
    }
1113
  }
1114
36
  if (!valid_package_name) {
1115
8
    std::string msg = "Invalid package name '" + specifier +
1116
12
      "' imported from " + base.ToFilePath();
1117
4
    node::THROW_ERR_INVALID_MODULE_SPECIFIER(env, msg.c_str());
1118
4
    return Nothing<URL>();
1119
  }
1120
64
  std::string pkg_subpath;
1121

55
  if ((sep_index == std::string::npos ||
1122
23
      sep_index == specifier.length() - 1)) {
1123
9
    pkg_subpath = "";
1124
  } else {
1125
23
    pkg_subpath = "." + specifier.substr(sep_index);
1126
  }
1127
64
  URL pjson_url("./node_modules/" + pkg_name + "/package.json", &base);
1128
64
  std::string pjson_path = pjson_url.ToFilePath();
1129
64
  std::string last_path;
1130
30
  do {
1131
    DescriptorType check =
1132
59
        CheckDescriptorAtPath(pjson_path.substr(0, pjson_path.length() - 13));
1133
59
    if (check != DIRECTORY) {
1134
30
      last_path = pjson_path;
1135
60
      pjson_url = URL((scope ?
1136
60
          "../../../../node_modules/" : "../../../node_modules/") +
1137
90
          pkg_name + "/package.json", &pjson_url);
1138
30
      pjson_path = pjson_url.ToFilePath();
1139
30
      continue;
1140
    }
1141
1142
    // Package match.
1143
29
    Maybe<const PackageConfig*> pcfg = GetPackageConfig(env, pjson_path, base);
1144
    // Invalid package configuration error.
1145
58
    if (pcfg.IsNothing()) return Nothing<URL>();
1146
29
    if (!pkg_subpath.length()) {
1147
6
      return PackageMainResolve(env, pjson_url, *pcfg.FromJust(), base);
1148
    } else {
1149
46
      if (!pcfg.FromJust()->exports.IsEmpty()) {
1150
        return PackageExportsResolve(env, pjson_url, pkg_subpath,
1151
21
                                     *pcfg.FromJust(), base);
1152
      } else {
1153
2
        return FinalizeResolution(env, URL(pkg_subpath, pjson_url), base);
1154
      }
1155
    }
1156
    CHECK(false);
1157
    // Cross-platform root check.
1158
30
  } while (pjson_path.length() != last_path.length());
1159
1160
6
  std::string msg = "Cannot find package '" + pkg_name +
1161
12
      "' imported from " + base.ToFilePath();
1162
3
  node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
1163
39
  return Nothing<URL>();
1164
}
1165
1166
}  // anonymous namespace
1167
1168
236
Maybe<URL> Resolve(Environment* env,
1169
                   const std::string& specifier,
1170
                   const URL& base) {
1171
  // Order swapped from spec for minor perf gain.
1172
  // Ok since relative URLs cannot parse as URLs.
1173
236
  URL resolved;
1174
236
  if (ShouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
1175
108
    resolved = URL(specifier, base);
1176
  } else {
1177
128
    URL pure_url(specifier);
1178
128
    if (!(pure_url.flags() & URL_FLAGS_FAILED)) {
1179
92
      resolved = pure_url;
1180
    } else {
1181
36
      return PackageResolve(env, specifier, base);
1182
92
    }
1183
  }
1184
200
  return FinalizeResolution(env, resolved, base);
1185
}
1186
1187
236
void ModuleWrap::Resolve(const FunctionCallbackInfo<Value>& args) {
1188
236
  Environment* env = Environment::GetCurrent(args);
1189
1190
  // module.resolve(specifier, url)
1191
236
  CHECK_EQ(args.Length(), 2);
1192
1193
708
  CHECK(args[0]->IsString());
1194
236
  Utf8Value specifier_utf8(env->isolate(), args[0]);
1195
435
  std::string specifier_std(*specifier_utf8, specifier_utf8.length());
1196
1197
708
  CHECK(args[1]->IsString());
1198
435
  Utf8Value url_utf8(env->isolate(), args[1]);
1199
435
  URL url(*url_utf8, url_utf8.length());
1200
1201
236
  if (url.flags() & URL_FLAGS_FAILED) {
1202
    return node::THROW_ERR_INVALID_ARG_TYPE(
1203
        env, "second argument is not a URL string");
1204
  }
1205
1206
  Maybe<URL> result =
1207
      node::loader::Resolve(env,
1208
                            specifier_std,
1209
435
                            url);
1210
236
  if (result.IsNothing()) {
1211
37
    return;
1212
  }
1213
1214
199
  URL resolution = result.FromJust();
1215
199
  CHECK(!(resolution.flags() & URL_FLAGS_FAILED));
1216
1217
  Local<Value> resolution_obj;
1218
398
  if (resolution.ToObject(env).ToLocal(&resolution_obj))
1219
597
    args.GetReturnValue().Set(resolution_obj);
1220
}
1221
1222
199
void ModuleWrap::GetPackageType(const FunctionCallbackInfo<Value>& args) {
1223
199
  Environment* env = Environment::GetCurrent(args);
1224
1225
  // module.getPackageType(url)
1226
199
  CHECK_EQ(args.Length(), 1);
1227
1228
597
  CHECK(args[0]->IsString());
1229
199
  Utf8Value url_utf8(env->isolate(), args[0]);
1230
398
  URL url(*url_utf8, url_utf8.length());
1231
1232
199
  PackageType pkg_type = PackageType::None;
1233
  Maybe<const PackageConfig*> pcfg =
1234
199
      GetPackageScopeConfig(env, url, url);
1235
199
  if (!pcfg.IsNothing()) {
1236
199
    pkg_type = pcfg.FromJust()->type;
1237
  }
1238
1239
796
  args.GetReturnValue().Set(Integer::New(env->isolate(), pkg_type));
1240
199
}
1241
1242
64
static MaybeLocal<Promise> ImportModuleDynamically(
1243
    Local<Context> context,
1244
    Local<v8::ScriptOrModule> referrer,
1245
    Local<String> specifier) {
1246
64
  Isolate* iso = context->GetIsolate();
1247
64
  Environment* env = Environment::GetCurrent(context);
1248
64
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
1249
64
  v8::EscapableHandleScope handle_scope(iso);
1250
1251
  Local<Function> import_callback =
1252
64
    env->host_import_module_dynamically_callback();
1253
1254
64
  Local<PrimitiveArray> options = referrer->GetHostDefinedOptions();
1255
64
  if (options->Length() != HostDefinedOptions::kLength) {
1256
    Local<Promise::Resolver> resolver =
1257
        Promise::Resolver::New(context).ToLocalChecked();
1258
    resolver
1259
        ->Reject(context,
1260
                 v8::Exception::TypeError(FIXED_ONE_BYTE_STRING(
1261
                     context->GetIsolate(), "Invalid host defined options")))
1262
        .ToChecked();
1263
    return handle_scope.Escape(resolver->GetPromise());
1264
  }
1265
1266
  Local<Value> object;
1267
1268
64
  int type = options->Get(iso, HostDefinedOptions::kType)
1269
128
                 .As<Number>()
1270
192
                 ->Int32Value(context)
1271
128
                 .ToChecked();
1272
64
  uint32_t id = options->Get(iso, HostDefinedOptions::kID)
1273
128
                    .As<Number>()
1274
192
                    ->Uint32Value(context)
1275
128
                    .ToChecked();
1276
64
  if (type == ScriptType::kScript) {
1277
3
    contextify::ContextifyScript* wrap = env->id_to_script_map.find(id)->second;
1278
6
    object = wrap->object();
1279
61
  } else if (type == ScriptType::kModule) {
1280
39
    ModuleWrap* wrap = ModuleWrap::GetFromID(env, id);
1281
78
    object = wrap->object();
1282
22
  } else if (type == ScriptType::kFunction) {
1283
22
    auto it = env->id_to_function_map.find(id);
1284
22
    CHECK_NE(it, env->id_to_function_map.end());
1285
44
    object = it->second->object();
1286
  } else {
1287
    UNREACHABLE();
1288
  }
1289
1290
  Local<Value> import_args[] = {
1291
    object,
1292
    Local<Value>(specifier),
1293
128
  };
1294
1295
  Local<Value> result;
1296
128
  if (import_callback->Call(
1297
        context,
1298
        v8::Undefined(iso),
1299
64
        arraysize(import_args),
1300
192
        import_args).ToLocal(&result)) {
1301
64
    CHECK(result->IsPromise());
1302
64
    return handle_scope.Escape(result.As<Promise>());
1303
  }
1304
1305
  return MaybeLocal<Promise>();
1306
}
1307
1308
111
void ModuleWrap::SetImportModuleDynamicallyCallback(
1309
    const FunctionCallbackInfo<Value>& args) {
1310
111
  Isolate* iso = args.GetIsolate();
1311
111
  Environment* env = Environment::GetCurrent(args);
1312
111
  HandleScope handle_scope(iso);
1313
1314
111
  CHECK_EQ(args.Length(), 1);
1315
222
  CHECK(args[0]->IsFunction());
1316
222
  Local<Function> import_callback = args[0].As<Function>();
1317
111
  env->set_host_import_module_dynamically_callback(import_callback);
1318
1319
111
  iso->SetHostImportModuleDynamicallyCallback(ImportModuleDynamically);
1320
111
}
1321
1322
176
void ModuleWrap::HostInitializeImportMetaObjectCallback(
1323
    Local<Context> context, Local<Module> module, Local<Object> meta) {
1324
176
  Environment* env = Environment::GetCurrent(context);
1325
176
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
1326
176
  ModuleWrap* module_wrap = GetFromModule(env, module);
1327
1328
176
  if (module_wrap == nullptr) {
1329
176
    return;
1330
  }
1331
1332
176
  Local<Object> wrap = module_wrap->object();
1333
  Local<Function> callback =
1334
176
      env->host_initialize_import_meta_object_callback();
1335
528
  Local<Value> args[] = { wrap, meta };
1336
176
  TryCatchScope try_catch(env);
1337
  USE(callback->Call(
1338
352
        context, Undefined(env->isolate()), arraysize(args), args));
1339

176
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
1340
    try_catch.ReThrow();
1341
176
  }
1342
}
1343
1344
111
void ModuleWrap::SetInitializeImportMetaObjectCallback(
1345
    const FunctionCallbackInfo<Value>& args) {
1346
111
  Environment* env = Environment::GetCurrent(args);
1347
111
  Isolate* isolate = env->isolate();
1348
1349
111
  CHECK_EQ(args.Length(), 1);
1350
222
  CHECK(args[0]->IsFunction());
1351
222
  Local<Function> import_meta_callback = args[0].As<Function>();
1352
111
  env->set_host_initialize_import_meta_object_callback(import_meta_callback);
1353
1354
  isolate->SetHostInitializeImportMetaObjectCallback(
1355
111
      HostInitializeImportMetaObjectCallback);
1356
111
}
1357
1358
5084
void ModuleWrap::Initialize(Local<Object> target,
1359
                            Local<Value> unused,
1360
                            Local<Context> context,
1361
                            void* priv) {
1362
5084
  Environment* env = Environment::GetCurrent(context);
1363
5084
  Isolate* isolate = env->isolate();
1364
1365
5084
  Local<FunctionTemplate> tpl = env->NewFunctionTemplate(New);
1366
10168
  tpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"));
1367
10168
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
1368
1369
5084
  env->SetProtoMethod(tpl, "link", Link);
1370
5084
  env->SetProtoMethod(tpl, "instantiate", Instantiate);
1371
5084
  env->SetProtoMethod(tpl, "evaluate", Evaluate);
1372
5084
  env->SetProtoMethodNoSideEffect(tpl, "getNamespace", GetNamespace);
1373
5084
  env->SetProtoMethodNoSideEffect(tpl, "getStatus", GetStatus);
1374
5084
  env->SetProtoMethodNoSideEffect(tpl, "getError", GetError);
1375
  env->SetProtoMethodNoSideEffect(tpl, "getStaticDependencySpecifiers",
1376
5084
                                  GetStaticDependencySpecifiers);
1377
1378
  target->Set(env->context(), FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"),
1379
25420
              tpl->GetFunction(context).ToLocalChecked()).Check();
1380
5084
  env->SetMethod(target, "resolve", Resolve);
1381
5084
  env->SetMethod(target, "getPackageType", GetPackageType);
1382
  env->SetMethod(target,
1383
                 "setImportModuleDynamicallyCallback",
1384
5084
                 SetImportModuleDynamicallyCallback);
1385
  env->SetMethod(target,
1386
                 "setInitializeImportMetaObjectCallback",
1387
5084
                 SetInitializeImportMetaObjectCallback);
1388
1389
#define V(name)                                                                \
1390
    target->Set(context,                                                       \
1391
      FIXED_ONE_BYTE_STRING(env->isolate(), #name),                            \
1392
      Integer::New(env->isolate(), Module::Status::name))                      \
1393
        .FromJust()
1394
20336
    V(kUninstantiated);
1395
20336
    V(kInstantiating);
1396
20336
    V(kInstantiated);
1397
20336
    V(kEvaluating);
1398
20336
    V(kEvaluated);
1399
20336
    V(kErrored);
1400
#undef V
1401
5084
}
1402
1403
}  // namespace loader
1404
}  // namespace node
1405
1406
4943
NODE_MODULE_CONTEXT_AWARE_INTERNAL(module_wrap,
1407
                                   node::loader::ModuleWrap::Initialize)