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: 705 828 85.1 %
Date: 2019-10-08 22:34:21 Branches: 392 601 65.2 %

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
726
ModuleWrap::ModuleWrap(Environment* env,
59
                       Local<Object> object,
60
                       Local<Module> module,
61
                       Local<String> url) :
62
  BaseObject(env, object),
63
3630
  id_(env->get_next_module_id()) {
64
726
  module_.Reset(env->isolate(), module);
65
726
  url_.Reset(env->isolate(), url);
66
726
  env->id_to_module_map.emplace(id_, this);
67
726
}
68
69
4907
ModuleWrap::~ModuleWrap() {
70
701
  HandleScope scope(env()->isolate());
71
1402
  Local<Module> module = module_.Get(env()->isolate());
72
701
  env()->id_to_module_map.erase(id_);
73
701
  auto range = env()->hash_to_module_map.equal_range(module->GetIdentityHash());
74
701
  for (auto it = range.first; it != range.second; ++it) {
75
701
    if (it->second == this) {
76
701
      env()->hash_to_module_map.erase(it);
77
701
      break;
78
    }
79
701
  }
80
1402
}
81
82
667
ModuleWrap* ModuleWrap::GetFromModule(Environment* env,
83
                                      Local<Module> module) {
84
667
  auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash());
85
667
  for (auto it = range.first; it != range.second; ++it) {
86
1334
    if (it->second->module_ == module) {
87
667
      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
// new ModuleWrap(source, url)
102
// new ModuleWrap(source, url, context?, lineOffset, columnOffset)
103
// new ModuleWrap(syntheticExecutionFunction, export_names, url)
104
732
void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
105
732
  Environment* env = Environment::GetCurrent(args);
106
732
  Isolate* isolate = env->isolate();
107
108
732
  CHECK(args.IsConstructCall());
109
732
  Local<Object> that = args.This();
110
111
732
  const int argc = args.Length();
112
732
  CHECK_GE(argc, 2);
113
114
  Local<Context> context;
115
  Local<Integer> line_offset;
116
  Local<Integer> column_offset;
117
118
732
  if (argc == 5) {
119
    // new ModuleWrap(source, url, context?, lineOffset, columnOffset)
120
162
    if (args[2]->IsUndefined()) {
121
47
      context = that->CreationContext();
122
    } else {
123
14
      CHECK(args[2]->IsObject());
124
      ContextifyContext* sandbox =
125
          ContextifyContext::ContextFromContextifiedSandbox(
126
14
              env, args[2].As<Object>());
127
7
      CHECK_NOT_NULL(sandbox);
128
7
      context = sandbox->context();
129
    }
130
131
108
    CHECK(args[3]->IsNumber());
132
108
    line_offset = args[3].As<Integer>();
133
134
108
    CHECK(args[4]->IsNumber());
135
108
    column_offset = args[4].As<Integer>();
136
  } else {
137
    // new ModuleWrap(source, url)
138
678
    context = that->CreationContext();
139
678
    line_offset = Integer::New(isolate, 0);
140
678
    column_offset = Integer::New(isolate, 0);
141
  }
142
143
  Local<String> url;
144
  Local<Module> module;
145
146
  Local<PrimitiveArray> host_defined_options =
147
732
      PrimitiveArray::New(isolate, HostDefinedOptions::kLength);
148
  host_defined_options->Set(isolate, HostDefinedOptions::kType,
149
1464
                            Number::New(isolate, ScriptType::kModule));
150
151
  // new ModuleWrap(syntheticExecutionFunction, export_names, url)
152
1464
  bool synthetic = args[0]->IsFunction();
153
732
  if (synthetic) {
154
1026
    CHECK(args[1]->IsArray());
155
1026
    Local<Array> export_names_arr = args[1].As<Array>();
156
157
513
    uint32_t len = export_names_arr->Length();
158
513
    std::vector<Local<String>> export_names(len);
159
10589
    for (uint32_t i = 0; i < len; i++) {
160
      Local<Value> export_name_val =
161
20152
          export_names_arr->Get(context, i).ToLocalChecked();
162
20152
      CHECK(export_name_val->IsString());
163
20152
      export_names[i] = export_name_val.As<String>();
164
    }
165
166
1539
    CHECK(args[2]->IsString());
167
1026
    url = args[2].As<String>();
168
169
    module = Module::CreateSyntheticModule(isolate, url, export_names,
170
513
        SyntheticModuleEvaluationStepsCallback);
171
  // Compile
172
  } else {
173
657
    CHECK(args[0]->IsString());
174
438
    Local<String> source_text = args[0].As<String>();
175
176
657
    CHECK(args[1]->IsString());
177
438
    url = args[1].As<String>();
178
179
219
    ShouldNotAbortOnUncaughtScope no_abort_scope(env);
180
432
    TryCatchScope try_catch(env);
181
182
    {
183
      ScriptOrigin origin(url,
184
                          line_offset,                      // line offset
185
                          column_offset,                    // column offset
186
                          True(isolate),                    // is cross origin
187
                          Local<Integer>(),                 // script id
188
                          Local<Value>(),                   // source map URL
189
                          False(isolate),                   // is opaque (?)
190
                          False(isolate),                   // is WASM
191
                          True(isolate),                    // is ES Module
192
219
                          host_defined_options);
193
      Context::Scope context_scope(context);
194
213
      ScriptCompiler::Source source(source_text, origin);
195
438
      if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) {
196

6
        if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
197
12
          CHECK(!try_catch.Message().IsEmpty());
198
12
          CHECK(!try_catch.Exception().IsEmpty());
199
          AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
200
6
                              ErrorHandlingMode::MODULE_ERROR);
201
6
          try_catch.ReThrow();
202
        }
203
6
        return;
204
213
      }
205
213
    }
206
  }
207
208
2904
  if (!that->Set(context, env->url_string(), url).FromMaybe(false)) {
209
    return;
210
  }
211
212
726
  ModuleWrap* obj = new ModuleWrap(env, that, module, url);
213
214
726
  if (synthetic) {
215
513
    obj->synthetic_ = true;
216
    obj->synthetic_evaluation_steps_.Reset(
217
1539
        env->isolate(), args[0].As<Function>());
218
  }
219
220
726
  obj->context_.Reset(isolate, context);
221
222
726
  env->hash_to_module_map.emplace(module->GetIdentityHash(), obj);
223
224
  host_defined_options->Set(isolate, HostDefinedOptions::kID,
225
1452
                            Number::New(isolate, obj->id()));
226
227
726
  that->SetIntegrityLevel(context, IntegrityLevel::kFrozen);
228
1452
  args.GetReturnValue().Set(that);
229
}
230
231
417
void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
232
417
  Environment* env = Environment::GetCurrent(args);
233
417
  Isolate* isolate = args.GetIsolate();
234
235
417
  CHECK_EQ(args.Length(), 1);
236
834
  CHECK(args[0]->IsFunction());
237
238
417
  Local<Object> that = args.This();
239
240
  ModuleWrap* obj;
241
419
  ASSIGN_OR_RETURN_UNWRAP(&obj, that);
242
243
417
  if (obj->linked_)
244
2
    return;
245
415
  obj->linked_ = true;
246
247
830
  Local<Function> resolver_arg = args[0].As<Function>();
248
249
830
  Local<Context> mod_context = obj->context_.Get(isolate);
250
830
  Local<Module> module = obj->module_.Get(isolate);
251
252
  Local<Array> promises = Array::New(isolate,
253
415
                                     module->GetModuleRequestsLength());
254
255
  // call the dependency resolve callbacks
256
1244
  for (int i = 0; i < module->GetModuleRequestsLength(); i++) {
257
207
    Local<String> specifier = module->GetModuleRequest(i);
258
207
    Utf8Value specifier_utf8(env->isolate(), specifier);
259
414
    std::string specifier_std(*specifier_utf8, specifier_utf8.length());
260
261
    Local<Value> argv[] = {
262
      specifier
263
414
    };
264
265
    MaybeLocal<Value> maybe_resolve_return_value =
266
207
        resolver_arg->Call(mod_context, that, 1, argv);
267
207
    if (maybe_resolve_return_value.IsEmpty()) {
268
      return;
269
    }
270
    Local<Value> resolve_return_value =
271
207
        maybe_resolve_return_value.ToLocalChecked();
272
207
    if (!resolve_return_value->IsPromise()) {
273
      env->ThrowError("linking error, expected resolver to return a promise");
274
    }
275
207
    Local<Promise> resolve_promise = resolve_return_value.As<Promise>();
276
207
    obj->resolve_cache_[specifier_std].Reset(env->isolate(), resolve_promise);
277
278
621
    promises->Set(mod_context, i, resolve_promise).Check();
279
207
  }
280
281
830
  args.GetReturnValue().Set(promises);
282
}
283
284
516
void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) {
285
516
  Environment* env = Environment::GetCurrent(args);
286
516
  Isolate* isolate = args.GetIsolate();
287
  ModuleWrap* obj;
288
519
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
289
1032
  Local<Context> context = obj->context_.Get(isolate);
290
1032
  Local<Module> module = obj->module_.Get(isolate);
291
516
  TryCatchScope try_catch(env);
292
516
  USE(module->InstantiateModule(context, ResolveCallback));
293
294
  // clear resolve cache on instantiate
295
516
  obj->resolve_cache_.clear();
296
297

516
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
298
6
    CHECK(!try_catch.Message().IsEmpty());
299
6
    CHECK(!try_catch.Exception().IsEmpty());
300
    AppendExceptionLine(env, try_catch.Exception(), try_catch.Message(),
301
3
                        ErrorHandlingMode::MODULE_ERROR);
302
3
    try_catch.ReThrow();
303
3
    return;
304
513
  }
305
}
306
307
518
void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) {
308
518
  Environment* env = Environment::GetCurrent(args);
309
518
  Isolate* isolate = env->isolate();
310
  ModuleWrap* obj;
311
531
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
312
1036
  Local<Context> context = obj->context_.Get(isolate);
313
1036
  Local<Module> module = obj->module_.Get(isolate);
314
315
  // module.evaluate(timeout, breakOnSigint)
316
518
  CHECK_EQ(args.Length(), 2);
317
318
1036
  CHECK(args[0]->IsNumber());
319
2072
  int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
320
321
1036
  CHECK(args[1]->IsBoolean());
322
1036
  bool break_on_sigint = args[1]->IsTrue();
323
324
518
  ShouldNotAbortOnUncaughtScope no_abort_scope(env);
325
1022
  TryCatchScope try_catch(env);
326
327
518
  bool timed_out = false;
328
518
  bool received_signal = false;
329
  MaybeLocal<Value> result;
330

518
  if (break_on_sigint && timeout != -1) {
331
    Watchdog wd(isolate, timeout, &timed_out);
332
    SigintWatchdog swd(isolate, &received_signal);
333
    result = module->Evaluate(context);
334
518
  } else if (break_on_sigint) {
335
    SigintWatchdog swd(isolate, &received_signal);
336
    result = module->Evaluate(context);
337
518
  } else if (timeout != -1) {
338
1
    Watchdog wd(isolate, timeout, &timed_out);
339
1
    result = module->Evaluate(context);
340
  } else {
341
517
    result = module->Evaluate(context);
342
  }
343
344
517
  if (result.IsEmpty()) {
345
13
    CHECK(try_catch.HasCaught());
346
  }
347
348
  // Convert the termination exception into a regular exception.
349

517
  if (timed_out || received_signal) {
350

1
    if (!env->is_main_thread() && env->is_stopping())
351
      return;
352
1
    env->isolate()->CancelTerminateExecution();
353
    // It is possible that execution was terminated by another timeout in
354
    // which this timeout is nested, so check whether one of the watchdogs
355
    // from this invocation is responsible for termination.
356
1
    if (timed_out) {
357
1
      THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
358
    } else if (received_signal) {
359
      THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
360
    }
361
  }
362
363
517
  if (try_catch.HasCaught()) {
364
13
    if (!try_catch.HasTerminated())
365
12
      try_catch.ReThrow();
366
13
    return;
367
  }
368
369
1512
  args.GetReturnValue().Set(result.ToLocalChecked());
370
}
371
372
122
void ModuleWrap::GetNamespace(const FunctionCallbackInfo<Value>& args) {
373
122
  Environment* env = Environment::GetCurrent(args);
374
122
  Isolate* isolate = args.GetIsolate();
375
  ModuleWrap* obj;
376
122
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
377
378
244
  Local<Module> module = obj->module_.Get(isolate);
379
380
122
  switch (module->GetStatus()) {
381
    default:
382
      return env->ThrowError(
383
          "cannot get namespace, Module has not been instantiated");
384
    case v8::Module::Status::kInstantiated:
385
    case v8::Module::Status::kEvaluating:
386
    case v8::Module::Status::kEvaluated:
387
122
      break;
388
  }
389
390
122
  Local<Value> result = module->GetModuleNamespace();
391
244
  args.GetReturnValue().Set(result);
392
}
393
394
133
void ModuleWrap::GetStatus(const FunctionCallbackInfo<Value>& args) {
395
133
  Isolate* isolate = args.GetIsolate();
396
  ModuleWrap* obj;
397
266
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
398
399
266
  Local<Module> module = obj->module_.Get(isolate);
400
401
399
  args.GetReturnValue().Set(module->GetStatus());
402
}
403
404
2
void ModuleWrap::GetStaticDependencySpecifiers(
405
    const FunctionCallbackInfo<Value>& args) {
406
2
  Environment* env = Environment::GetCurrent(args);
407
  ModuleWrap* obj;
408
4
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
409
410
4
  Local<Module> module = obj->module_.Get(env->isolate());
411
412
2
  int count = module->GetModuleRequestsLength();
413
414
2
  Local<Array> specifiers = Array::New(env->isolate(), count);
415
416
3
  for (int i = 0; i < count; i++)
417
4
    specifiers->Set(env->context(), i, module->GetModuleRequest(i)).Check();
418
419
4
  args.GetReturnValue().Set(specifiers);
420
}
421
422
1
void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
423
1
  Isolate* isolate = args.GetIsolate();
424
  ModuleWrap* obj;
425
2
  ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
426
427
2
  Local<Module> module = obj->module_.Get(isolate);
428
3
  args.GetReturnValue().Set(module->GetException());
429
}
430
431
198
MaybeLocal<Module> ModuleWrap::ResolveCallback(Local<Context> context,
432
                                               Local<String> specifier,
433
                                               Local<Module> referrer) {
434
198
  Environment* env = Environment::GetCurrent(context);
435
198
  CHECK_NOT_NULL(env);  // TODO(addaleax): Handle nullptr here.
436
198
  Isolate* isolate = env->isolate();
437
438
198
  ModuleWrap* dependent = GetFromModule(env, referrer);
439
198
  if (dependent == nullptr) {
440
    env->ThrowError("linking error, null dep");
441
    return MaybeLocal<Module>();
442
  }
443
444
198
  Utf8Value specifier_utf8(isolate, specifier);
445
396
  std::string specifier_std(*specifier_utf8, specifier_utf8.length());
446
447
198
  if (dependent->resolve_cache_.count(specifier_std) != 1) {
448
    env->ThrowError("linking error, not in local cache");
449
    return MaybeLocal<Module>();
450
  }
451
452
  Local<Promise> resolve_promise =
453
396
      dependent->resolve_cache_[specifier_std].Get(isolate);
454
455
198
  if (resolve_promise->State() != Promise::kFulfilled) {
456
    env->ThrowError("linking error, dependency promises must be resolved on "
457
                    "instantiate");
458
    return MaybeLocal<Module>();
459
  }
460
461
396
  Local<Object> module_object = resolve_promise->Result().As<Object>();
462

396
  if (module_object.IsEmpty() || !module_object->IsObject()) {
463
    env->ThrowError("linking error, expected a valid module object from "
464
                    "resolver");
465
    return MaybeLocal<Module>();
466
  }
467
468
  ModuleWrap* module;
469
198
  ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Module>());
470
594
  return module->module_.Get(isolate);
471
}
472
473
namespace {
474
475
// Tests whether a path starts with /, ./ or ../
476
// In WhatWG terminology, the alternative case is called a "bare" specifier
477
// (e.g. in `import "jquery"`).
478
240
inline bool ShouldBeTreatedAsRelativeOrAbsolutePath(
479
    const std::string& specifier) {
480
240
  size_t len = specifier.length();
481
240
  if (len == 0)
482
    return false;
483
240
  if (specifier[0] == '/') {
484
    return true;
485
240
  } else if (specifier[0] == '.') {
486

110
    if (len == 1 || specifier[1] == '/')
487
34
      return true;
488
76
    if (specifier[1] == '.') {
489

76
      if (len == 2 || specifier[2] == '/')
490
76
        return true;
491
    }
492
  }
493
130
  return false;
494
}
495
496
19
std::string ReadFile(uv_file file) {
497
19
  std::string contents;
498
  uv_fs_t req;
499
  char buffer_memory[4096];
500
19
  uv_buf_t buf = uv_buf_init(buffer_memory, sizeof(buffer_memory));
501
502
  do {
503
    const int r = uv_fs_read(nullptr,
504
                             &req,
505
                             file,
506
                             &buf,
507
                             1,
508
38
                             contents.length(),  // offset
509
38
                             nullptr);
510
38
    uv_fs_req_cleanup(&req);
511
512
38
    if (r <= 0)
513
19
      break;
514
19
    contents.append(buf.base, r);
515
  } while (true);
516
19
  return contents;
517
}
518
519
enum DescriptorType {
520
  FILE,
521
  DIRECTORY,
522
  NONE
523
};
524
525
// When DescriptorType cache is added, this can also return
526
// Nothing for the "null" cache entries.
527
1205
inline Maybe<uv_file> OpenDescriptor(const std::string& path) {
528
  uv_fs_t fs_req;
529
#ifdef _WIN32
530
  std::string pth = "\\\\.\\" + path;
531
  uv_file fd = uv_fs_open(nullptr, &fs_req, pth.c_str(), O_RDONLY, 0, nullptr);
532
#else
533
1205
  uv_file fd = uv_fs_open(nullptr, &fs_req, path.c_str(), O_RDONLY, 0, nullptr);
534
#endif
535
1205
  uv_fs_req_cleanup(&fs_req);
536
1205
  if (fd < 0) return Nothing<uv_file>();
537
256
  return Just(fd);
538
}
539
540
256
inline void CloseDescriptor(uv_file fd) {
541
  uv_fs_t fs_req;
542
256
  CHECK_EQ(0, uv_fs_close(nullptr, &fs_req, fd, nullptr));
543
256
  uv_fs_req_cleanup(&fs_req);
544
256
}
545
546
256
inline DescriptorType CheckDescriptorAtFile(uv_file fd) {
547
  uv_fs_t fs_req;
548
256
  int rc = uv_fs_fstat(nullptr, &fs_req, fd, nullptr);
549
256
  if (rc == 0) {
550
256
    uint64_t is_directory = fs_req.statbuf.st_mode & S_IFDIR;
551
256
    uv_fs_req_cleanup(&fs_req);
552
256
    return is_directory ? DIRECTORY : FILE;
553
  }
554
  uv_fs_req_cleanup(&fs_req);
555
  return NONE;
556
}
557
558
// TODO(@guybedford): Add a DescriptorType cache layer here.
559
// Should be directory based -> if path/to/dir doesn't exist
560
// then the cache should early-fail any path/to/dir/file check.
561
320
DescriptorType CheckDescriptorAtPath(const std::string& path) {
562
320
  Maybe<uv_file> fd = OpenDescriptor(path);
563
320
  if (fd.IsNothing()) return NONE;
564
237
  DescriptorType type = CheckDescriptorAtFile(fd.FromJust());
565
237
  CloseDescriptor(fd.FromJust());
566
237
  return type;
567
}
568
569
885
Maybe<std::string> ReadIfFile(const std::string& path) {
570
885
  Maybe<uv_file> fd = OpenDescriptor(path);
571
885
  if (fd.IsNothing()) return Nothing<std::string>();
572
19
  DescriptorType type = CheckDescriptorAtFile(fd.FromJust());
573
19
  if (type != FILE) return Nothing<std::string>();
574
19
  std::string source = ReadFile(fd.FromJust());
575
19
  CloseDescriptor(fd.FromJust());
576
19
  return Just(source);
577
}
578
579
using Exists = PackageConfig::Exists;
580
using IsValid = PackageConfig::IsValid;
581
using HasMain = PackageConfig::HasMain;
582
using PackageType = PackageConfig::PackageType;
583
584
1759
Maybe<const PackageConfig*> GetPackageConfig(Environment* env,
585
                                             const std::string& path,
586
                                             const URL& base) {
587
1759
  auto existing = env->package_json_cache.find(path);
588
1759
  if (existing != env->package_json_cache.end()) {
589
874
    const PackageConfig* pcfg = &existing->second;
590
874
    if (pcfg->is_valid == IsValid::No) {
591
      std::string msg = "Invalid JSON in " + path +
592
        " imported from " + base.ToFilePath();
593
      node::THROW_ERR_INVALID_PACKAGE_CONFIG(env, msg.c_str());
594
      return Nothing<const PackageConfig*>();
595
    }
596
874
    return Just(pcfg);
597
  }
598
599
885
  Maybe<std::string> source = ReadIfFile(path);
600
601
885
  if (source.IsNothing()) {
602
    auto entry = env->package_json_cache.emplace(path,
603
        PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "",
604
1732
                        PackageType::None, Global<Value>() });
605
866
    return Just(&entry.first->second);
606
  }
607
608
19
  std::string pkg_src = source.FromJust();
609
610
19
  Isolate* isolate = env->isolate();
611
38
  v8::HandleScope handle_scope(isolate);
612
613
  Local<Object> pkg_json;
614
  {
615
    Local<Value> src;
616
    Local<Value> pkg_json_v;
617
19
    Local<Context> context = env->context();
618
619

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

152
        !v8::JSON::Parse(context, src.As<String>()).ToLocal(&pkg_json_v) ||
621
57
        !pkg_json_v->ToObject(context).ToLocal(&pkg_json)) {
622
      env->package_json_cache.emplace(path,
623
          PackageConfig { Exists::Yes, IsValid::No, HasMain::No, "",
624
                          PackageType::None, Global<Value>() });
625
      std::string msg = "Invalid JSON in " + path +
626
          " imported from " + base.ToFilePath();
627
      node::THROW_ERR_INVALID_PACKAGE_CONFIG(env, msg.c_str());
628
      return Nothing<const PackageConfig*>();
629
    }
630
  }
631
632
  Local<Value> pkg_main;
633
19
  HasMain has_main = HasMain::No;
634
38
  std::string main_std;
635
76
  if (pkg_json->Get(env->context(), env->main_string()).ToLocal(&pkg_main)) {
636
38
    if (pkg_main->IsString()) {
637
14
      has_main = HasMain::Yes;
638
    }
639
19
    Utf8Value main_utf8(isolate, pkg_main);
640
19
    main_std.assign(std::string(*main_utf8, main_utf8.length()));
641
  }
642
643
19
  PackageType pkg_type = PackageType::None;
644
  Local<Value> type_v;
645
76
  if (pkg_json->Get(env->context(), env->type_string()).ToLocal(&type_v)) {
646
38
    if (type_v->StrictEquals(env->module_string())) {
647
6
      pkg_type = PackageType::Module;
648
26
    } else if (type_v->StrictEquals(env->commonjs_string())) {
649
4
      pkg_type = PackageType::CommonJS;
650
    }
651
    // ignore unknown types for forwards compatibility
652
  }
653
654
  Local<Value> exports_v;
655

114
  if (env->options()->experimental_exports &&
656
      pkg_json->Get(env->context(),
657


152
      env->exports_string()).ToLocal(&exports_v) &&
658
38
      !exports_v->IsNullOrUndefined()) {
659
    Global<Value> exports;
660
2
    exports.Reset(env->isolate(), exports_v);
661
662
    auto entry = env->package_json_cache.emplace(path,
663
        PackageConfig { Exists::Yes, IsValid::Yes, has_main, main_std,
664
4
                        pkg_type, std::move(exports) });
665
2
    return Just(&entry.first->second);
666
  }
667
668
  auto entry = env->package_json_cache.emplace(path,
669
      PackageConfig { Exists::Yes, IsValid::Yes, has_main, main_std,
670
34
                      pkg_type, Global<Value>() });
671
902
  return Just(&entry.first->second);
672
}
673
674
203
Maybe<const PackageConfig*> GetPackageScopeConfig(Environment* env,
675
                                                  const URL& resolved,
676
                                                  const URL& base) {
677
203
  URL pjson_url("./package.json", &resolved);
678
  while (true) {
679
1732
    std::string pjson_url_path = pjson_url.path();
680

6418
    if (pjson_url_path.length() > 25 &&
681
5398
        pjson_url_path.substr(pjson_url_path.length() - 25, 25) ==
682
        "node_modules/package.json") {
683
2
      break;
684
    }
685
    Maybe<const PackageConfig*> pkg_cfg =
686
1730
        GetPackageConfig(env, pjson_url.ToFilePath(), base);
687
1730
    if (pkg_cfg.IsNothing()) return pkg_cfg;
688
1730
    if (pkg_cfg.FromJust()->exists == Exists::Yes) return pkg_cfg;
689
690
3228
    URL last_pjson_url = pjson_url;
691
1699
    pjson_url = URL("../package.json", pjson_url);
692
693
    // Terminates at root where ../package.json equals ../../package.json
694
    // (can't just check "/package.json" for Windows support).
695

1699
    if (pjson_url.path() == last_pjson_url.path()) break;
696
1529
  }
697
  auto entry = env->package_json_cache.emplace(pjson_url.ToFilePath(),
698
  PackageConfig { Exists::No, IsValid::Yes, HasMain::No, "",
699
344
                  PackageType::None, Global<Value>() });
700
172
  const PackageConfig* pcfg = &entry.first->second;
701
172
  return Just(pcfg);
702
}
703
704
/*
705
 * Legacy CommonJS main resolution:
706
 * 1. let M = pkg_url + (json main field)
707
 * 2. TRY(M, M.js, M.json, M.node)
708
 * 3. TRY(M/index.js, M/index.json, M/index.node)
709
 * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
710
 * 5. NOT_FOUND
711
 */
712
56
inline bool FileExists(const URL& url) {
713
56
  return CheckDescriptorAtPath(url.ToFilePath()) == FILE;
714
}
715
Maybe<URL> LegacyMainResolve(const URL& pjson_url,
716
                             const PackageConfig& pcfg) {
717
  URL guess;
718
  if (pcfg.has_main == HasMain::Yes) {
719
    // Note: fs check redundances will be handled by Descriptor cache here.
720
    if (FileExists(guess = URL("./" + pcfg.main, pjson_url))) {
721
      return Just(guess);
722
    }
723
    if (FileExists(guess = URL("./" + pcfg.main + ".js", pjson_url))) {
724
      return Just(guess);
725
    }
726
    if (FileExists(guess = URL("./" + pcfg.main + ".json", pjson_url))) {
727
      return Just(guess);
728
    }
729
    if (FileExists(guess = URL("./" + pcfg.main + ".node", pjson_url))) {
730
      return Just(guess);
731
    }
732
    if (FileExists(guess = URL("./" + pcfg.main + "/index.js", pjson_url))) {
733
      return Just(guess);
734
    }
735
    // Such stat.
736
    if (FileExists(guess = URL("./" + pcfg.main + "/index.json", pjson_url))) {
737
      return Just(guess);
738
    }
739
    if (FileExists(guess = URL("./" + pcfg.main + "/index.node", pjson_url))) {
740
      return Just(guess);
741
    }
742
    // Fallthrough.
743
  }
744
  if (FileExists(guess = URL("./index.js", pjson_url))) {
745
    return Just(guess);
746
  }
747
  // So fs.
748
  if (FileExists(guess = URL("./index.json", pjson_url))) {
749
    return Just(guess);
750
  }
751
  if (FileExists(guess = URL("./index.node", pjson_url))) {
752
    return Just(guess);
753
  }
754
  // Not found.
755
  return Nothing<URL>();
756
}
757
758
enum ResolveExtensionsOptions {
759
  TRY_EXACT_NAME,
760
  ONLY_VIA_EXTENSIONS
761
};
762
763
template <ResolveExtensionsOptions options>
764
22
Maybe<URL> ResolveExtensions(const URL& search) {
765
  if (options == TRY_EXACT_NAME) {
766
17
    if (FileExists(search)) {
767
9
      return Just(search);
768
    }
769
  }
770
771

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

39
    if (FileExists(guess)) {
774

7
      return Just(guess);
775
    }
776
  }
777
778
6
  return Nothing<URL>();
779
}
780
781
5
inline Maybe<URL> ResolveIndex(const URL& search) {
782
5
  return ResolveExtensions<ONLY_VIA_EXTENSIONS>(URL("index", search));
783
}
784
785
217
Maybe<URL> FinalizeResolution(Environment* env,
786
                              const URL& resolved,
787
                              const URL& base) {
788
217
  if (env->options()->es_module_specifier_resolution == "node") {
789
17
    Maybe<URL> file = ResolveExtensions<TRY_EXACT_NAME>(resolved);
790
17
    if (!file.IsNothing()) {
791
12
      return file;
792
    }
793
5
    if (resolved.path().back() != '/') {
794
4
      file = ResolveIndex(URL(resolved.path() + "/", &base));
795
    } else {
796
1
      file = ResolveIndex(resolved);
797
    }
798
5
    if (!file.IsNothing()) {
799
4
      return file;
800
    }
801
2
    std::string msg = "Cannot find module " + resolved.path() +
802
4
        " imported from " + base.ToFilePath();
803
1
    node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
804
18
    return Nothing<URL>();
805
  }
806
807
200
  const std::string& path = resolved.ToFilePath();
808
200
  if (CheckDescriptorAtPath(path) != FILE) {
809
30
    std::string msg = "Cannot find module " +
810
45
        (path.length() != 0 ? path : resolved.path()) +
811
45
        " imported from " + base.ToFilePath();
812
15
    node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
813
15
    return Nothing<URL>();
814
  }
815
816
185
  return Just(resolved);
817
}
818
819
2
void ThrowExportsNotFound(Environment* env,
820
                          const std::string& subpath,
821
                          const URL& pjson_url,
822
                          const URL& base) {
823
4
  const std::string msg = "Package exports for " +
824
4
      pjson_url.ToFilePath() + " do not define a '" + subpath +
825
6
      "' subpath, imported from " + base.ToFilePath();
826
2
  node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
827
2
}
828
829
18
void ThrowExportsInvalid(Environment* env,
830
                         const std::string& subpath,
831
                         const std::string& target,
832
                         const URL& pjson_url,
833
                         const URL& base) {
834
36
  const std::string msg = "Cannot resolve package exports target '" + target +
835
72
      "' matched for '" + subpath + "' in " + pjson_url.ToFilePath() +
836
54
      ", imported from " + base.ToFilePath();
837
18
  node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
838
18
}
839
840
8
void ThrowExportsInvalid(Environment* env,
841
                         const std::string& subpath,
842
                         Local<Value> target,
843
                         const URL& pjson_url,
844
                         const URL& base) {
845
  Local<String> target_string;
846
24
  if (target->ToString(env->context()).ToLocal(&target_string)) {
847
8
    Utf8Value target_utf8(env->isolate(), target_string);
848
16
    std::string target_str(*target_utf8, target_utf8.length());
849
8
    if (target->IsArray()) {
850
1
      target_str = '[' + target_str + ']';
851
    }
852
16
    ThrowExportsInvalid(env, subpath, target_str, pjson_url, base);
853
  }
854
8
}
855
856
19
Maybe<URL> ResolveExportsTarget(Environment* env,
857
                                const std::string& target,
858
                                const std::string& subpath,
859
                                const std::string& match,
860
                                const URL& pjson_url,
861
                                const URL& base,
862
                                bool throw_invalid = true) {
863
19
  if (target.substr(0, 2) != "./") {
864
8
    if (throw_invalid) {
865
5
      ThrowExportsInvalid(env, match, target, pjson_url, base);
866
    }
867
8
    return Nothing<URL>();
868
  }
869

11
  if (subpath.length() > 0 && target.back() != '/') {
870
1
    if (throw_invalid) {
871
      ThrowExportsInvalid(env, match, target, pjson_url, base);
872
    }
873
1
    return Nothing<URL>();
874
  }
875
10
  URL resolved(target, pjson_url);
876
20
  std::string resolved_path = resolved.path();
877
20
  std::string pkg_path = URL(".", pjson_url).path();
878

20
  if (resolved_path.find(pkg_path) != 0 ||
879
10
      resolved_path.find("/node_modules/", pkg_path.length() - 1) !=
880
      std::string::npos) {
881
1
    if (throw_invalid) {
882
1
      ThrowExportsInvalid(env, match, target, pjson_url, base);
883
    }
884
1
    return Nothing<URL>();
885
  }
886
9
  if (subpath.length() == 0) return Just(resolved);
887
10
  URL subpath_resolved(subpath, resolved);
888
10
  std::string subpath_resolved_path = subpath_resolved.path();
889

9
  if (subpath_resolved_path.find(resolved_path) != 0 ||
890
4
      subpath_resolved_path.find("/node_modules/", pkg_path.length() - 1)
891
      != std::string::npos) {
892
1
    if (throw_invalid) {
893
1
      ThrowExportsInvalid(env, match, target + subpath, pjson_url, base);
894
    }
895
1
    return Nothing<URL>();
896
  }
897
14
  return Just(subpath_resolved);
898
}
899
900
6
Maybe<URL> PackageMainResolve(Environment* env,
901
                              const URL& pjson_url,
902
                              const PackageConfig& pcfg,
903
                              const URL& base) {
904
6
  if (pcfg.exists == Exists::Yes) {
905
6
    Isolate* isolate = env->isolate();
906
6
    Local<Context> context = env->context();
907
12
    if (!pcfg.exports.IsEmpty()) {
908
2
      Local<Value> exports = pcfg.exports.Get(isolate);
909


3
      if (exports->IsString() || exports->IsObject() || exports->IsArray()) {
910
        Local<Value> target;
911
1
        if (!exports->IsObject()) {
912
          target = exports;
913
        } else {
914
1
          Local<Object> exports_obj = exports.As<Object>();
915
          Local<String> dot_string = String::NewFromUtf8(env->isolate(), ".",
916
2
              v8::NewStringType::kNormal).ToLocalChecked();
917
          target =
918
3
              exports_obj->Get(env->context(), dot_string).ToLocalChecked();
919
        }
920
2
        if (target->IsString()) {
921
1
          Utf8Value target_utf8(isolate, target.As<v8::String>());
922
2
          std::string target(*target_utf8, target_utf8.length());
923
          Maybe<URL> resolved = ResolveExportsTarget(env, target, "", ".",
924
2
              pjson_url, base);
925
1
          if (resolved.IsNothing()) {
926
            ThrowExportsInvalid(env, ".", target, pjson_url, base);
927
            return Nothing<URL>();
928
          }
929
2
          return FinalizeResolution(env, resolved.FromJust(), base);
930
        } else if (target->IsArray()) {
931
          Local<Array> target_arr = target.As<Array>();
932
          const uint32_t length = target_arr->Length();
933
          if (length == 0) {
934
            ThrowExportsInvalid(env, ".", target, pjson_url, base);
935
            return Nothing<URL>();
936
          }
937
          for (uint32_t i = 0; i < length; i++) {
938
            auto target_item = target_arr->Get(context, i).ToLocalChecked();
939
            if (target_item->IsString()) {
940
              Utf8Value target_utf8(isolate, target_item.As<v8::String>());
941
              std::string target_str(*target_utf8, target_utf8.length());
942
              Maybe<URL> resolved = ResolveExportsTarget(env, target_str, "",
943
                  ".", pjson_url, base, false);
944
              if (resolved.IsNothing()) continue;
945
              return FinalizeResolution(env, resolved.FromJust(), base);
946
            }
947
          }
948
          auto invalid = target_arr->Get(context, length - 1).ToLocalChecked();
949
          if (!invalid->IsString()) {
950
            ThrowExportsInvalid(env, ".", invalid, pjson_url, base);
951
            return Nothing<URL>();
952
          }
953
          Utf8Value invalid_utf8(isolate, invalid.As<v8::String>());
954
          std::string invalid_str(*invalid_utf8, invalid_utf8.length());
955
          Maybe<URL> resolved = ResolveExportsTarget(env, invalid_str, "",
956
                                                    ".", pjson_url, base);
957
          CHECK(resolved.IsNothing());
958
          return Nothing<URL>();
959
        } else {
960
          ThrowExportsInvalid(env, ".", target, pjson_url, base);
961
          return Nothing<URL>();
962
        }
963
      }
964
    }
965
5
    if (pcfg.has_main == HasMain::Yes) {
966
5
      URL resolved(pcfg.main, pjson_url);
967
8
      const std::string& path = resolved.ToFilePath();
968
5
      if (CheckDescriptorAtPath(path) == FILE) {
969
2
        return Just(resolved);
970
3
      }
971
    }
972
3
    if (env->options()->es_module_specifier_resolution == "node") {
973
3
      if (pcfg.has_main == HasMain::Yes) {
974
3
        return FinalizeResolution(env, URL(pcfg.main, pjson_url), base);
975
      } else {
976
        return FinalizeResolution(env, URL("index", pjson_url), base);
977
      }
978
    }
979
    if (pcfg.type != PackageType::Module) {
980
      Maybe<URL> resolved = LegacyMainResolve(pjson_url, pcfg);
981
      if (!resolved.IsNothing()) {
982
        return resolved;
983
      }
984
    }
985
  }
986
  std::string msg = "Cannot find main entry point for " +
987
      URL(".", pjson_url).ToFilePath() + " imported from " +
988
      base.ToFilePath();
989
  node::THROW_ERR_MODULE_NOT_FOUND(env, msg.c_str());
990
  return Nothing<URL>();
991
}
992
993
21
Maybe<URL> PackageExportsResolve(Environment* env,
994
                                 const URL& pjson_url,
995
                                 const std::string& pkg_subpath,
996
                                 const PackageConfig& pcfg,
997
                                 const URL& base) {
998
21
  CHECK(env->options()->experimental_exports);
999
21
  Isolate* isolate = env->isolate();
1000
21
  Local<Context> context = env->context();
1001
42
  Local<Value> exports = pcfg.exports.Get(isolate);
1002
21
  if (!exports->IsObject()) {
1003
1
    ThrowExportsNotFound(env, pkg_subpath, pjson_url, base);
1004
1
    return Nothing<URL>();
1005
  }
1006
20
  Local<Object> exports_obj = exports.As<Object>();
1007
  Local<String> subpath = String::NewFromUtf8(isolate,
1008
40
      pkg_subpath.c_str(), v8::NewStringType::kNormal).ToLocalChecked();
1009
1010
40
  if (exports_obj->HasOwnProperty(context, subpath).FromJust()) {
1011
24
    Local<Value> target = exports_obj->Get(context, subpath).ToLocalChecked();
1012
24
    if (target->IsString()) {
1013
5
      Utf8Value target_utf8(isolate, target.As<v8::String>());
1014
10
      std::string target_str(*target_utf8, target_utf8.length());
1015
      Maybe<URL> resolved = ResolveExportsTarget(env, target_str, "",
1016
10
          pkg_subpath, pjson_url, base);
1017
5
      if (resolved.IsNothing()) {
1018
3
        ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
1019
3
        return Nothing<URL>();
1020
      }
1021
7
      return FinalizeResolution(env, resolved.FromJust(), base);
1022
7
    } else if (target->IsArray()) {
1023
3
      Local<Array> target_arr = target.As<Array>();
1024
3
      const uint32_t length = target_arr->Length();
1025
3
      if (length == 0) {
1026
1
        ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
1027
1
        return Nothing<URL>();
1028
      }
1029
9
      for (uint32_t i = 0; i < length; i++) {
1030
16
        auto target_item = target_arr->Get(context, i).ToLocalChecked();
1031
16
        if (target_item->IsString()) {
1032
3
          Utf8Value target_utf8(isolate, target_item.As<v8::String>());
1033
3
          std::string target(*target_utf8, target_utf8.length());
1034
          Maybe<URL> resolved = ResolveExportsTarget(env, target, "",
1035
3
              pkg_subpath, pjson_url, base, false);
1036
3
          if (resolved.IsNothing()) continue;
1037

1
          return FinalizeResolution(env, resolved.FromJust(), base);
1038
        }
1039
      }
1040
3
      auto invalid = target_arr->Get(context, length - 1).ToLocalChecked();
1041
2
      if (!invalid->IsString()) {
1042
        ThrowExportsInvalid(env, pkg_subpath, invalid, pjson_url, base);
1043
        return Nothing<URL>();
1044
      }
1045
1
      Utf8Value invalid_utf8(isolate, invalid.As<v8::String>());
1046
2
      std::string invalid_str(*invalid_utf8, invalid_utf8.length());
1047
      Maybe<URL> resolved = ResolveExportsTarget(env, invalid_str, "",
1048
2
                                                 pkg_subpath, pjson_url, base);
1049
1
      CHECK(resolved.IsNothing());
1050
2
      return Nothing<URL>();
1051
    } else {
1052
4
      ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
1053
4
      return Nothing<URL>();
1054
    }
1055
  }
1056
1057
  Local<String> best_match;
1058
8
  std::string best_match_str = "";
1059
  Local<Array> keys =
1060
16
      exports_obj->GetOwnPropertyNames(context).ToLocalChecked();
1061
288
  for (uint32_t i = 0; i < keys->Length(); ++i) {
1062
408
    Local<String> key = keys->Get(context, i).ToLocalChecked().As<String>();
1063
136
    Utf8Value key_utf8(isolate, key);
1064
168
    std::string key_str(*key_utf8, key_utf8.length());
1065
136
    if (key_str.back() != '/') continue;
1066


39
    if (pkg_subpath.substr(0, key_str.length()) == key_str &&
1067
7
        key_str.length() > best_match_str.length()) {
1068
7
      best_match = key;
1069
7
      best_match_str = key_str;
1070
    }
1071
32
  }
1072
1073
8
  if (best_match_str.length() > 0) {
1074
14
    auto target = exports_obj->Get(context, best_match).ToLocalChecked();
1075
7
    std::string subpath = pkg_subpath.substr(best_match_str.length());
1076
14
    if (target->IsString()) {
1077
6
      Utf8Value target_utf8(isolate, target.As<v8::String>());
1078
12
      std::string target(*target_utf8, target_utf8.length());
1079
      Maybe<URL> resolved = ResolveExportsTarget(env, target, subpath,
1080
12
          pkg_subpath, pjson_url, base);
1081
6
      if (resolved.IsNothing()) {
1082
3
        ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
1083
3
        return Nothing<URL>();
1084
      }
1085
9
      return FinalizeResolution(env, URL(subpath, resolved.FromJust()), base);
1086
1
    } else if (target->IsArray()) {
1087
1
      Local<Array> target_arr = target.As<Array>();
1088
1
      const uint32_t length = target_arr->Length();
1089
1
      if (length == 0) {
1090
        ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
1091
        return Nothing<URL>();
1092
      }
1093
6
      for (uint32_t i = 0; i < length; i++) {
1094
12
        auto target_item = target_arr->Get(context, i).ToLocalChecked();
1095
12
        if (target_item->IsString()) {
1096
3
          Utf8Value target_utf8(isolate, target_item.As<v8::String>());
1097
3
          std::string target_str(*target_utf8, target_utf8.length());
1098
          Maybe<URL> resolved = ResolveExportsTarget(env, target_str, subpath,
1099
3
              pkg_subpath, pjson_url, base, false);
1100
3
          if (resolved.IsNothing()) continue;
1101

1
          return FinalizeResolution(env, resolved.FromJust(), base);
1102
        }
1103
      }
1104
      auto invalid = target_arr->Get(context, length - 1).ToLocalChecked();
1105
      if (!invalid->IsString()) {
1106
        ThrowExportsInvalid(env, pkg_subpath, invalid, pjson_url, base);
1107
        return Nothing<URL>();
1108
      }
1109
      Utf8Value invalid_utf8(isolate, invalid.As<v8::String>());
1110
      std::string invalid_str(*invalid_utf8, invalid_utf8.length());
1111
      Maybe<URL> resolved = ResolveExportsTarget(env, invalid_str, subpath,
1112
                                                 pkg_subpath, pjson_url, base);
1113
      CHECK(resolved.IsNothing());
1114
      return Nothing<URL>();
1115
    } else {
1116
      ThrowExportsInvalid(env, pkg_subpath, target, pjson_url, base);
1117
      return Nothing<URL>();
1118
7
    }
1119
  }
1120
1121
1
  ThrowExportsNotFound(env, pkg_subpath, pjson_url, base);
1122
1
  return Nothing<URL>();
1123
}
1124
1125
36
Maybe<URL> PackageResolve(Environment* env,
1126
                          const std::string& specifier,
1127
                          const URL& base) {
1128
36
  size_t sep_index = specifier.find('/');
1129
36
  bool valid_package_name = true;
1130
36
  bool scope = false;
1131
36
  if (specifier[0] == '@') {
1132
1
    scope = true;
1133

1
    if (sep_index == std::string::npos || specifier.length() == 0) {
1134
1
      valid_package_name = false;
1135
    } else {
1136
      sep_index = specifier.find('/', sep_index + 1);
1137
    }
1138
35
  } else if (specifier[0] == '.') {
1139
    valid_package_name = false;
1140
  }
1141
  std::string pkg_name = specifier.substr(0,
1142
36
      sep_index == std::string::npos ? std::string::npos : sep_index);
1143
  // Package name cannot have leading . and cannot have percent-encoding or
1144
  // separators.
1145
379
  for (size_t i = 0; i < pkg_name.length(); i++) {
1146
346
    char c = pkg_name[i];
1147

346
    if (c == '%' || c == '\\') {
1148
3
      valid_package_name = false;
1149
3
      break;
1150
    }
1151
  }
1152
36
  if (!valid_package_name) {
1153
8
    std::string msg = "Invalid package name '" + specifier +
1154
12
      "' imported from " + base.ToFilePath();
1155
4
    node::THROW_ERR_INVALID_MODULE_SPECIFIER(env, msg.c_str());
1156
4
    return Nothing<URL>();
1157
  }
1158
64
  std::string pkg_subpath;
1159

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

47
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
1378
    try_catch.ReThrow();
1379
47
  }
1380
}
1381
1382
113
void ModuleWrap::SetInitializeImportMetaObjectCallback(
1383
    const FunctionCallbackInfo<Value>& args) {
1384
113
  Environment* env = Environment::GetCurrent(args);
1385
113
  Isolate* isolate = env->isolate();
1386
1387
113
  CHECK_EQ(args.Length(), 1);
1388
226
  CHECK(args[0]->IsFunction());
1389
226
  Local<Function> import_meta_callback = args[0].As<Function>();
1390
113
  env->set_host_initialize_import_meta_object_callback(import_meta_callback);
1391
1392
  isolate->SetHostInitializeImportMetaObjectCallback(
1393
113
      HostInitializeImportMetaObjectCallback);
1394
113
}
1395
1396
422
MaybeLocal<Value> ModuleWrap::SyntheticModuleEvaluationStepsCallback(
1397
    Local<Context> context, Local<Module> module) {
1398
422
  Environment* env = Environment::GetCurrent(context);
1399
422
  Isolate* isolate = env->isolate();
1400
1401
422
  ModuleWrap* obj = GetFromModule(env, module);
1402
1403
422
  TryCatchScope try_catch(env);
1404
  Local<Function> synthetic_evaluation_steps =
1405
844
      obj->synthetic_evaluation_steps_.Get(isolate);
1406
  MaybeLocal<Value> ret = synthetic_evaluation_steps->Call(context,
1407
844
      obj->object(), 0, nullptr);
1408
422
  if (ret.IsEmpty()) {
1409
6
    CHECK(try_catch.HasCaught());
1410
  }
1411
422
  obj->synthetic_evaluation_steps_.Reset();
1412

422
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
1413
12
    CHECK(!try_catch.Message().IsEmpty());
1414
12
    CHECK(!try_catch.Exception().IsEmpty());
1415
6
    try_catch.ReThrow();
1416
6
    return MaybeLocal<Value>();
1417
  }
1418
416
  return Undefined(isolate);
1419
}
1420
1421
30985
void ModuleWrap::SetSyntheticExport(
1422
      const v8::FunctionCallbackInfo<v8::Value>& args) {
1423
30985
  Isolate* isolate = args.GetIsolate();
1424
30985
  Local<Object> that = args.This();
1425
1426
  ModuleWrap* obj;
1427
61970
  ASSIGN_OR_RETURN_UNWRAP(&obj, that);
1428
1429
30985
  CHECK(obj->synthetic_);
1430
1431
30985
  CHECK_EQ(args.Length(), 2);
1432
1433
92955
  CHECK(args[0]->IsString());
1434
61970
  Local<String> export_name = args[0].As<String>();
1435
1436
30985
  Local<Value> export_value = args[1];
1437
1438
61970
  Local<Module> module = obj->module_.Get(isolate);
1439
30985
  module->SetSyntheticModuleExport(export_name, export_value);
1440
}
1441
1442
5120
void ModuleWrap::Initialize(Local<Object> target,
1443
                            Local<Value> unused,
1444
                            Local<Context> context,
1445
                            void* priv) {
1446
5120
  Environment* env = Environment::GetCurrent(context);
1447
5120
  Isolate* isolate = env->isolate();
1448
1449
5120
  Local<FunctionTemplate> tpl = env->NewFunctionTemplate(New);
1450
10240
  tpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"));
1451
10240
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
1452
1453
5120
  env->SetProtoMethod(tpl, "link", Link);
1454
5120
  env->SetProtoMethod(tpl, "instantiate", Instantiate);
1455
5120
  env->SetProtoMethod(tpl, "evaluate", Evaluate);
1456
5120
  env->SetProtoMethod(tpl, "setExport", SetSyntheticExport);
1457
5120
  env->SetProtoMethodNoSideEffect(tpl, "getNamespace", GetNamespace);
1458
5120
  env->SetProtoMethodNoSideEffect(tpl, "getStatus", GetStatus);
1459
5120
  env->SetProtoMethodNoSideEffect(tpl, "getError", GetError);
1460
  env->SetProtoMethodNoSideEffect(tpl, "getStaticDependencySpecifiers",
1461
5120
                                  GetStaticDependencySpecifiers);
1462
1463
  target->Set(env->context(), FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"),
1464
25600
              tpl->GetFunction(context).ToLocalChecked()).Check();
1465
5120
  env->SetMethod(target, "resolve", Resolve);
1466
5120
  env->SetMethod(target, "getPackageType", GetPackageType);
1467
  env->SetMethod(target,
1468
                 "setImportModuleDynamicallyCallback",
1469
5120
                 SetImportModuleDynamicallyCallback);
1470
  env->SetMethod(target,
1471
                 "setInitializeImportMetaObjectCallback",
1472
5120
                 SetInitializeImportMetaObjectCallback);
1473
1474
#define V(name)                                                                \
1475
    target->Set(context,                                                       \
1476
      FIXED_ONE_BYTE_STRING(env->isolate(), #name),                            \
1477
      Integer::New(env->isolate(), Module::Status::name))                      \
1478
        .FromJust()
1479
20480
    V(kUninstantiated);
1480
20480
    V(kInstantiating);
1481
20480
    V(kInstantiated);
1482
20480
    V(kEvaluating);
1483
20480
    V(kEvaluated);
1484
20480
    V(kErrored);
1485
#undef V
1486
5120
}
1487
1488
}  // namespace loader
1489
}  // namespace node
1490
1491
4981
NODE_MODULE_CONTEXT_AWARE_INTERNAL(module_wrap,
1492
                                   node::loader::ModuleWrap::Initialize)