js2flowchart.js
js2flowchart là một công cụ giúp tạo ra các biểu đồ luồng SVG đẹp từ mã JavaScript.
Để bắt đầu, bạn có thể cài đặt gói từ NPM
yarn add js2flowchart
hoặc bạn có thể thử ngay tại codepen sample, hoặc chơi với bản demo bên dưới.
Demo
Kiểm tra tại đây code editor, dán mã của bạn và tải xuống tệp SVG của biểu đồ luồng!
js2flowchart làm gì?
js2flowchart lấy mã JS của bạn và trả về biểu đồ luồng SVG, hoạt động trên máy khách/máy chủ, hỗ trợ ES6.
Các tính năng chính:
- các cấp độ trừu tượng đã được xác định để chỉ hiển thị các mục nhập/xuất, tên lớp/tên hàm, sự phụ thuộc của hàm để học/giải thích mã một bước một lần.
- hỗ trợ cấp độ trừu tượng tùy chỉnh tạo cấp độ riêng của bạn
- bộ tạo bài thuyết trình để tạo danh sách các SVG để phân cấp các cấp độ trừu tượng khác nhau
- các trình sửa đổi cây luồng đã xác định để ánh xạ các API nổi tiếng như i.e. [].map, [].forEach, [].filter thành cấu trúc Vòng lặp trên sơ đồ và cách khác.
- trình sửa đổi hủy diệt để thay thế khối mã bằng một hình dạng trên sơ đồ
- hỗ trợ trình sửa đổi cây luồng tùy chỉnh tạo cấp độ riêng của bạn
- bộ lọc bỏ qua cây luồng để bỏ qua hoàn toàn một số nút mã, ví dụ như dòng đăng nhập
- nút tập trung hoặc nhánh logic mã toàn bộ để làm nổi bật phần quan trọng trên sơ đồ
- nút làm mờ hoặc nhánh logic mã toàn bộ để ẩn đi những thứ ít quan trọng hơn
- hỗ trợ các chủ đề kiểu đã xác định chọn một chủ đề bạn thích
- hỗ trợ các chủ đề tùy chỉnh tạo chủ đề riêng phù hợp với màu sắc ngữ cảnh của bạn hơn
- hỗ trợ màu sắc và kiểu tùy chỉnh cung cấp API tiện dụng để thay đổi các kiểu cụ thể mà không cần mẫu cố định
Các trường hợp sử dụng:
- giải thích/tài liệu mã của bạn bằng các biểu đồ luồng
- học mã của người khác bằng cách hiểu biết hình ảnh
- tạo các biểu đồ luồng cho bất kỳ quy trình nào được mô tả đơn giản bằng cú pháp JS hợp lệ
CLI
Bạn có thể dễ dàng tạo ra các tệp SVG từ các tệp JS cục bộ của bạn bằng cách sử dụng công cụ CLI. Cài đặt js2flowchart một cách toàn cầu bằng cách chạy:
yarn global add js2flowchart
Hoặc trong dự án bằng cách chạy:
yarn add js2flowchart –dev
Mở terminal và di chuyển đến thư mục cần thiết với tệp JS bạn muốn hiển thị hình ảnh (ví dụ: ‘./my-project/main.js’). Chạy lệnh (nếu bạn đã cài đặt toàn cầu)
js2flowchart main.js
Hoặc thêm nội dung sau vào tệp package.json của bạn:
{
"scripts": {
"js2flowchart": "js2flowchart"
}
}
Và chạy (bằng npm hoặc yarn):
yarn run js2flowchart main.js
Sau khi tập lệnh được thực thi, quan sát log Tệp SVG đã được tạo: ./js2flowchart/main.js.svg
. Tệp SVG sẽ được đặt trong thư mục mới ‘/js2flowchart’ gần tệp JS của bạn.
API và ví dụ
Bạn có thể tìm nguồn các ví dụ được giải thích ở dưới trong thư mục tài liệu.
Chỉ trong các ví dụ thư viện js2flowchart được bao gồm một cách rõ ràng, bằng cách sử dụng thẻ <script>
và được truy cập bằng biến toàn cầu từ window
để làm cho việc chạy mà không cần mẫu cố định. Nhưng hãy thoải mái sử dụng nó thông qua các mô-đun ES6 cũng, khi bạn đã cấu hình máy chủ cục bộ Babel & Webpack.
/**
* Access APIs when js2flowchart injected into HTML page
*/
const {convertCodeToFlowTree, convertFlowTreeToSvg} = window.js2flowchart;
/**
* or import from node_modules
*/
import {convertCodeToFlowTree, convertFlowTreeToSvg} from 'js2flowchart';//way 1
import * as js2flowchart from 'js2flowchart';//way 2
Mặc định
Dưới đây là một hàm mã cho trường hợp cổ điển Tìm kiếm Nhị phân
const code = `function indexSearch(list, element) {
let currentIndex,
currentElement,
minIndex = 0,
maxIndex = list.length - 1;
while (minIndex <= maxIndex) {
currentIndex = Math.floor(minIndex + maxIndex) / 2;
currentElement = list[currentIndex];
if (currentElement === element) {
return currentIndex;
}
if (currentElement < element) {
minIndex = currentIndex + 1;
}
if (currentElement > element) {
maxIndex = currentIndex - 1;
}
}
return -1;
}`;
hãy chuyển đổi thành SVG(cách đơn giản nhất):
const svg = js2flowchart.convertCodeToSvg(code);
Kết quả:
Nếu bạn cần sửa đổi hành vi mặc định, bạn có thể chia js2flowchart.convertCodeToSvg
thành hai khối xây dựng cơ bản:
- xây dựng cây luồng
-
in các hình dạng
const {convertCodeToFlowTree, convertFlowTreeToSvg} = js2flowchart;
const flowTree = convertCodeToFlowTree(code);
const svg = convertFlowTreeToSvg(flowTree);//XML string
hoặc khi bạn cần kiểm soát đầy đủ, hãy tạo các phiên bản chính thức một cách thủ công:
const {createFlowTreeBuilder, createSVGRender} = js2flowchart;
const flowTreeBuilder = createFlowTreeBuilder(),
svgRender = createSVGRender();
const flowTree = flowTreeBuilder.build(code),
shapesTree = svgRender.buildShapesTree(flowTree);
const svg = shapesTree.print();//XML string
Xem ví dụ hoạt động tại here hoặc xem toàn bộ mã nguồn của nó.
Mức độ trừu tượng được xác định
Gọi là ‘mức độ trừu tượng’ là gì? Hãy nói bạn muốn bỏ qua một số chi tiết, chẳng hạn như cho một module cụ thể, bạn chỉ quan tâm đến những gì mà module đó exports
, hoặc, những lớp nó chứa. Có danh sách các mức độ đã được xác định mà bạn có thể thực hiện điều đó. Truy cập thông qua giao diện ABSTRACTION_LEVELS
.
FUNCTION
FUNCTION_DEPENDENCIES
CLASS
IMPORT
EXPORT
Hãy xem ví dụ về việc nhập và xuất module. Dưới đây là mã của một tệp print-util.js
.
const code = `
import {format, trim} from 'formattier';
import {log} from 'logger';
const data = [];
export default print = (list) => {
list.forEach(i => {
console.log(i);
});
}
export const formatString = (str) => formatter(str);
export const MAX_STR_LENGTH = 15;
`;
chúng ta cần khởi tạo flowTreeBuilder
và gán mức độ trừu tượng cho nó.
const {
ABSTRACTION_LEVELS, createFlowTreeBuilder, convertFlowTreeToSvg
} = js2flowchart;
const flowTreeBuilder = createFlowTreeBuilder();
//you can pass one level or multiple levels
flowTreeBuilder.setAbstractionLevel([
ABSTRACTION_LEVELS.IMPORT,
ABSTRACTION_LEVELS.EXPORT
]);
const flowTree = flowTreeBuilder.build(code);
const svg = convertFlowTreeToSvg(flowTree);
Kết quả:
Xem ví dụ hoạt động tại here hoặc xem toàn bộ mã nguồn của nó.
Mức độ trừu tượng tùy chỉnh (nhãn: advanced)
Nếu bạn muốn ‘tự’ đặt mức độ? Tới cùng điểm cuối API flowTreeBuilder.setAbstractionLevel
, bạn có thể cung cấp đối tượng cấu hình. Ví dụ, xem mã của mức độ trừu tượng về phụ thuộc hàm. Xem export của nó
export const getFunctionDependenciesLevel = () => ({
defined: [TOKEN_TYPES.CALL_EXPRESSION],
custom: [
getCustomFunctionDeclaration(),
getCustomAssignmentExpression(),
getCustomVariableDeclarator()
]
});
Đây là định dạng dữ liệu bạn cần truyền:
flowTreeBuilder.setAbstractionLevel({
defined: [TOKEN_TYPES.CALL_EXPRESSION],
custom: [
getCustomFunctionDeclaration(),
getCustomAssignmentExpression(),
getCustomVariableDeclarator()
]
})
Và cái gì đằng sau getCustomAssignmentExpression
ví dụ? Có một cấu hình phân tích mã thông báo.
{
type: 'TokenType', /*see types in TOKEN_TYPES map*/
getName: (path) => {/*extract name from token*/},
ignore: (path) => {/*return true if want to omit entry*/}
body: true /* should it contain nested blocks? */
}
Xem thêm cấu hình phân tích mã thông báo từ mã nguồn (entryDefinitionsMap.js)
Trình tạo bài thuyết trình
Khi bạn học mã của người khác, việc đi qua từng mức trừu tượng khác nhau là tốt. Xem xem module xuất ra gì, chứa các hàm và lớp nào v.v. Có một phụ-module createPresentationGenerator
để tạo danh sách các SVG theo từng mức độ trừu tượng khác nhau.
Hãy xem ví dụ về mã tiếp theo:
const code = `
import {format} from './util/string';
function formatName(name) {
if (!name) return 'no-name';
return format(name);
}
class Animal {
constructor(breed) {
this.breed = breed;
}
getBreed() {
return this.breed;
}
setName(name) {
if (this.nameExist()) {
return;
}
this.name = name;
}
}
class Man extends Animal {
sayName() {
console.log('name', this.name);
}
}
export default Man;
`;
truyền nó vào
const { createPresentationGenerator } = js2flowchart;
const presentationGenerator = createPresentationGenerator(code);
const slides = presentationGenerator.buildSlides();//array of SVGs
Kết quả (một trong các slide):
Bạn có thể chuyển đổi các slide bằng các nút prev-next.
Xem ví dụ hoạt động tại here hoặc xem toàn bộ mã nguồn của nó.
Chủ đề màu đã xác định
Bạn có thể áp dụng các chủ đề khác nhau cho thể hiện svgRender
của bạn. Chỉ cần gọi ví dụ svgRender.applyLightTheme()
để áp dụng sơ đồ ánh sáng.
Dưới đây là các chủ đề màu đã được định nghĩa:
- MẶC ĐỊNH:
applyDefaultTheme
- ĐEN VÀ TRẮNG:
applyBlackAndWhiteTheme
- MỜ:
applyBlurredTheme
- ÁNH SÁNG:
applyLightTheme
Hãy xem ví dụ mã đơn giản của câu lệnh switch
từ Tài liệu Mozzila Web.
const code = `
function switchSampleFromMDN() {
const foo = 0;
switch (foo) {
case -1:
console.log('negative 1');
break;
case 0:
console.log(0);
case 1:
console.log(1);
return 1;
default:
console.log('default');
}
}
`;
và áp dụng sơ đồ để thể hiện.
const {createSVGRender, convertCodeToFlowTree} = js2flowchart;
const flowTree = convertCodeToFlowTree(code),
svgRender = createSVGRender();
//applying another theme for render
svgRender.applyLightTheme();
const svg = svgRender.buildShapesTree(flowTree).print();
Kết quả:
Xem ví dụ hoạt động tại here hoặc xem toàn bộ mã nguồn của nó.
Chủ đề màu tùy chỉnh
Tuy nhiên, nhưng nếu bạn muốn có màu sắc khác? Chắc chắn, dưới đây là một ví dụ về các màu sắc của chủ đề Ánh sáng nhưng được tạo thủ công.
svgRender.applyColorBasedTheme({
strokeColor: '#555',
defaultFillColor: '#fff',
textColor: '#333',
arrowFillColor: '#444',
rectangleFillColor: '#bbdefb',
rectangleDotFillColor: '#ede7f6',
functionFillColor: '#c8e6c9',
rootCircleFillColor: '#fff9c4',
loopFillColor: '#d1c4e9',
conditionFillColor: '#e1bee7',
destructedNodeFillColor: '#ffecb3',
classFillColor: '#b2dfdb',
debuggerFillColor: '#ffcdd2',
exportFillColor: '#b3e5fc',
throwFillColor: '#ffccbc',
tryFillColor: '#FFE082',
objectFillColor: '#d1c4e9',
callFillColor: '#dcedc8',
debugModeFillColor: '#666'
});
Kiểu tùy chỉnh
Nếu bạn cần các kiểu khác, không chỉ là màu sắc? Ở đây có svgRender.applyTheme({})
. Bạn có thể áp dụng các kiểu trên chủ đề hiện tại, ghi đè chỉ vào hành vi bạn cần. Hãy xem ví dụ về câu lệnh Return.
svgRender.applyTheme({
common: {
maxNameLength: 100
},
ReturnStatement: {
fillColor: 'red',
roundBorder: 10
}
});
Vui lòng kiểm tra định nghĩa của DefaultBaseTheme
để xem tất cả các tên hình dạng và thuộc tính có thể.
Trình chỉnh sửa cây hình dạng
Có một phụ-module để sửa đổi cây hình dạng gọi là ‘ShapesTreeEditor’. Nó cung cấp các giao diện sau:
findShape
applyShapeStyles
blur
focus
blurShapeBranch
focusShapeBranch
print
Hãy tìm hiểu cách sử dụng nó qua ví dụ. Dưới đây là mã với một số ‘devMode hooks’.
const code = `
const doStuff = (stuff) => {
if (stuff) {
if (devFlag) {
log('perf start');
doRecursion();
log('perf end');
return;
}
doRecursion();
end();
} else {
throw new Error('No stuff!');
}
return null;
};
`;
Những gì chúng ta muốn ở đây là ‘blur’ điều kiện của nhánh phát triển ‘dev’, vì nó làm xáo trộn khả năng đọc mã.
const {
convertCodeToFlowTree,
createSVGRender,
createShapesTreeEditor
} = js2flowchart;
const flowTree = convertCodeToFlowTree(code),
svgRender = createSVGRender();
shapesTree = svgRender.buildShapesTree(flowTree);
const shapesTreeEditor = createShapesTreeEditor(shapesTree);
shapesTreeEditor.blurShapeBranch(
(shape) => shape.getName() === '(devFlag)'
);
const svg = shapesTreeEditor.print();
Kết quả:
Xem ví dụ đang chạy tại here hoặc kiểm tra mã nguồn hoàn chỉnh của nó.
Bộ điều chỉnh cây luồng
Có một phần con để điều chỉnh cây luồng gọi là ‘FlowTreeModifier’ cho phép bạn áp dụng các bộ điều chỉnh được định nghĩa riêng biệt vào cây luồng hiện có của bạn. Hãy xem xét một trường hợp sử dụng đơn giản: bạn muốn thay đổi ‘tên’ (tiêu đề) trên các nút cây, ở đây chỉ cần định nghĩa bộ điều chỉnh cho điều đó. Nhưng thực tế, có một số hành vi mà chúng ta đã biết rằng chúng ta cần phải điều chỉnh cây luồng.
Hãy xem xét các bộ lặp mảng ES5 như forEach
, map
và như vậy. Chúng ta đều biết chúng hoạt động như một vòng lặp, đúng không? Hãy coi chúng như một ‘vòng lặp’ sau đó.
const code = `
function print(list) {
const newList = list.map(i => {
return i + 1;
});
newList.forEach(i => {
console.debug('iteration start');
console.log(i);
console.debug('iteration end');
});
}
`;
const {
createFlowTreeBuilder,
createFlowTreeModifier,
convertFlowTreeToSvg,
MODIFIER_PRESETS
} = js2flowchart;
const flowTreeBuilder = createFlowTreeBuilder(),
flowTree = flowTreeBuilder.build(code);
const flowTreeModifier = createFlowTreeModifier();
flowTreeModifier.setModifier(MODIFIER_PRESETS.es5ArrayIterators);
flowTreeModifier.applyToFlowTree(flowTree);
const svg = convertFlowTreeToSvg(flowTree);
Kết quả:
Như bạn có thể thấy, cả hai bộ lặp đều được xử lý như một vòng lặp. Và forEach
cũng bỏ qua hàm gọi lại chức năng.
Xem ví dụ đang chạy tại here hoặc kiểm tra mã nguồn hoàn chỉnh của nó.
Còn một bộ điều chỉnh được định nghĩa khác để phá hủy nút. Nó lấy khối bạn chỉ định và phá hủy thành một khối.
flowTreeModifier.destructNodeTree((node) => node.name.indexOf('.forEach') !== -1, 'and print list...');
Nếu bạn muốn bộ điều chỉnh tùy chỉnh, thì sao?
flowTreeModifier.registerNewModifier((node)=> node.name.includes('hello'), {
name: 'world'
});
Hiển thị gỡ lỗi
Nếu bạn muốn chọn một hình dạng để áp dụng các kiểu đặc biệt và muốn một bộ chọn id duy nhất? Chỉ cần truyền cờ debug
vào print
;
const {
convertCodeToFlowTree,
createSVGRender,
createShapesTreeEditor
} = js2flowchart;
const svgRender = createSVGRender();
const shapesTree = svgRender.buildShapesTree(convertCodeToFlowTree(code));
const shapesTreeEditor = createShapesTreeEditor(shapesTree);
shapesTreeEditor.applyShapeStyles(
shape => shape.getNodePathId() === 'NODE-ID:|THIS.NAME=N|TCCP-', {
fillColor: '#90caf9'
});
const svg = shapesTreeEditor.print({debug: true});
Kết quả:
Xem ví dụ đang chạy tại here hoặc kiểm tra mã nguồn hoàn chỉnh của nó.
Công cụ
Nhờ @LucasBadico chúng ta đã có tiện ích mở rộng Visual Studio. Kiểm tra tại it out.
Bên trong
Các giai đoạn chính:
- Lấy cây cú pháp AST từ mã code, sử dụng bộ phân tích Babylon (được phát triển bởi đội Babel)
- Chuyển đổi AST thành FlowTree, loại bỏ và kết hợp các nút (FlowTreeBuilder)
- Áp dụng các bộ điều chỉnh (FlowTreeModifier)
- Tạo đối tượng SVG dựa trên FlowTree (SVGRender)
- Áp dụng ShapesTreeEditor
- Áp dụng chủ đề (xem các chủ đề)
- In đối tượng SVG thành chuỗi XML
Các việc dự định TODO
- Hỗ trợ CLI đầy đủ
- Hỗ trợ JSX
- Hỗ trợ Flow
- Hỗ trợ TypeScript
- Hỗ trợ nhiều tệp
- Plugin Webstorm
- Tiện ích mở rộng Chrome cho công cụ phát triển
Đóng góp
Hãy thoải mái tạo một vấn đề nếu nó không hoạt động với đoạn mã của bạn (vui lòng thêm các dòng mã ‘breaking’ nếu có thể nhận biết) hoặc cho bất kỳ điều gì khác mà bạn nghĩ có thể được cải thiện. Rất đánh giá cao nếu bạn có thể tham gia và giúp đỡ với bất kỳ việc dự định nào ở trên. Cảm ơn bạn.
Phiên bản
Lần đầu bắn! Hãy thư giãn (kiểm tra số phiên bản ở trên trong biểu ngữ NPM)
Tại sao? Trong thời gian làm việc với Under-the-hood-ReactJS, tôi đã dành rất nhiều thời gian để tạo các sơ đồ. Mọi thay đổi trong mã hoặc biểu đồ luôn ảnh hưởng đến toàn bộ sơ đồ ngay lập tức, buộc bạn phải di chuyển và sắp xếp ‘mảnh vỡ’. Chỉ là công việc thủ công lặp lại…
Đối với việc hỗ trợ nhiều tệp (và các tính năng thú vị khác để đơn giản hóa việc học và tài liệu mã nguồn) hãy kiểm tra Codecrumbs project tôi đang xây dựng.
Hãy tưởng tượng một thư viện có thể lấy bất kỳ mã JS nào và tạo ra biểu đồ luồng SVG từ đó, hoạt động trên máy khách và máy chủ. Cho phép bạn dễ dàng điều chỉnh sơ đồ kiểu dáng cho ngữ cảnh của bạn hoặc trình bày logic mã của bạn từ các mức trừu tượng khác nhau. Tô sáng, phá hủy các khối hoàn chỉnh, điều chỉnh tùy chỉnh cho nhu cầu của bạn, v.v.
Cảm ơn bạn!
Thông tin tải về:
Tác giả: Bogdan-Lyashenko
Mã nguồn: https://github.com/Bogdan-Lyashenko/js-code-to-svg-flowchart
Giấy phép: MIT license
Cảm ơn bạn!