• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const common = require('../common');
4const ArrayStream = require('../common/arraystream');
5const fixtures = require('../common/fixtures');
6const assert = require('assert');
7const { builtinModules } = require('module');
8const publicModules = builtinModules.filter(
9  (lib) => !lib.startsWith('_') && !lib.includes('/'),
10);
11
12if (!common.isMainThread)
13  common.skip('process.chdir is not available in Workers');
14
15// We have to change the directory to ../fixtures before requiring repl
16// in order to make the tests for completion of node_modules work properly
17// since repl modifies module.paths.
18process.chdir(fixtures.fixturesDir);
19
20const repl = require('repl');
21
22const putIn = new ArrayStream();
23const testMe = repl.start({
24  prompt: '',
25  input: putIn,
26  output: process.stdout,
27  allowBlockingCompletions: true
28});
29
30// Some errors are passed to the domain, but do not callback
31testMe._domain.on('error', assert.ifError);
32
33// Tab complete provides built in libs for import()
34testMe.complete('import(\'', common.mustCall((error, data) => {
35  assert.strictEqual(error, null);
36  publicModules.forEach((lib) => {
37    assert(
38      data[0].includes(lib) && data[0].includes(`node:${lib}`),
39      `${lib} not found`,
40    );
41  });
42  const newModule = 'foobar';
43  assert(!builtinModules.includes(newModule));
44  repl.builtinModules.push(newModule);
45  testMe.complete('import(\'', common.mustCall((_, [modules]) => {
46    assert.strictEqual(data[0].length + 1, modules.length);
47    assert(modules.includes(newModule) &&
48      !modules.includes(`node:${newModule}`));
49  }));
50}));
51
52testMe.complete("import\t( 'n", common.mustCall((error, data) => {
53  assert.strictEqual(error, null);
54  assert.strictEqual(data.length, 2);
55  assert.strictEqual(data[1], 'n');
56  const completions = data[0];
57  // import(...) completions include `node:` URL modules:
58  publicModules.forEach((lib, index) =>
59    assert.strictEqual(completions[index], `node:${lib}`));
60  assert.strictEqual(completions[publicModules.length], '');
61  // There is only one Node.js module that starts with n:
62  assert.strictEqual(completions[publicModules.length + 1], 'net');
63  assert.strictEqual(completions[publicModules.length + 2], '');
64  // It's possible to pick up non-core modules too
65  completions.slice(publicModules.length + 3).forEach((completion) => {
66    assert.match(completion, /^n/);
67  });
68}));
69
70{
71  const expected = ['@nodejsscope', '@nodejsscope/'];
72  // Import calls should handle all types of quotation marks.
73  for (const quotationMark of ["'", '"', '`']) {
74    putIn.run(['.clear']);
75    testMe.complete('import(`@nodejs', common.mustCall((err, data) => {
76      assert.strictEqual(err, null);
77      assert.deepStrictEqual(data, [expected, '@nodejs']);
78    }));
79
80    putIn.run(['.clear']);
81    // Completions should not be greedy in case the quotation ends.
82    const input = `import(${quotationMark}@nodejsscope${quotationMark}`;
83    testMe.complete(input, common.mustCall((err, data) => {
84      assert.strictEqual(err, null);
85      assert.deepStrictEqual(data, [[], undefined]);
86    }));
87  }
88}
89
90{
91  putIn.run(['.clear']);
92  // Completions should find modules and handle whitespace after the opening
93  // bracket.
94  testMe.complete('import \t("no_ind', common.mustCall((err, data) => {
95    assert.strictEqual(err, null);
96    assert.deepStrictEqual(data, [['no_index', 'no_index/'], 'no_ind']);
97  }));
98}
99
100// Test tab completion for import() relative to the current directory
101{
102  putIn.run(['.clear']);
103
104  const cwd = process.cwd();
105  process.chdir(__dirname);
106
107  ['import(\'.', 'import(".'].forEach((input) => {
108    testMe.complete(input, common.mustCall((err, data) => {
109      assert.strictEqual(err, null);
110      assert.strictEqual(data.length, 2);
111      assert.strictEqual(data[1], '.');
112      assert.strictEqual(data[0].length, 2);
113      assert.ok(data[0].includes('./'));
114      assert.ok(data[0].includes('../'));
115    }));
116  });
117
118  ['import(\'..', 'import("..'].forEach((input) => {
119    testMe.complete(input, common.mustCall((err, data) => {
120      assert.strictEqual(err, null);
121      assert.deepStrictEqual(data, [['../'], '..']);
122    }));
123  });
124
125  ['./', './test-'].forEach((path) => {
126    [`import('${path}`, `import("${path}`].forEach((input) => {
127      testMe.complete(input, common.mustCall((err, data) => {
128        assert.strictEqual(err, null);
129        assert.strictEqual(data.length, 2);
130        assert.strictEqual(data[1], path);
131        assert.ok(data[0].includes('./test-repl-tab-complete.js'));
132      }));
133    });
134  });
135
136  ['../parallel/', '../parallel/test-'].forEach((path) => {
137    [`import('${path}`, `import("${path}`].forEach((input) => {
138      testMe.complete(input, common.mustCall((err, data) => {
139        assert.strictEqual(err, null);
140        assert.strictEqual(data.length, 2);
141        assert.strictEqual(data[1], path);
142        assert.ok(data[0].includes('../parallel/test-repl-tab-complete.js'));
143      }));
144    });
145  });
146
147  {
148    const path = '../fixtures/repl-folder-extensions/f';
149    testMe.complete(`import('${path}`, common.mustSucceed((data) => {
150      assert.strictEqual(data.length, 2);
151      assert.strictEqual(data[1], path);
152      assert.ok(data[0].includes(
153        '../fixtures/repl-folder-extensions/foo.js/'));
154    }));
155  }
156
157  process.chdir(cwd);
158}
159