Skip to content

Commit abb781a

Browse files
refactor: replace module-deps-sortable on own implementation to control how parse files
BREAKING CHANGE: all Extensions whould contains '.' so that mean if you have just 'ts' then need to convert to '.ts'
1 parent e3c59d7 commit abb781a

File tree

8 files changed

+331
-353
lines changed

8 files changed

+331
-353
lines changed

__tests__/lib/input/dependency.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ test('dependency', async function () {
2323
});
2424
{
2525
const dependencies = await dependency([paths['index.js']], {
26-
parseExtension: ['js']
26+
parseExtension: ['.js']
2727
});
2828
expect(dependencies.length).toEqual(1);
2929
}
3030
{
3131
const dependencies = await dependency([paths['requires.js']], {
32-
parseExtension: ['js']
32+
parseExtension: ['.js']
3333
});
3434
expect(dependencies.length).toEqual(2);
3535
}

docs/NODE_API.md

+1-6
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,9 @@ Formats documentation as HTML.
126126

127127
```javascript
128128
var documentation = require('documentation');
129-
var streamArray = require('stream-array');
130-
var vfs = require('vinyl-fs');
131129

132130
documentation.build(['index.js'])
133-
.then(documentation.formats.html)
134-
.then(output => {
135-
streamArray(output).pipe(vfs.dest('./output-directory'));
136-
});
131+
.then(documentation.formats.html);
137132
```
138133

139134
Returns **[Promise][21]<[Array][17]<[Object][19]>>** Promise with results

package-lock.json

+200-288
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
"@babel/types": "^7.14.1",
1717
"chalk": "^4.1.2",
1818
"chokidar": "^3.4.0",
19-
"concat-stream": "^2.0.0",
2019
"diff": "^5.0.0",
2120
"doctrine-temporary-fork": "2.1.0",
2221
"git-url-parse": "^11.1.2",
@@ -30,7 +29,6 @@
3029
"mdast-util-find-and-replace": "^2.1.0",
3130
"mdast-util-inject": "^1.1.0",
3231
"micromark-util-character": "^1.1.0",
33-
"module-deps-sortable": "^5.0.3",
3432
"parse-filepath": "^1.0.2",
3533
"pify": "^5.0.0",
3634
"read-pkg-up": "^9.0.0",
@@ -39,8 +37,9 @@
3937
"remark-html": "^15.0.0",
4038
"remark-reference-links": "^6.0.0",
4139
"remark-toc": "^8.0.0",
40+
"detective": "^5.2.0",
41+
"konan": "^2.1.1",
4242
"resolve": "^1.8.1",
43-
"stream-array": "^1.1.2",
4443
"strip-json-comments": "^4.0.0",
4544
"unist-builder": "^3.0.0",
4645
"unist-util-visit": "^4.1.0",
@@ -59,6 +58,7 @@
5958
"documentation-schema": "0.0.1",
6059
"eslint": "^8.0.1",
6160
"eslint-config-prettier": "^8.3.0",
61+
"concat-stream": "^2.0.0",
6262
"fs-extra": "^10.0.0",
6363
"husky": "^4.3.8",
6464
"jest": "^27.1.0",

src/config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const defaultConfig = {
22
// package.json ignored and don't get project infromation
33
'no-package': false,
44
// Extenstions which by dafault are parse
5-
parseExtension: ['mjs', 'js', 'jsx', 'es5', 'es6', 'vue', 'ts', 'tsx']
5+
parseExtension: ['.mjs', '.js', '.jsx', '.es5', '.es6', '.vue', '.ts', '.tsx']
66
};
77

88
function normalaze(config, global) {

src/input/dependency.js

+9-47
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import mdeps from 'module-deps-sortable';
2-
import path from 'path';
3-
import concat from 'concat-stream';
1+
import mdeps from './moduleDeps.js';
42
import internalOnly from '../module_filters.js';
53
import smartGlob from '../smart_glob.js';
64

75
/**
8-
* Returns a readable stream of dependencies, given an array of entry
6+
* Returns a array of dependencies, given an array of entry
97
* points and an object of options to provide to module-deps.
108
*
119
* This stream requires filesystem access, and thus isn't suitable
@@ -15,55 +13,19 @@ import smartGlob from '../smart_glob.js';
1513
* @param config optional options passed
1614
* @returns results
1715
*/
18-
export default function dependencyStream(indexes, config) {
19-
const md = mdeps({
16+
export default async function dependencyStream(
17+
indexes,
18+
{ parseExtension = [], requireExtension = [] }
19+
) {
20+
const md = await mdeps(smartGlob(indexes, parseExtension), {
2021
/**
2122
* Determine whether a module should be included in documentation
2223
* @param {string} id path to a module
2324
* @returns {boolean} true if the module should be included.
2425
*/
2526
filter: id => internalOnly(id),
26-
extensions: []
27-
.concat(config.requireExtension || [])
28-
.map(ext => '.' + ext.replace(/^\./, ''))
29-
.concat(['.mjs', '.js', '.json', '.es6', '.jsx']),
30-
resolve:
31-
config.resolve === 'node' &&
32-
((id, opts, cb) => {
33-
const r = require('resolve');
34-
opts.basedir = path.dirname(opts.filename);
35-
r(id, opts, cb);
36-
})
27+
extensions: [...parseExtension, ...requireExtension]
3728
});
38-
smartGlob(indexes, config.parseExtension).forEach(index => {
39-
md.write(path.resolve(index));
40-
});
41-
md.end();
4229

43-
return new Promise((resolve, reject) => {
44-
md.once('error', reject);
45-
md.pipe(
46-
concat(function (inputs) {
47-
resolve(
48-
inputs
49-
.filter(
50-
input =>
51-
// At this point, we may have allowed a JSON file to be caught by
52-
// module-deps, or anything else allowed by requireExtension.
53-
// otherwise module-deps would complain about
54-
// it not being found. But Babel can't parse JSON, so we filter non-JavaScript
55-
// files away.
56-
config.parseExtension.indexOf(
57-
path.extname(input.file).replace(/^\./, '')
58-
) > -1
59-
)
60-
.map(input => {
61-
// remove source file, since it's transformed anyway
62-
delete input.source;
63-
return input;
64-
})
65-
);
66-
})
67-
);
68-
});
30+
return md;
6931
}

src/input/moduleDeps.js

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import path from 'path';
2+
import util from 'util';
3+
import { readFile } from 'fs/promises';
4+
import r from 'resolve';
5+
import detective from 'detective';
6+
import konan from 'konan';
7+
8+
// const parseExst = ['.js', '.mjs', '.jsx', '.vue', '.ts', '.tsx'];
9+
const resolveExst = ['.json', '.css', '.less', '.sass'];
10+
const resolve = util.promisify(r);
11+
12+
class Deps {
13+
constructor(opts = {}) {
14+
this.fileCache = opts.fileCache || {};
15+
this.visited = {};
16+
this.res = [];
17+
18+
this.options = { ...opts };
19+
}
20+
21+
async flush(input) {
22+
const promises = input.map(file => {
23+
const dir = path.dirname(file);
24+
return this.walk(file, {
25+
basedir: dir,
26+
filename: 'root'
27+
});
28+
});
29+
await Promise.all(promises);
30+
31+
return this.res;
32+
}
33+
34+
async readFile(file) {
35+
if (this.fileCache[file]) {
36+
return this.fileCache[file];
37+
}
38+
return readFile(file, {
39+
encoding: 'utf8'
40+
});
41+
}
42+
43+
async walk(id, parent) {
44+
const extensions = this.options.extensions;
45+
const sortKey = parent.sortKey || '';
46+
let file = null;
47+
48+
try {
49+
file = await resolve(id, { ...parent, extensions });
50+
} catch (err) {
51+
if (err.code === 'MODULE_NOT_FOUND') {
52+
console.warn(`module not found: "${id}" from file ${parent.filename}`);
53+
return;
54+
}
55+
throw err;
56+
}
57+
58+
if (this.visited[file] || resolveExst.includes(path.extname(file))) {
59+
return file;
60+
}
61+
this.visited[file] = true;
62+
63+
const source = await this.readFile(file);
64+
const depsArray = this.parseDeps(file, source);
65+
if (!depsArray) {
66+
return file;
67+
}
68+
69+
const deps = {};
70+
const promises = depsArray.map(async (id, i) => {
71+
const filter = this.options.filter;
72+
if (filter && !filter(id)) {
73+
deps[id] = false;
74+
return;
75+
}
76+
const number = i.toString().padStart(8, '0');
77+
deps[id] = await this.walk(id, {
78+
filename: file,
79+
basedir: path.dirname(file),
80+
sortKey: sortKey + '!' + file + ':' + number
81+
});
82+
});
83+
84+
await Promise.all(promises);
85+
86+
this.res.push({
87+
id: file,
88+
source,
89+
deps,
90+
file,
91+
sortKey: sortKey + '!' + file
92+
});
93+
return file;
94+
}
95+
96+
parseDeps(file, src) {
97+
try {
98+
try {
99+
return konan(src).strings;
100+
} catch (ex) {
101+
// konan does not support Vue (component) file, try to parse using detective (as a fallback)
102+
return detective(src);
103+
}
104+
} catch (ex) {
105+
console.error(`Parsing file ${file}: ${ex}`);
106+
return;
107+
}
108+
}
109+
}
110+
111+
export default async function (input = [], opts = {}) {
112+
const dep = new Deps(opts);
113+
return dep.flush(Array.from(new Set(input)));
114+
}

src/output/html.js

+1-6
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,9 @@ import mergeConfig from '../merge_config.js';
1212
* @public
1313
* @example
1414
* var documentation = require('documentation');
15-
* var streamArray = require('stream-array');
16-
* var vfs = require('vinyl-fs');
1715
*
1816
* documentation.build(['index.js'])
19-
* .then(documentation.formats.html)
20-
* .then(output => {
21-
* streamArray(output).pipe(vfs.dest('./output-directory'));
22-
* });
17+
* .then(documentation.formats.html);
2318
*/
2419
export default async function html(comments, localConfig = {}) {
2520
const config = await mergeConfig(localConfig);

0 commit comments

Comments
 (0)