78 Commits

Author SHA1 Message Date
Bohdan Liashenko
31ca6f4a78 Update README.md 2021-09-11 13:27:58 +02:00
Bohdan Liashenko
1f9bc3a2d3 Update README.md 2021-05-02 18:07:16 +02:00
Bohdan Liashenko
aad81bedbd Update README.md 2021-05-02 18:02:51 +02:00
Bohdan Liashenko
1158c5fc1d Update README.md 2021-04-27 19:22:55 +02:00
Bohdan Liashenko
a9727b990d Update README.md 2021-04-27 19:20:40 +02:00
Bogdan Lyashenko
a9f94a2cfa chore: version bump 2021-03-23 17:51:46 +01:00
Bogdan Lyashenko
eb0b9bfc40 Merge branch 'syarig-code-parse-php-namespace' 2021-03-23 14:24:17 +01:00
Bogdan Lyashenko
b4e1a99add fix: syntax changes 2021-03-23 14:23:58 +01:00
syarig
c21d3ff504 chore: remove npm scripts for docker 2021-01-03 19:55:02 +09:00
syarig
2957d95133 feat: changed to ran server-dev in Docker environment 2021-01-03 19:50:30 +09:00
syarig
d6ce727b0c refactor: improved to use cache that parsed code 2020-12-15 23:33:56 +09:00
syarig
c18c9fadd1 refactor: parse in php namespaces 2020-12-13 23:12:50 +09:00
syarig
dce33716d9 refactor: change public function names in namespaces 2020-12-13 00:49:59 +09:00
syarig
cf8ba61943 chore: remove example project code in src-php 2020-12-12 23:29:49 +09:00
syarig
26383aa79d feat: change behavior for dependency direct only 2020-12-12 12:53:32 +09:00
syarig
136bd77d5f feat: add namespaces, parser for php in code parse 2020-12-11 01:26:13 +09:00
syarig
ba6620f040 feat: add code parse php namespace 2020-12-07 23:09:15 +09:00
Bohdan Liashenko
4a8e7b7dc8 Update README.md 2020-05-23 18:50:38 +02:00
Bogdan Lyashenko
6ca48eb537 fix: build 2019-08-17 11:53:52 +02:00
Bogdan Lyashenko
2864a098ab 1.7.3 2019-08-17 11:52:57 +02:00
Bogdan Lyashenko
fec0cceba6 fix: docs 2019-08-17 11:47:34 +02:00
Bogdan Lyashenko
3bf39ce1b0 fix: readme change 2019-08-17 11:43:46 +02:00
Bogdan Lyashenko
3a047b5bbe chore: clean up 2019-08-17 11:39:39 +02:00
Bogdan Lyashenko
50145d4d1a 1.7.2 2019-08-12 20:55:38 +02:00
Bogdan Lyashenko
4df2e8a48b fix: saga 2019-08-12 20:55:31 +02:00
Bogdan Lyashenko
3dae451776 feat: hide source tree 2019-08-12 20:53:44 +02:00
Bogdan Lyashenko
4d038f37b3 feat: add file path to code preview 2019-08-12 19:49:45 +02:00
Bogdan Lyashenko
a09ef4df65 feat: add file path to code preview 2019-08-12 19:46:46 +02:00
Bogdan Lyashenko
628862d024 fix: underlay styles for namespace title 2019-08-10 20:29:53 +02:00
Bogdan Lyashenko
af83be1fcc 1.7.1 2019-08-10 20:17:33 +02:00
Bogdan Lyashenko
05cb5527e3 fix: peformance for flow steps 2019-08-10 20:17:21 +02:00
Bogdan Lyashenko
7d910a0f75 1.7.0 2019-08-06 20:31:37 +02:00
Bogdan Lyashenko
ab74f6426e 1.6.18 2019-08-06 20:26:39 +02:00
Bogdan Lyashenko
390bb8ff67 fix: left margin for svg 2019-08-06 20:26:30 +02:00
Bogdan Lyashenko
fcd108f9e7 fix: readme 2019-08-06 20:10:33 +02:00
Bogdan Lyashenko
dd2c6ee3d2 1.6.17 2019-08-06 20:08:17 +02:00
Bogdan Lyashenko
9917425cc8 fix: config file support 2019-08-06 20:07:45 +02:00
Bohdan Liashenko
3f54ca11a1 Merge pull request #85 from idoo/feature/config
WIP: feat: added codecrumbs.config
2019-08-06 19:05:41 +02:00
Bohdan Liashenko
e059f800d6 Merge branch 'master' into feature/config 2019-08-06 19:04:40 +02:00
Bogdan Lyashenko
f2dec10c05 feat: add extra persist list 2019-08-06 18:57:37 +02:00
Ivan Verevkin
d8117eac7d feat: added codecrumbs.config 2019-08-06 15:26:09 +02:00
Ivan Verevkin
354514818c feat: added codecrumbs.config 2019-08-06 13:48:29 +02:00
Ivan Verevkin
4ac814be93 feat: added codecrumbs.config 2019-08-06 12:20:52 +02:00
Ivan Verevkin
2f7387a67f feat: added codecrumbs.config 2019-08-06 11:59:06 +02:00
Bogdan Lyashenko
1cf779c5a6 test: test 2019-08-04 12:43:03 +02:00
Bogdan Lyashenko
64c9a75d92 test: test 2019-08-04 12:37:05 +02:00
Bogdan Lyashenko
5a8c4e6a9b 1.6.16 2019-08-04 12:20:57 +02:00
Bogdan Lyashenko
2fd728b5e8 feat: add tree diagram content id 2019-08-04 12:20:51 +02:00
Bogdan Lyashenko
9bda1672d5 1.6.15 2019-08-03 21:15:48 +02:00
Bogdan Lyashenko
101eade38f feat: v update info 2019-08-03 21:15:41 +02:00
Bogdan Lyashenko
6a1c8bcd75 1.6.14 2019-08-03 20:36:43 +02:00
Bogdan Lyashenko
c49a09e721 feat: add debug mode flag 2019-08-03 20:36:35 +02:00
Bogdan Lyashenko
d526ded04b chore: add hint about cc group 2019-08-03 19:36:01 +02:00
Ivan Verevkin
06344bee72 feat: added codecrumbs.config 2019-08-02 18:18:08 +02:00
Bogdan Lyashenko
f9f67ff9ea 1.6.13 2019-08-01 20:16:49 +02:00
Bogdan Lyashenko
9e519166d5 fix: flow without steps 2019-08-01 20:16:43 +02:00
Bogdan Lyashenko
1b649bbe96 1.6.12 2019-08-01 19:50:40 +02:00
Bogdan Lyashenko
9ed305c08b fix: unique keys for react lists 2019-08-01 19:50:32 +02:00
Bogdan Lyashenko
dfebfa20a2 fix: layout calc 2019-08-01 19:11:11 +02:00
Bogdan Lyashenko
564c81362e fix: geometry calc 2019-07-30 21:16:40 +02:00
Bogdan Lyashenko
d938ea3ef1 1.6.11 2019-07-28 11:23:57 +02:00
Bogdan Lyashenko
beceb476d9 feat: extend store 2019-07-28 11:23:21 +02:00
Bogdan Lyashenko
ca882e4568 1.6.10 2019-07-27 20:04:13 +02:00
Bogdan Lyashenko
227c626c3a fix: layout 2019-07-27 20:03:38 +02:00
Bogdan Lyashenko
c3606e3c3e fix: border for single space 2019-07-27 19:22:36 +02:00
Bogdan Lyashenko
ae9ffccf65 chore: js2flowchart update 2019-07-27 10:44:09 +02:00
Ivan Verevkin
897dcb8c3b feat: added codecrumbs.config 2019-07-26 14:18:51 +02:00
Bogdan Lyashenko
38e1fdeeda 1.6.9 2019-07-25 20:08:15 +02:00
Bogdan Lyashenko
c94e587675 fix: padding for geometry 2019-07-25 20:07:10 +02:00
Bohdan Liashenko
5354dad9fe Merge pull request #80 from idoo/chore/refactor-codecrumbs
chore: import only getCrumbs
2019-07-25 20:02:29 +02:00
Bohdan Liashenko
cbbab432e4 Merge pull request #81 from idoo/chore/upgrade-madge
chore: upgraded madge
2019-07-25 19:58:05 +02:00
Bogdan Lyashenko
e21ab82729 1.6.8 2019-07-25 19:37:38 +02:00
Bogdan Lyashenko
987a98732a fix: downgrade http-server to v0.9.0 2019-07-25 19:36:41 +02:00
Ivan Verevkin
3ddfda80ed chore: upgraded madge 2019-07-23 17:29:03 +02:00
Ivan Verevkin
3e5da523ce chore: import only getCrumbs 2019-07-23 14:00:05 +02:00
Bohdan Liashenko
6f6625d3db Merge pull request #79 from idoo/feature/lua
feat: added Lua support
2019-07-23 11:00:34 +02:00
Ivan Verevkin
e9b4331d60 Merge branch 'master' into feature/lua 2019-07-22 16:20:40 +02:00
Ivan Verevkin
b7e5b70df7 feat: added Lua support 2019-07-22 16:18:17 +02:00
67 changed files with 830 additions and 411 deletions

View File

@@ -1,4 +1,5 @@
.idea
example-project
docs
src/public/js
src/public/js
build

11
Dockerfile Normal file
View File

@@ -0,0 +1,11 @@
FROM node:14-slim
WORKDIR /usr/src/codecrumbs
COPY package*.json ./
RUN yarn install
COPY . .
EXPOSE 2018 3018

View File

@@ -18,17 +18,28 @@
<a href="#support">Support</a>
</h3>
## What
> **Have you ever got lost in a big or unknown codebase?** This tool will help you to solve that. Also, it will increase your development speed and give more knowledge about your application architecture.
>
**Have you ever got lost in a big or unknown codebase?** This tool will help you to solve that. Also, it will increase your development speed and give more knowledge about your application architecture.
> If you like this project, follow me on Twitter [@bliashenko](https://twitter.com/bliashenko) to hear about things I am building.
## Codecrumbs v2
Check out new version of this project as [standalone application](https://codecrumbs.io). Just in a few clicks you can start exploring a codebase in more efficient way, create interactive visual guides and share them with others on your own blog! See [quick guide here](https://codecrumbs.io/guides/web-app-with-github/).
<p align="center">
<a href="https://codecrumbs.io" target="_blank">
<img src="https://codecrumbs.io/external/img/common/app-ui-1.png" />
</a>
</p>
## Demo
Check out prepared example for [**standalone version running here**](https://codecrumbs.io/app).
## Codecrumbs v1
>**How it works?** You run `codecrumbs` command for a codebase, it analyzes source code and builds its visual representation. Write down a codecrumb-comment and codebase state will be reflected by visual client in browser on the fly.
>
> Check out [my talk at React-Finland](https://www.youtube.com/watch?v=S_1-1jzLxm4) for more details.
>
>-[@bliashenko](https://twitter.com/bliashenko)
## Demo
Check out the example of [**standalone version running here**](https://codecrumbs.io/#showcase=todo-react-redux).
<img src="/docs/main-ui-3.png" width="100%"/>
@@ -40,15 +51,18 @@ Check out the example of [**standalone version running here**](https://codecrumb
2) Run ```codecrumbs -d project-src-dir -e project-src-dir/index.js```. Change parameters to match your project:```-d``` is *directory with source code*, ```-e``` is *entry point file* .
3) Go to [http://localhost:2018](http://localhost:2018/#) in the browser to check it out.
### CLI
Parameter | Description | Example
--- | --- | ---
```-d```, ```--dir``` | Relative path to project source code directory | ```-d src```
```-e```, ```--entry``` | Relative path to project source entry point file (must be inside ```dir```) | ```-e src/app.js```
```-x```, ```--excludeDir``` | Relative path(or paths separated by ```,```) to directories for exclusion | ```-x src/doc,src/thirdparty```
```-i```, ```--ideCmd``` | command to open file in IDE from bash (default 'webstorm') | ```-i code```
```-p```, ```--port``` | Port for Codecrumbs client (optional, default *2018*) | ```-p 2019```
```-n```, ```--projectName``` | Project name alias (optional, default same as ```-d``` value) | ```-n my-hello-world```
### Configuration
Run codecrumbs with CLI params or specify static config file `codecrumbs.config.js` (see example [here](/example-project/codecrumbs.config.js))
CLI | Config file | Description | Example
--- | --- | --- | ---
```d``` | ```projectDir``` | Relative path to project source code directory | ```-d src```
```e``` | ```entryPoint``` | Relative path to project source entry point file (must be inside ```dir```) | ```-e src/app.js```
```x``` | ```excludeDir``` | Relative path(or paths separated by ```,```) to directories for exclusion | ```-x src/doc,src/thirdparty```
```p``` | ```clientPort``` | Port for Codecrumbs client (optional, default *2018*) | ```-p 2019```
```n``` | ```projectNameAlias``` | Project name alias (optional, default same as ```-d``` value) | ```-n my-hello-world```
```C``` | - | Path to codecrumbs.config.js (optional, by default will try to find the file in PWD) | ```-C config/codecrumbs.config.js```
```D``` | ```debugModeEnabled``` | Enable debug mode for logs (optional, default is ```false```) | ```-D```
## Features
### Breadcrumbs and trails
@@ -76,6 +90,8 @@ Example | Description | Use case
> Note: current version supports single line comments only.
> Hint: you can use trail id without step number (e.g. ```//cc:groupname#;test```) just to group breadcrumbs, you always can add step numbers later when you know the correct order.
### Multi-codebase integration
You might be interested to study connections between several codebases (sub-modules), codecrumbs supports that.
Simply start codecrumbs multiple times (once for each codebase), it all **will be synced in one picture** inside the browser tab. To control a diagram UI - select it by clicking on it.
@@ -102,12 +118,6 @@ Current version supports next programming languages:
Please file an issue to support other language you would like to have.
### Download & Upload (learn andshare your knowledge)
You can take a snapshot of application state at any point of time and share it with others. Simply download the json file of codecrumbs store (*top-right corner, "setup -> download"*). This json file can be then uploaded to codecrumbs (*top-right corner, "setup -> upload"*) to represent exactly same picture, even without having that project locally!
<img src="/docs/upload-feature-2.gif" width="100%"/>
### Dependencies
> Note: In current version only [JavaScript, TypeScript] offer this feature
@@ -125,18 +135,6 @@ UI explained:
[js2flowchart](https://github.com/Bogdan-Lyashenko/js-code-to-svg-flowchart) is used in the sidebar to draw flowchart for the selected file code.
### IDE integration
> Check ```-i``` CLI param first to configure command.
Navigate from browser to your code editor simply by clicking ```Command+click```(or ```Alt+click```) on a file or a codecrumb to open file in your IDE.
<img src="/docs/ide-integration.gif" width="100%"/>
## Case studies
The tool (codecrumbs) allows us to learn, document and explain a codebase much faster. Also, with *Download & Upload* feature it becomes super easy to collect and share your "investigation results".
The ultimate goal is to have many case studies hosting at [https://codecrumbs.io](https://codecrumbs.io/). **The library of projects "explained with codecrumbs", the place for collaborative learning**. More features around that coming soon, stay tuned.
## Support
Any support is very much appreciated! 👍 😘 ❤️
If you like this project, please, **put a :star: and tweet about it**. Thanks!
@@ -168,6 +166,4 @@ yarn && yarn start
## WIP
Next features are developing:
- **eject codecrumbs** - ability to remove all "breadcrumbs" from source code in "one click"
- **data transferring between cc trail steps**
- **VS Code extension** - some neat features right inside the code editor. Checkout [the repo here](https://github.com/Bogdan-Lyashenko/vs-code-codecrumbs).

View File

@@ -1,12 +1,17 @@
#!/usr/bin/env node
const path = require('path');
const program = require('commander');
const colors = require('colors');
const _ = require('lodash');
const showUpdatesInfo = require('./updatesInfo');
const server = require('../src/server');
showUpdatesInfo();
program
.option('-e, --entry [entryFile]', 'Specify path to entry point file. E.g. `src/app.js`')
.option('-e, --entry [entryPoint]', 'Specify path to entry point file. E.g. `src/app.js`')
.option('-d, --dir [projectDir]', 'Specify path to project source code directory. E.g. `src`', '')
.option(
'-w, --webpack [webpackConfigFile]',
@@ -20,27 +25,33 @@ program
.option('-i, --ideCmd [ideCmd]', 'IDE command to open file')
.option('-x, --excludeDir [excludeDirectories]', 'Exclude directories')
.option('-n, --projectName [projectNameAlias]', 'Project name alias')
.option('-C, --configFile [pathToConfigFile]', 'Path to codecrumbs.config.js')
.option('-D, --debugModeEnabled [debugModeEnabled]', 'Enable debug mode for logs.')
.parse(process.argv);
if (!program.entry || !program.dir) {
const pathToConfigFile = program.configFile || 'codecrumbs.config.js';
const configFileExists = server.checkIfPathExists(pathToConfigFile);
if ((!program.entry || !program.dir) && !configFileExists) {
console.log(
colors.magenta(
'Please specify `entry` and `dir` params. E.g. `codecrumbs -e src/app.js -d src`'
'Please specify `entryPoint` and `projectDir` params (e.g. `codecrumbs -e src/app.js -d src`). Or use `-C codecrumbs.config.js` instead.'
)
);
process.exit();
}
server.setup(
{
projectNameAlias: program.projectName,
entryPoint: program.entry,
projectDir: program.dir,
webpackConfigPath: program.webpack,
tsConfigPath: program.tsconfig,
clientPort: program.port,
excludeDir: program.excludeDir,
ideCmd: program.ideCmd
},
{ isDev: false }
);
const configFromFile = configFileExists ? require(path.resolve(pathToConfigFile)) : {};
const configFromCLI = {
projectNameAlias: program.projectName,
entryPoint: program.entry,
projectDir: program.dir,
webpackConfigPath: program.webpack,
tsConfigPath: program.tsconfig,
clientPort: program.port,
excludeDir: program.excludeDir,
ideCmd: program.ideCmd,
debugModeEnabled: program.debugModeEnabled
};
server.setup(_.merge(configFromCLI, configFromFile), { isDev: false });

20
cli/updatesInfo.js Normal file
View File

@@ -0,0 +1,20 @@
const colors = require('colors');
const exec = require('child_process').exec;
module.exports = () => {
try {
exec('npm outdated codecrumbs').stdout.on('data', function(data) {
const list = data
.split(' ')
.filter(v => !!v)
.map(v => v.trim());
const latestVersion = list[list.length - 2];
console.log(
colors.cyan.underline(
`There is new version of codecrumbs (${latestVersion}) available! Please update to have all latest features and improvements!`
)
);
});
} catch (e) {}
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

View File

@@ -0,0 +1,7 @@
module.exports = {
entryPoint: 'example-project/src-client/index.js',
projectDir: 'example-project/src-client',
clientPort: 1234,
projectNameAlias: 'example-project-for-client',
debugModeEnabled: true
};

View File

@@ -0,0 +1,2 @@
-- hello world program
print ("Hello World!")

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests\CommentRequest;
use App\Models\Post;
use App\Models\Comment;
use Auth;
use Validator;
class CommentController extends Controller
{
function index()
{
// index
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests\PostRequest;
use App\Models\Post;
use App\Models\Category;
use Hashids\Hashids;
use Illuminate\Support\Facades\Auth;
class PostController extends Controller
{
public function index()
{
// index
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use App\Rules\Category;
class PostRequest extends FormRequest
{
public function authorize()
{
// authorize
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
public function posts()
{
// posts
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function user()
{
// user
}
}

View File

@@ -0,0 +1,7 @@
<?php
namespace App;
use App\Http\Controllers\CommentController;
use App\Http\Controllers\PostController;
use App\Http\Requests\PostRequest;

View File

@@ -1,6 +1,6 @@
{
"name": "codecrumbs",
"version": "1.6.7",
"version": "1.8.3",
"author": "Bohdan Liashenko",
"license": "BSD-3-Clause",
"repository": {
@@ -13,11 +13,11 @@
"server:two": "node src/index.dev.js two",
"client-dev": "cd src/public && webpack --config webpack.dev.js --progress --colors --watch --env dev",
"server-dev": "nodemon src/index.dev.js",
"server:cli": "node cli/index.cli.js -e example-project/src-client/index.js -d example-project/src-client/",
"server-debug": "nodemon --inspect src/index.dev.js",
"clean": "rm -rf build",
"babel-compile-standalone": "babel src/public/js -d build --config-file ./src/public/babel.config.js --copy-files",
"webpack-compile-local": "cd src/public && webpack --config webpack.local.js --progress",
"build": "yarn clean && yarn babel-compile-standalone && yarn webpack-compile-local",
"build": "yarn clean && yarn webpack-compile-local",
"pretty": "prettier --write \"./src/public/js/**/*.js\""
},
"bin": {
@@ -35,14 +35,15 @@
"d3-flextree": "^2.1.1",
"directory-tree": "^2.1.0",
"file-saver": "^2.0.0",
"http-server": "^0.11.1",
"js2flowchart": "^1.1.7",
"http-server": "0.9.0",
"js2flowchart": "1.3.2",
"lodash": "^4.17.10",
"lodash.debounce": "^4.0.8",
"madge": "^3.3.0",
"madge": "^3.4.4",
"php-parser": "^3.0.2",
"portscanner": "^2.2.0",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-redux": "^5.0.7",
"react-syntax-highlighter": "8.0.1",
"redux": "^4.0.0",

View File

@@ -5,7 +5,8 @@ const namespaceOne = {
projectDir: `example-project/src-client`,
entryPoint: `example-project/src-client/index.js`,
webpackConfigPath: `example-project/webpack.config.js`,
clientPort: 2018
clientPort: 2018,
debugModeEnabled: true
};
const namespaceTwo = {
@@ -23,6 +24,13 @@ const namespaceTypeScriptExample = {
clientPort: 2018
};
const namespacePhpExample = {
projectNameAlias: 'php-example-server',
projectDir: `example-project/src-php`,
entryPoint: `example-project/src-php/index.php`,
clientPort: 2018
};
const namespaceDebug = {
projectNameAlias: 'debug',
projectDir: `example-project/debug`,
@@ -40,7 +48,8 @@ const namespaceLanguageTest = {
const args = process.argv.slice(2);
const namespaces = {
two: namespaceTwo,
ts: namespaceTypeScriptExample
ts: namespaceTypeScriptExample,
php: namespacePhpExample
};
const namespace = namespaces[args[0]] !== undefined ? namespaces[args[0]] : namespaceOne;
server.setup(namespace, { isDev: true });

View File

@@ -22,9 +22,7 @@ const ExplorerBar = React.lazy(() =>
import(/* webpackChunkName: "explorer-bar" */ './components/explorerBar/ExplorerBarContainer')
);
const Footer = React.lazy(() =>
import(/* webpackChunkName: "footer" */ './components/footer')
);
const Footer = React.lazy(() => import(/* webpackChunkName: "footer" */ './components/footer'));
import './App.less';

View File

@@ -11,7 +11,7 @@ const PADDING_TOP = 5;
//TODO: add select with several themes
//TODO: scrool to/highlight crumbed lines
//https://github.com/conorhastings/react-syntax-highlighter/blob/master/README.md
export default class extends React.Component {
export default class extends React.PureComponent {
fixScroll() {
const { dependenciesLines = [], crumbedLines = [], lineHeight } = this.props;
if (!this.codeRef || !this.codeRef.scrollTo) {
@@ -28,6 +28,7 @@ export default class extends React.Component {
this.codeRef.scrollTo(0, (lines[0][0] - 1) * (lineHeight || LINE_HEIGHT) + PADDING_TOP - 2);
}
componentDidUpdate(prevProps) {
// TODO: don\t do it each time (check real changes)
this.fixScroll();
}
componentDidMount() {

View File

@@ -8,8 +8,7 @@ import 'antd/es/alert/style';
import { NO_TRAIL_FLOW } from '../../../../shared-constants';
import { getCodeCrumbsUserChoice } from '../../../../core/dataBus/selectors';
import { getNamespacesList } from '../../../../core/dataBus/selectors';
import { gatherFlowStepsData } from '../../../treeDiagram/component/Tree/CodeCrumbs/helpers';
import { getSharedFlowStepsData } from '../../../../core/namespaceIntegration/selectors';
import Code from '../Code';
import './index.less';
@@ -34,7 +33,7 @@ const CrumbsTab = props => {
header={`[${typeof stepFile.step !== 'undefined' ? stepFile.step : '*'}] ${
stepFile.file.path
}`}
key={i}
key={stepFile.crumbNodeLines.join(',')}
>
<Code
language={language}
@@ -58,7 +57,6 @@ const CrumbsTab = props => {
};
const mapStateToProps = (state, props) => {
const namespacesList = getNamespacesList(state);
const { namespace } = props;
const {
@@ -69,10 +67,7 @@ const mapStateToProps = (state, props) => {
namespace
});
const { involvedNsData, sortedFlowSteps } = gatherFlowStepsData(state, {
currentSelectedCrumbedFlowKey,
namespacesList
});
const { involvedNsData, sortedFlowSteps } = getSharedFlowStepsData(state);
if (currentSelectedCrumbedFlowKey === NO_TRAIL_FLOW) {
return {

View File

@@ -12,7 +12,7 @@ import 'antd/es/icon/style';
import { VIEW_TYPES } from '../../../../../core/controlsBus/constants';
import './ViewSwitch.less';
class ViewSwitch extends React.Component {
class ViewSwitch extends React.PureComponent {
renderMenu() {
const {
name,
@@ -78,7 +78,7 @@ class ViewSwitch extends React.Component {
}
render() {
const { name, itemKey, subMenuItems, checkedState, toggleSwitch } = this.props;
const { name, itemKey, subMenuItems, checkedState, disabledState, toggleSwitch } = this.props;
return (
<div className="ViewSwitchItem">
@@ -92,6 +92,7 @@ class ViewSwitch extends React.Component {
size="small"
checked={checkedState[itemKey]}
onChange={v => toggleSwitch(itemKey, v)}
disabled={disabledState[itemKey]}
/>
</div>
</div>

View File

@@ -17,7 +17,7 @@
}
.settingContainer {
display: flex;
display: none;
flex-direction: row;
.spacer {
@@ -26,4 +26,4 @@
border-left: 1px solid #d9d9d9;
}
}
}
}

View File

@@ -1,6 +1,8 @@
.TreeDiagramsContainer {
overflow: auto;
width: 100%;
margin-top: 20px;
margin-left: 10px;
}
.MainLoader {
@@ -10,4 +12,4 @@
padding: 250px;
margin-top: 60px;
width: 100%;
}
}

View File

@@ -24,6 +24,7 @@ const TreeDiagramsContainer = ({ namespacesList, activeNamespace }) => {
);
}
// TODO: use ref for TreeDiagram container (on mount set it to store)
return (
<div className={'TreeDiagramsContainer'}>
{namespacesList.map(namespace => (

View File

@@ -13,6 +13,7 @@ export const CodeCrumbName = props => {
cover,
flow,
flowStep,
original,
selected,
onMouseOver,
onClick
@@ -73,7 +74,7 @@ export const CodeCrumbName = props => {
onClick={onClick}
className={'CodeCrumbName-flow'}
>
{flowStep}
{flowStep !== 0 ? flowStep : /#0/.test(original) ? 0 : '*'}
</text>
</React.Fragment>
)) ||

View File

@@ -35,7 +35,7 @@ const DetailsComponent = props => {
};
const ccUnderlayPaddingH = 20;
class CodeComponent extends React.Component {
class CodeComponent extends React.PureComponent {
state = {};
onMouseEnter = () => {
@@ -48,8 +48,7 @@ class CodeComponent extends React.Component {
render() {
const { position, crumbNodeLines, file, language, namespace } = this.props;
const { fileCode } = file.data;
const { fileCode, path, name } = file.data;
const { isExpanded } = this.state;
return (
@@ -63,6 +62,12 @@ class CodeComponent extends React.Component {
onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}
>
<div className={'FilePath'}>
<span>{path.replace(name, '')}</span>
<span>
<b>{name}</b>
</span>
</div>
<Suspense fallback={null}>
<Code
namespace={namespace}
@@ -101,7 +106,7 @@ const ExtraInfoSet = ({
namespace,
language
}) => {
if (!detailsEnabled && !codePreviewEnabled) return null;
if ((!detailsEnabled && !codePreviewEnabled) || !sortedFlowSteps) return null;
const crumbs = sortedFlowSteps.length ? sortedFlowSteps : flowSteps;
return (

View File

@@ -22,6 +22,12 @@
transition: height .1s;
overflow: hidden;
z-index: 1;
.FilePath {
border-bottom: 1px solid #ebedf0;
font-size: 11px;
padding: 1px 5px;
}
}
@CcCodeContainerExpandedHeight: 300px;
@@ -47,4 +53,4 @@
height: (@CcCodeContainerExpandedHeight + @ccUnderlayPaddingV);
transition: height, background-color .1s;
z-index: 2;
}
}

View File

@@ -17,6 +17,10 @@ export default props => {
selectedCcFlowEdgeNodes
} = props;
if (!involvedNsData || !involvedNsData[namespace]) {
return null;
}
const { codecrumbsLayoutMap } = involvedNsData[namespace];
const ccNamespacesKeys = Object.keys(involvedNsData || {});
@@ -27,7 +31,11 @@ export default props => {
if (!i) return null;
const fromItem = list[i - 1];
if (fromItem.namespace !== namespace && toItem.namespace !== namespace) {
if (
(fromItem.namespace !== namespace && toItem.namespace !== namespace) ||
fromItem.step === toItem.step
) {
return null;
}
@@ -38,7 +46,7 @@ export default props => {
});
const edgeBaseProps = {
key: `cc-external-edge-${fromItem.name}-${toItem.name}`,
key: `cc-external-edge-${fromItem.name}-${toItem.name}-${edgePoints[0].y}`,
sourcePosition: edgePoints[0],
targetPosition: edgePoints[1],
onClick: () => onFlowEdgeClick(fromItem, toItem, ccNamespacesKeys),

View File

@@ -7,6 +7,7 @@ import { isCodeCrumbSelected, getCcPosition } from './helpers';
const Tree = props => {
const {
sourceDiagramOn,
ccAlightPoint,
ccShiftIndexMap,
shiftToCenterPoint,
@@ -19,6 +20,10 @@ const Tree = props => {
selectedCcFlowEdgeNodes
} = props;
if (!ccShiftIndexMap) {
return null;
}
return (
<React.Fragment>
{Object.keys(codecrumbsLayoutMap).map(key => {
@@ -40,7 +45,7 @@ const Tree = props => {
).x;
return (
<React.Fragment key={`code-crumb-${node.data.path}-${key}`}>
<React.Fragment key={`code-crumb-${key}-${nX}-${nY}`}>
{!codeCrumbsMinimize &&
node.children.map((crumb, i) => {
const [_, cY] = [crumb.y, crumb.x];
@@ -55,22 +60,26 @@ const Tree = props => {
const ccParams = crumbData.params;
return (
<React.Fragment key={`code-crumb-edge-${file.path}-${crumbData.name}`}>
{!i && (
<PartEdge
sourcePosition={position}
parentName={file.name}
ccAlightPoint={crumbPosition.x}
singleCrumb={singleCrumb}
/>
)}
{!singleCrumb && (
<CodeCrumbMultiEdge
sourcePosition={position}
targetPosition={crumbPosition}
ccAlightPoint={i && firstCrumbXPoint}
/>
)}
<React.Fragment
key={`code-crumb-edge-${crumbData.name}-${crumbPosition.x}-${crumbPosition.y}`}
>
{!i &&
sourceDiagramOn && (
<PartEdge
sourcePosition={position}
parentName={file.name}
ccAlightPoint={crumbPosition.x}
singleCrumb={singleCrumb}
/>
)}
{!singleCrumb &&
sourceDiagramOn && (
<CodeCrumbMultiEdge
sourcePosition={position}
targetPosition={crumbPosition}
ccAlightPoint={i && firstCrumbXPoint}
/>
)}
<CodeCrumbName
position={crumbPosition}
loc={codeCrumbsLineNumbers ? crumbData.displayLoc : ''}
@@ -84,6 +93,7 @@ const Tree = props => {
currentSelectedCrumbedFlowKey !== NO_TRAIL_FLOW
}
flowStep={ccParams.flowStep}
original={ccParams.original}
onClick={e => onCodeCrumbSelect(e, { fileNode: file, codeCrumb: crumbData })}
/>
</React.Fragment>

View File

@@ -1,6 +1,3 @@
import { getCodeCrumbsUserChoice, getSourceLayout } from '../../../../../core/dataBus/selectors';
import { NO_TRAIL_FLOW } from '../../../../../core/constants';
export const isCodeCrumbsEqual = (cc, currentCc) =>
cc.name === currentCc.name && cc.flowStep === currentCc.flowStep;
@@ -13,100 +10,4 @@ export const isCodeCrumbSelected = (selectedCcFlowEdgeNodes, cc) => {
);
};
const stepSorter = (a, b) => a.step - b.step;
const getFlowSteps = ({
namespace,
codeCrumbedFlowsMap,
selectedCrumbedFlowKey,
codecrumbsLayoutMap
}) => {
const currentFlow = codeCrumbedFlowsMap[selectedCrumbedFlowKey] || {};
return Object.keys(currentFlow).reduce((flowSteps, filePath) => {
const steps = ((codecrumbsLayoutMap[filePath] && codecrumbsLayoutMap[filePath].children) || [])
.filter(({ data }) => data.params.flow === selectedCrumbedFlowKey)
.map(({ data, x, y }) => ({
...data,
namespace,
filePath,
step: data.params.flowStep,
flow: selectedCrumbedFlowKey,
x,
y
}));
return [...flowSteps, ...steps];
}, []);
};
const createCcShiftIndexMap = sortedFlowSteps => {
const ccMap = {};
let shiftOrderIndex = 0;
sortedFlowSteps.forEach((crumb, i, list) => {
if (!i) {
ccMap[crumb.id] = shiftOrderIndex;
return;
}
if (crumb.x < list[i - 1].x) {
shiftOrderIndex++;
}
ccMap[crumb.id] = shiftOrderIndex;
});
return ccMap;
};
export const gatherFlowStepsData = (state, { namespacesList, currentSelectedCrumbedFlowKey }) => {
const flowStepsData = namespacesList.reduce(
(acc, ns) => {
const namespaceProps = { namespace: ns };
const { selectedCrumbedFlowKey, codeCrumbedFlowsMap } = getCodeCrumbsUserChoice(
state,
namespaceProps
);
if (currentSelectedCrumbedFlowKey !== selectedCrumbedFlowKey) {
return acc;
}
const { codecrumbsLayoutMap, ccAlightPoint } = getSourceLayout(state, namespaceProps);
const flowSteps = getFlowSteps({
namespace: ns,
codeCrumbedFlowsMap,
selectedCrumbedFlowKey,
codecrumbsLayoutMap
});
return {
flowSteps,
sortedFlowSteps:
selectedCrumbedFlowKey !== NO_TRAIL_FLOW
? [...acc.sortedFlowSteps, ...flowSteps].sort(stepSorter)
: [],
involvedNsData: {
...acc.involvedNsData,
[ns]: { codecrumbsLayoutMap, ccAlightPoint }
}
};
},
{ involvedNsData: {}, flowSteps: [], sortedFlowSteps: [] }
);
return {
...flowStepsData,
ccShiftIndexMap: createCcShiftIndexMap(flowStepsData.sortedFlowSteps)
};
};
export const getCcPosition = (x, index = 0) => x + 70 * index;
export const getMaxWidthForNs = (state, { namespacesList }) =>
namespacesList.reduce((maxWidth, namespace) => {
const { layoutSize } = getSourceLayout(state, { namespace });
return layoutSize && layoutSize.width > maxWidth ? layoutSize.width : maxWidth;
}, 0);

View File

@@ -18,7 +18,7 @@ import Tree from './Tree';
import FlowEdges from './FlowEdge';
const mapStateToProps = (state, props) => {
const { codeCrumbsMinimize, codeCrumbsLineNumbers } = getCheckedState(state);
const { codeCrumbsMinimize, codeCrumbsLineNumbers, sourceDiagramOn } = getCheckedState(state);
const namespacesList = getNamespacesList(state);
@@ -35,6 +35,7 @@ const mapStateToProps = (state, props) => {
});
return {
sourceDiagramOn,
codecrumbsLayoutMap,
ccAlightPoint,
filesMap,

View File

@@ -2,24 +2,20 @@ import React from 'react';
import { connect } from 'react-redux';
import { DependenciesEdge, DependenciesArrow } from '../../Edge/DepenenciesEdge';
import { FileName } from '../../../component/Node/File';
import { selectDependencyEdge } from '../../../../../core/dataBus/actions';
import {
getSourceLayout,
getSourceUserChoice,
getDependenciesUserChoice
} from '../../../../../core/dataBus/selectors';
import { getCheckedState } from '../../../../../core/controlsBus/selectors';
import { getGroupsAroundNode, checkIsEdgeSelected } from './utils';
const DependenciesTree = props => {
const {
language,
selectedNode,
filesLayoutMap,
shiftToCenterPoint,
sourceDiagramOn,
onDependencyEdgeClick,
selectedDependencyEdgeNodes
} = props;
@@ -33,28 +29,19 @@ const DependenciesTree = props => {
<React.Fragment>
{selectedNodeDependencies &&
[selectedNodeDependencies].map(({ moduleName, importedModuleNames }) => {
const moduleNode = filesLayoutMap[moduleName];
const moduleNode = filesLayoutMap[selectedNode.path];
if (!moduleNode) return null;
const { name, path } = moduleNode.data;
const [mX, mY] = [moduleNode.y, moduleNode.x];
const targetPosition = shiftToCenterPoint(mX, mY);
const sourceNodes = [];
if (!sourceDiagramOn) {
// TODO: un sync with FileName in SourceTree, duplication
sourceNodes.push(
<FileName
language={language}
key={path}
position={targetPosition}
name={name}
dependency={true}
/>
);
}
const importedNodes = importedModuleNames
.map(name => filesLayoutMap[name])
.map(moduleName => {
const key = Object.keys(selectedNode.dependencies).find(key => {
return selectedNode.dependencies[key].moduleName === moduleName
})
return filesLayoutMap[key]
})
.filter(node => !!node);
const edges = [];
@@ -72,15 +59,15 @@ const DependenciesTree = props => {
groupNodes.forEach((importedNode, i) => {
const [iX, iY] = [importedNode.y, importedNode.x];
const sourcePosition = shiftToCenterPoint(iX, iY);
const { path: importedNodePath, name } = importedNode.data;
const { path: importedNodePath } = importedNode.data;
const selected =
selectedDependencyEdgeNodes &&
checkIsEdgeSelected(selectedDependencyEdgeNodes, moduleName, importedNodePath);
checkIsEdgeSelected(selectedDependencyEdgeNodes, selectedNode.path, importedNodePath);
const edge = (
<DependenciesEdge
key={`dep-edge-${importedNodePath}`}
key={`dep-edge-${importedNodePath}-${sourcePosition.x}-${targetPosition.x}`}
anyEdgeSelected={!!selectedDependencyEdgeNodes}
selected={selected}
groupName={groupName}
@@ -89,7 +76,7 @@ const DependenciesTree = props => {
firstSourcePosition={i ? firstSourcePosition : null}
onClick={() =>
onDependencyEdgeClick({
target: moduleName,
target: selectedNode.path,
sources: [importedNodePath],
groupName
})
@@ -106,7 +93,7 @@ const DependenciesTree = props => {
const arrow = (
<DependenciesArrow
key={`dep-arrow-${importedNodePath}`}
key={`dep-arrow-${importedNodePath}-${groupName}`}
selected={arrowSelected}
groupName={groupName}
targetPosition={targetPosition}
@@ -114,18 +101,6 @@ const DependenciesTree = props => {
);
arrowSelected ? selectedEdges.push(arrow) : edges.push(arrow);
}
if (!sourceDiagramOn) {
sourceNodes.push(
<FileName
key={importedNodePath}
language={language}
position={sourcePosition}
name={name}
dependency={true}
/>
);
}
});
}
);
@@ -134,7 +109,6 @@ const DependenciesTree = props => {
<React.Fragment key={moduleName}>
{edges}
{selectedEdges}
{sourceNodes}
</React.Fragment>
);
})}
@@ -143,8 +117,6 @@ const DependenciesTree = props => {
};
const mapStateToProps = (state, props) => {
const { sourceDiagramOn } = getCheckedState(state);
const { namespace } = props;
const namespaceProps = { namespace };
const { filesLayoutMap } = getSourceLayout(state, namespaceProps);
@@ -152,7 +124,6 @@ const mapStateToProps = (state, props) => {
const { selectedDependencyEdgeNodes } = getDependenciesUserChoice(state, namespaceProps);
return {
sourceDiagramOn,
filesLayoutMap,
selectedNode,
selectedDependencyEdgeNodes

View File

@@ -60,7 +60,7 @@ const SourceTree = props => {
const edge = (
<SourceEdge
key={`source-edge-${path}`}
key={`source-edge-${path}-${sourcePosition.x}-${sourcePosition.y}`}
targetPosition={position}
sourcePosition={sourcePosition}
disabled={sourceDimFolders}
@@ -77,7 +77,13 @@ const SourceTree = props => {
(type === FILE_NODE_TYPE &&
!(dependenciesDiagramOn && selectedNode.dependencies && selectedNode.dependencies[path]))
) {
sourceDotes.push(<Dot key={`dot-${path}`} position={position} selected={selected} />);
sourceDotes.push(
<Dot
key={`dot-${path}-${position.x}-${position.y}`}
position={position}
selected={selected}
/>
);
}
let nodeBasedOnType = null;
@@ -108,7 +114,7 @@ const SourceTree = props => {
selectedNodeDependencies[path] &&
!selectedNodeDependencies[path].importedModuleNames.length
}
onNodeClick={e => onFileNodeClick(e, fileNode)}
onNodeClick={e => selectedNode !== fileNode && onFileNodeClick(e, fileNode)}
/>
);
} else if (type === DIR_NODE_TYPE) {

View File

@@ -8,18 +8,23 @@ import { UnderLayer } from './UnderLayer';
import './TreeDiagram.less';
import { buildShiftToPoint } from '../../../core/dataBus/utils/geometry';
import {
getProjectMetadata,
getSourceLayout,
getCodeCrumbsUserChoice,
getNamespacesList
} from '../../../core/dataBus/selectors';
import { getProjectMetadata, getSourceLayout } from '../../../core/dataBus/selectors';
import { getCheckedState, getValuesState } from '../../../core/controlsBus/selectors';
import { selectDependencyEdge, selectCcFlowEdge } from '../../../core/dataBus/actions';
import {
selectDependencyEdge,
selectCcFlowEdge,
saveTreeDiagramContentId
} from '../../../core/dataBus/actions';
import { setActiveNamespace } from '../../../core/namespaceIntegration/actions';
import { gatherFlowStepsData, getMaxWidthForNs } from './Tree/CodeCrumbs/helpers';
import { getSharedFlowStepsData } from '../../../core/namespaceIntegration/selectors';
class TreeDiagram extends React.PureComponent {
componentDidUpdate(prevProps) {
if (!prevProps.layoutSize && this.props.layoutSize) {
this.props.saveContentId(this.treeDiagramContent.getAttribute('id'));
}
}
class TreeDiagram extends React.Component {
render() {
// TODO: fix diagramZoom
const {
@@ -50,7 +55,7 @@ class TreeDiagram extends React.Component {
});
return (
<div className={'TreeDiagram'}>
<div className={classNames('TreeDiagram', { border: multiple })}>
{multiple ? (
<p
className={classNames('namespaceTitle', {
@@ -60,35 +65,41 @@ class TreeDiagram extends React.Component {
{projectName}
</p>
) : null}
<svg
width={maxWidth || width}
height={height}
xmlns="http://www.w3.org/2000/svg"
shapeRendering="optimizeSpeed"
<div
id={`TreeDiagram-${namespace}-content`}
className={'content'}
ref={el => (this.treeDiagramContent = el)}
>
{sourceLayoutTree && (
<React.Fragment>
<UnderLayer width={maxWidth || width} height={height} onClick={onUnderLayerClick} />
<SourceTree
namespace={namespace}
shiftToCenterPoint={shiftToCenterPoint}
areaHeight={height}
sortedFlowSteps={sortedFlowSteps}
involvedNsData={involvedNsData}
ccShiftIndexMap={ccShiftIndexMap}
/>
</React.Fragment>
)}
</svg>
{codeCrumbsDiagramOn ? (
<CodeCrumbsExtraInfo
namespace={namespace}
shiftToCenterPoint={shiftToCenterPoint}
ccShiftIndexMap={ccShiftIndexMap}
sortedFlowSteps={sortedFlowSteps}
flowSteps={flowSteps}
/>
) : null}
<svg
width={maxWidth || width}
height={height}
xmlns="http://www.w3.org/2000/svg"
shapeRendering="optimizeSpeed"
>
{sourceLayoutTree && (
<React.Fragment>
<UnderLayer width={maxWidth || width} height={height} onClick={onUnderLayerClick} />
<SourceTree
namespace={namespace}
shiftToCenterPoint={shiftToCenterPoint}
areaHeight={height}
sortedFlowSteps={sortedFlowSteps}
involvedNsData={involvedNsData}
ccShiftIndexMap={ccShiftIndexMap}
/>
</React.Fragment>
)}
</svg>
{codeCrumbsDiagramOn ? (
<CodeCrumbsExtraInfo
namespace={namespace}
shiftToCenterPoint={shiftToCenterPoint}
ccShiftIndexMap={ccShiftIndexMap}
sortedFlowSteps={sortedFlowSteps}
flowSteps={flowSteps}
/>
) : null}
</div>
</div>
);
}
@@ -105,31 +116,7 @@ const mapStateToProps = (state, props) => {
const { diagramZoom } = getValuesState(state);
const { codeCrumbsDiagramOn } = getCheckedState(state);
let extendedCcProps = {};
if (codeCrumbsDiagramOn) {
const codeCrumbsUserChoice = getCodeCrumbsUserChoice(state, {
namespace
});
const namespacesList = getNamespacesList(state);
const { flowSteps, sortedFlowSteps, involvedNsData, ccShiftIndexMap } = gatherFlowStepsData(
state,
{
currentSelectedCrumbedFlowKey: codeCrumbsUserChoice.selectedCrumbedFlowKey,
namespacesList
}
);
const maxWidth = getMaxWidthForNs(state, { namespacesList });
extendedCcProps = {
flowSteps,
sortedFlowSteps,
involvedNsData,
ccShiftIndexMap,
maxWidth
};
}
const extendedCcProps = codeCrumbsDiagramOn ? getSharedFlowStepsData(state) : {};
return {
namespace,
@@ -149,7 +136,8 @@ const mapDispatchToProps = (dispatch, props) => {
dispatch(setActiveNamespace(namespace));
dispatch(selectDependencyEdge(undefined, namespace));
dispatch(selectCcFlowEdge(undefined, namespace));
}
},
saveContentId: ref => dispatch(saveTreeDiagramContentId(ref, namespace))
};
};

View File

@@ -5,7 +5,10 @@
margin: 0;
padding: 0;
overflow-y: hidden;
border-bottom: 1px solid #ebedf0;
&.border {
border-bottom: 1px solid #ebedf0;
}
.namespaceTitle {
position: absolute;
@@ -14,6 +17,7 @@
left: 0;
z-index: 2;
border-left: 1px solid #ebedf0;
background: rgba(255,255,255,0.8);
font-size: 11px;
&.activeTreeDiagram {
@@ -22,7 +26,9 @@
}
}
svg {
display: block;
.content {
svg {
display: block;
}
}
}

View File

@@ -24,3 +24,8 @@ export const setZoom = payload => ({
type: ACTIONS.SET_ZOOM,
payload
});
export const setFullState = payload => ({
type: ACTIONS.SET_FULL_STATE,
payload
});

View File

@@ -7,8 +7,11 @@ import { getFoldersForPaths, downloadObjectAsJsonFile, uploadFileAsObject } from
import {
getTreeLayout,
getFilesForCurrentCcFlow,
getCodeCrumbsMapForCurrentCcFlow
getCodeCrumbsMapForCurrentCcFlow,
getFileNodesMap,
getCodecrumbNodesMap
} from './utils/treeLayout';
import { calculateLayoutProps } from './utils/geometry';
import { ACTIONS } from './constants';
import {
@@ -155,6 +158,7 @@ export const calcFilesTreeLayoutNodes = namespace => (dispatch, getState) => {
);
const {
sourceDiagramOn,
codeCrumbsDiagramOn,
codeCrumbsMinimize,
codeCrumbsDetails,
@@ -172,16 +176,30 @@ export const calcFilesTreeLayoutNodes = namespace => (dispatch, getState) => {
});
}
const sourceLayoutTree = getTreeLayout(sourceTree, {
includeFileChildren: codeCrumbsDiagramOn && !codeCrumbsMinimize,
extraSpaceForDetails: codeCrumbsDetails,
extraSpaceForCodePreview: codeCrumbsCodePreview,
openedFolders,
activeItemsMap,
activeCodeCrumbs
});
const filesLayoutMap = getFileNodesMap(sourceLayoutTree);
const codecrumbsLayoutMap = getCodecrumbNodesMap(filesLayoutMap);
const { ccAlightPoint, ...layoutSize } = calculateLayoutProps(sourceLayoutTree, {
sourceDiagramOn
});
return dispatch({
type: ACTIONS.UPDATE_FILES_TREE_LAYOUT_NODES,
payload: getTreeLayout(sourceTree, {
includeFileChildren: codeCrumbsDiagramOn && !codeCrumbsMinimize,
extraSpaceForDetails: codeCrumbsDetails,
extraSpaceForCodePreview: codeCrumbsCodePreview,
openedFolders,
activeItemsMap,
activeCodeCrumbs
}),
payload: {
sourceLayoutTree,
filesLayoutMap,
codecrumbsLayoutMap,
ccAlightPoint,
layoutSize
},
namespace
});
};
@@ -339,3 +357,19 @@ export const setPredefinedState = predefinedState => dispatch => {
}, 100 * i);
});
};
export const saveTreeDiagramContentId = (payload, namespace) => ({
type: ACTIONS.SAVE_TREE_DIAGRAM_CONTENT_ID,
payload,
namespace
});
export const setFullState = payload => ({
type: ACTIONS.SET_FULL_STATE,
payload
});
export const setNamespaceState = payload => ({
type: ACTIONS.SET_NAMESPACE_STATE,
payload
});

View File

@@ -1,5 +1,7 @@
export const ACTIONS = {
SET_INITIAL_SOURCE_DATA: 'DATA_BUS.SET_INITIAL_SOURCE_DATA',
SET_FULL_STATE: 'DATA_BUS.SET_FULL_STATE',
SET_NAMESPACE_STATE: 'DATA_BUS.SET_NAMESPACE_STATE',
RESET_ALL: 'DATA_BUS.RESET_ALL',
SET_CHANGED_SOURCE_DATA: 'DATA_BUS.SET_CHANGED_SOURCE_DATA',
UPDATE_FILES_TREE_LAYOUT_NODES: 'DATA_BUS.UPDATE_FILES_TREE_LAYOUT_NODES',
@@ -14,5 +16,6 @@ export const ACTIONS = {
SET_DEPENDENCIES_ENTRY_POINT: 'DATA_BUS.SET_DEPENDENCIES_ENTRY_POINT',
SELECT_DEPENDENCY_EDGE: 'DATA_BUS.SELECT_DEPENDENCY_EDGE',
SELECT_CC_FLOW_EDGE: 'DATA_BUS.SELECT_CC_FLOW_EDGE',
UPDATE_FILES: 'DATA_BUS.UPDATE_FILES'
UPDATE_FILES: 'DATA_BUS.UPDATE_FILES',
SAVE_TREE_DIAGRAM_CONTENT_ID: 'DATA_BUS.SAVE_TREE_DIAGRAM_CONTENT_ID'
};

View File

@@ -10,7 +10,7 @@ import {
updateFiles
} from './actions';
class DataBusContainer extends React.Component {
class DataBusContainer extends React.PureComponent {
componentDidMount() {
const { standalone } = this.props;

View File

@@ -1,8 +1,6 @@
import { FOLDER_OPEN_STATE } from '../constants';
import { ACTIONS } from './constants';
import { getFileNodesMap, getCodecrumbNodesMap } from './utils/treeLayout';
import { calculateLayoutProps } from './utils/geometry';
const DefaultState = {};
@@ -36,7 +34,7 @@ export const getMergeState = (state, namespace) => namespaceStateUpdate => ({
}
});
const FULL_FEATURES_LANG_LIST = ['javascript', 'typescript'];
const FULL_FEATURES_LANG_LIST = ['javascript', 'typescript', 'php'];
export default (state = DefaultState, action) => {
const namespace = action.namespace;
@@ -65,18 +63,9 @@ export default (state = DefaultState, action) => {
return mergeState(action.payload);
case ACTIONS.UPDATE_FILES_TREE_LAYOUT_NODES: {
const { payload: sourceLayoutTree } = action;
const { ccAlightPoint, ...layoutSize } = calculateLayoutProps(sourceLayoutTree);
const filesLayoutMap = getFileNodesMap(sourceLayoutTree);
const codecrumbsLayoutMap = getCodecrumbNodesMap(filesLayoutMap);
const { payload } = action;
return mergeState({
sourceLayoutTree,
layoutSize,
filesLayoutMap,
codecrumbsLayoutMap,
ccAlightPoint
...payload
});
}
@@ -161,10 +150,9 @@ export default (state = DefaultState, action) => {
const { fileNode } = action.payload;
const dependenciesEntryName = fileNode ? fileNode.path : namespaceState.dependenciesEntryName;
// do some reducerr
// do some reducer
return mergeState({
dependenciesEntryName,
selectedDependencyEdgeNodes: null
});
}
@@ -195,6 +183,22 @@ export default (state = DefaultState, action) => {
}
});
case ACTIONS.SAVE_TREE_DIAGRAM_CONTENT_ID:
return mergeState({
treeDiagramContentId: action.payload
});
case ACTIONS.SET_FULL_STATE:
return {
...state,
...action.payload
};
case ACTIONS.SET_NAMESPACE_STATE:
return mergeState({
...action.payload
});
case ACTIONS.RESET_ALL:
return DefaultState;

View File

@@ -13,6 +13,11 @@ export const getProjectMetadata = createSelector([getNamespaceState], namespaceS
return { projectName, language, platformPathSeparator, fullFeaturesSupport };
});
export const getTreeDiagramContentId = createSelector([getNamespaceState], namespaceState => {
const { treeDiagramContentId } = namespaceState;
return { id: treeDiagramContentId };
});
export const getSource = createSelector([getNamespaceState], namespaceState => {
const { sourceTree, filesMap, foldersMap } = namespaceState;

View File

@@ -1,6 +1,6 @@
import { CC_NODE_TYPE } from '../../constants';
export const calculateLayoutProps = (list, padding = 100) => {
export const calculateLayoutProps = (list, { sourceDiagramOn }) => {
if (!list) {
return {
width: 0,
@@ -35,25 +35,29 @@ export const calculateLayoutProps = (list, padding = 100) => {
minX = x;
}
if (y - ySize / 2 < minY) {
minY = y - ySize / 2;
if (y < minY) {
minY = y;
}
if (x + xSize > maxX) {
maxX = x + xSize;
}
if (y + ySize / 2 > maxY) {
maxY = y + ySize / 2;
if (y + ySize > maxY) {
maxY = y + ySize;
}
});
const yShift = Math.abs(Math.round(minY)) + 20;
const height = Math.round(Math.abs(maxY) + Math.abs(yShift)) + 5;
const width = Math.round(Math.abs(maxX + maxCcWidth) + Math.abs(minX) + 2 * 20);
return {
width: Math.round(Math.abs(maxX + maxCcWidth) + Math.abs(minX) + 2 * padding),
height: Math.round(Math.abs(maxY) + Math.abs(minY) + 2 * padding),
xShift: padding / 4,
yShift: Math.abs(Math.round(minY)) > 2 * padding ? Math.abs(Math.round(minY)) : 2 * padding,
ccAlightPoint
xShift: 5,
width,
height,
yShift,
ccAlightPoint: sourceDiagramOn ? ccAlightPoint : 50
};
};

View File

@@ -69,6 +69,8 @@ export const getTreeLayout = (
}, 0);
}
// TODO: calc properly, not 5000
// impossible to do in one loop
const LARGE_WIDTH_CC = 5000;
const widthSpace =
node.data.type !== DIR_NODE_TYPE && node.data.type !== FILE_NODE_TYPE

View File

@@ -1,6 +1,32 @@
import { ACTIONS } from './constants';
import { gatherFlowStepsData } from './utils/sharedCcFlows';
import { getCodeCrumbsUserChoice, getNamespacesList } from '../dataBus/selectors';
import { getActiveNamespace } from './selectors';
export const setActiveNamespace = payload => ({
type: ACTIONS.SET_ACTIVE_NAMESPACE,
payload
});
export const calcSharedFlowStepsData = () => (dispatch, getState) => {
const state = getState();
const namespace = getActiveNamespace(state);
const namespacesList = getNamespacesList(state);
const { selectedCrumbedFlowKey: currentSelectedCrumbedFlowKey } = getCodeCrumbsUserChoice(state, {
namespace
});
dispatch({
type: ACTIONS.CALC_SHARED_FLOW_STEPS_DATA,
payload: gatherFlowStepsData(state, {
currentSelectedCrumbedFlowKey,
namespacesList
})
});
};
export const setFullState = payload => ({
type: ACTIONS.SET_FULL_STATE,
payload
});

View File

@@ -1,4 +1,6 @@
export const ACTIONS = {
SET_ACTIVE_NAMESPACE: 'NAMESPACE_INTEGRATION.SET_ACTIVE_NAMESPACE',
CALC_SHARED_FLOW_STEPS_DATA: 'NAMESPACE_INTEGRATION.CALC_SHARED_FLOW_STEPS_DATA',
SET_FULL_STATE: 'NAMESPACE_INTEGRATION.SET_FULL_STATE',
RESET_ALL: 'NAMESPACE_INTEGRATION.RESET_ALL'
};

View File

@@ -1,7 +1,8 @@
import { ACTIONS } from './constants';
const DefaultState = {
activeNamespace: undefined
activeNamespace: undefined,
sharedFlowStepsData: null
};
export default (state = DefaultState, action) => {
@@ -12,6 +13,18 @@ export default (state = DefaultState, action) => {
activeNamespace: action.payload
};
case ACTIONS.CALC_SHARED_FLOW_STEPS_DATA:
return {
...state,
sharedFlowStepsData: action.payload
};
case ACTIONS.SET_FULL_STATE:
return {
...state,
...action.payload
};
case ACTIONS.RESET_ALL:
return DefaultState;

View File

@@ -1 +1,2 @@
export const getActiveNamespace = state => state.namespaceIntegration.activeNamespace;
export const getSharedFlowStepsData = state => state.namespaceIntegration.sharedFlowStepsData;

View File

@@ -0,0 +1,99 @@
import { getCodeCrumbsUserChoice, getSourceLayout } from '../../dataBus/selectors';
import { NO_TRAIL_FLOW } from '../../../shared-constants';
export const gatherFlowStepsData = (state, { namespacesList, currentSelectedCrumbedFlowKey }) => {
const flowStepsData = namespacesList.reduce(
(acc, ns) => {
const namespaceProps = { namespace: ns };
const { selectedCrumbedFlowKey, codeCrumbedFlowsMap } = getCodeCrumbsUserChoice(
state,
namespaceProps
);
if (currentSelectedCrumbedFlowKey !== selectedCrumbedFlowKey) {
return acc;
}
const { codecrumbsLayoutMap, ccAlightPoint } = getSourceLayout(state, namespaceProps);
const flowSteps = getFlowSteps({
namespace: ns,
codeCrumbedFlowsMap,
selectedCrumbedFlowKey,
codecrumbsLayoutMap
});
return {
flowSteps,
sortedFlowSteps:
selectedCrumbedFlowKey !== NO_TRAIL_FLOW
? [...acc.sortedFlowSteps, ...flowSteps].sort(stepSorter)
: [],
involvedNsData: {
...acc.involvedNsData,
[ns]: { codecrumbsLayoutMap, ccAlightPoint }
}
};
},
{ involvedNsData: {}, flowSteps: [], sortedFlowSteps: [] }
);
return {
...flowStepsData,
ccShiftIndexMap: createCcShiftIndexMap(flowStepsData.sortedFlowSteps),
maxWidth: getMaxWidthForNs(state, { namespacesList })
};
};
const stepSorter = (a, b) => a.step - b.step;
const getFlowSteps = ({
namespace,
codeCrumbedFlowsMap,
selectedCrumbedFlowKey,
codecrumbsLayoutMap
}) => {
const currentFlow = codeCrumbedFlowsMap[selectedCrumbedFlowKey] || {};
return Object.keys(currentFlow).reduce((flowSteps, filePath) => {
const steps = ((codecrumbsLayoutMap[filePath] && codecrumbsLayoutMap[filePath].children) || [])
.filter(({ data }) => data.params.flow === selectedCrumbedFlowKey)
.map(({ data, x, y }) => ({
...data,
namespace,
filePath,
step: data.params.flowStep,
flow: selectedCrumbedFlowKey,
x,
y
}));
return [...flowSteps, ...steps];
}, []);
};
const createCcShiftIndexMap = sortedFlowSteps => {
const ccMap = {};
let shiftOrderIndex = 0;
sortedFlowSteps.forEach((crumb, i, list) => {
if (!i) {
ccMap[crumb.id] = shiftOrderIndex;
return;
}
if (crumb.x < list[i - 1].x) {
shiftOrderIndex++;
}
ccMap[crumb.id] = shiftOrderIndex;
});
return ccMap;
};
const getMaxWidthForNs = (state, { namespacesList }) =>
namespacesList.reduce((maxWidth, namespace) => {
const { layoutSize } = getSourceLayout(state, { namespace }); // TODO: double select for getSourceLayout, use from above
return layoutSize && layoutSize.width > maxWidth ? layoutSize.width : maxWidth;
}, 0);

View File

@@ -17,7 +17,8 @@ import { ACTIONS as SWITCHES_ACTIONS, CONTROLS_KEYS } from '../controlsBus/const
import { setDisabledControl, toggleSwitch } from '../controlsBus/actions';
import { getCheckedState } from '../controlsBus/selectors';
import { setActiveNamespace } from '../namespaceIntegration/actions';
import { getActiveNamespace } from '../namespaceIntegration/selectors';
import { setActiveNamespace, calcSharedFlowStepsData } from '../namespaceIntegration/actions';
function* reactOnSwitchToggle(action) {
const namespacesList = yield select(getNamespacesList);
@@ -29,6 +30,20 @@ function* reactOnSwitchToggle(action) {
}
function* applyReactionOnSwitchToggleToNamespace({ switchKey, checked, namespace }) {
if (switchKey === CONTROLS_KEYS.SOURCE_DIAGRAM_ON) {
if (!checked) {
yield all([
put(toggleSwitch(CONTROLS_KEYS.DEPENDENCIES_DIAGRAM_ON, false)),
put(setDisabledControl(CONTROLS_KEYS.DEPENDENCIES_DIAGRAM_ON, true))
]);
} else {
yield all([
put(setDisabledControl(CONTROLS_KEYS.DEPENDENCIES_DIAGRAM_ON, false)),
reactByUpdatingFoldersState({ namespace })
]);
}
}
if (switchKey === CONTROLS_KEYS.SOURCE_KEEP_ONLY_ACTIVE_ITEMS) {
if (checked) {
yield reactByUpdatingFoldersState({ namespace });
@@ -102,14 +117,24 @@ function* applyReactionOnButtonActionToNamespace({ buttonKey, namespace }) {
}
}
function* reactOnUpdateFiles({namespace}) {
const {dependenciesShowDirectOnly} = yield select(getCheckedState)
if (dependenciesShowDirectOnly) {
yield put(setDependenciesEntryPoint(undefined, namespace))
}
}
function* reactOnToggledFolder({ namespace }) {
yield put(calcFilesTreeLayoutNodes(namespace));
}
function* reactOnSourceSet({ namespace }) {
const { dependenciesDiagramOn, codeCrumbsDiagramOn } = yield select(getCheckedState);
const activeNamespace = yield select(getActiveNamespace);
yield put(setActiveNamespace(namespace));
if (activeNamespace !== namespace) {
yield put(setActiveNamespace(namespace));
}
if (!dependenciesDiagramOn && !codeCrumbsDiagramOn) {
yield reactByUpdatingFoldersState({ namespace });
@@ -129,6 +154,13 @@ function* reactByUpdatingFoldersState({ namespace }) {
yield put(calcFilesTreeLayoutNodes(namespace));
}
function* reactByCalcSharedFlowStepsData() {
const { codeCrumbsDiagramOn } = yield select(getCheckedState);
if (codeCrumbsDiagramOn) {
yield put(calcSharedFlowStepsData());
}
}
// TODO: will work if switches per namespace as well
/*function* reactByDisablingFeatures({ payload }) {
const { fullFeaturesSupport } = yield select(state =>
@@ -147,8 +179,11 @@ function* reactOnCcFlowEdgeSelect({ payload, namespace }) {
}
}
function* reactBySettingActiveNamespace({ payload, namespace }) {
yield put(setActiveNamespace(namespace));
function* reactBySettingActiveNamespace({ namespace }) {
const activeNamespace = yield select(getActiveNamespace);
if (activeNamespace !== namespace) {
yield put(setActiveNamespace(namespace));
}
}
export default function* rootSaga() {
@@ -160,9 +195,10 @@ export default function* rootSaga() {
takeLatest(DATA_BUS_ACTIONS.SET_CHANGED_SOURCE_DATA, reactOnSourceSet),
takeLatest(DATA_BUS_ACTIONS.SET_DEPENDENCIES_ENTRY_POINT, reactByUpdatingFoldersState),
takeLatest(DATA_BUS_ACTIONS.SELECT_CODE_CRUMBED_FLOW, reactByUpdatingFoldersState),
takeLatest(DATA_BUS_ACTIONS.UPDATE_FILES, reactByUpdatingFoldersState),
takeLatest(DATA_BUS_ACTIONS.SELECT_CC_FLOW_EDGE, reactOnCcFlowEdgeSelect),
takeLatest(DATA_BUS_ACTIONS.SELECT_NODE, reactBySettingActiveNamespace),
takeLatest(DATA_BUS_ACTIONS.SELECT_CODE_CRUMB, reactBySettingActiveNamespace)
takeLatest(DATA_BUS_ACTIONS.UPDATE_FILES, reactOnUpdateFiles),
takeLatest(DATA_BUS_ACTIONS.SELECT_CODE_CRUMB, reactBySettingActiveNamespace),
takeLatest(DATA_BUS_ACTIONS.UPDATE_FILES_TREE_LAYOUT_NODES, reactByCalcSharedFlowStepsData)
]);
}

View File

@@ -12,7 +12,8 @@ module.exports = merge(common, {
openAnalyzer: false
}),
new webpack.DefinePlugin({
'process.env.LOCAL': JSON.stringify(true)
'process.env.LOCAL': JSON.stringify(true),
'process.env.DEV': JSON.stringify(true)
})
]
});

View File

@@ -4,12 +4,21 @@ const { getLanguageParsers } = require('./language');
const parseFile = (
itemPath,
projectDir,
{ parseCodeCrumbs, parseImports, parseDependencies, attachCode, language, webpackConfigPath, tsConfigPath } = {}
{
parseCodeCrumbs,
parseImports,
parseDependencies,
attachCode,
language,
webpackConfigPath,
tsConfigPath
} = {}
) => {
const { codecrumbsParser, dependenciesParser } = getLanguageParsers(language);
return Promise.all([
parseDependencies && dependenciesParser.getDependencies(itemPath, projectDir, {webpackConfigPath, tsConfigPath}),
parseDependencies &&
dependenciesParser.getDependencies(itemPath, projectDir, { webpackConfigPath, tsConfigPath }),
file.read(itemPath, 'utf8')
]).then(([dependencies, code]) => {
const item = {
@@ -37,7 +46,7 @@ const parseFile = (
item.flows = undefined;
}
}
if (parseImports) {
const importedDependencies = dependenciesParser.getImports(code, itemPath);
if (importedDependencies.length) {

View File

@@ -1,7 +1,4 @@
const { setupGetCrumbs, setupGetCommentsFromCode } = require('../default/codecrumbs');
const CPP_COMMENT_REGEX = /^([^\/\/]*)\/\/(.*)$/;
const getCrumbs = setupGetCrumbs(setupGetCommentsFromCode(CPP_COMMENT_REGEX));
const { getCrumbs } = require('../default/codecrumbs');
// replace with own implementation if needed
module.exports = {

View File

@@ -1,8 +1,4 @@
const { setupGetCrumbs, setupGetCommentsFromCode } = require('../default/codecrumbs');
const CSHARP_COMMENT_REGEX = /^([^\/\/]*)\/\/(.*)$/;
const getCrumbs = setupGetCrumbs(setupGetCommentsFromCode(CSHARP_COMMENT_REGEX));
const { getCrumbs } = require('../default/codecrumbs');
// replace with own implementation if needed
module.exports = {
getCrumbs

View File

@@ -1,7 +1,4 @@
const { setupGetCrumbs, setupGetCommentsFromCode } = require('../default/codecrumbs');
const GOLANG_COMMENT_REGEX = /^([^\/\/]*)\/\/(.*)$/
const getCrumbs = setupGetCrumbs(setupGetCommentsFromCode(GOLANG_COMMENT_REGEX));
const { getCrumbs } = require('../default/codecrumbs');
// replace with own implementation if needed
module.exports = {

View File

@@ -11,6 +11,7 @@ const LANGUAGES = [
'java',
'javascript',
'kotlin',
'lua',
'ocaml',
'perl',
'php',

View File

@@ -1,7 +1,4 @@
const { setupGetCrumbs, setupGetCommentsFromCode } = require('../default/codecrumbs');
const JAVA_COMMENT_REGEX = /^([^\/\/]*)\/\/(.*)$/;
const getCrumbs = setupGetCrumbs(setupGetCommentsFromCode(JAVA_COMMENT_REGEX));
const { getCrumbs } = require('../default/codecrumbs');
// replace with own implementation if needed
module.exports = {

View File

@@ -23,11 +23,9 @@ const getCrumbs = (fileCode, path) => {
}
};*/
const { setupGetCrumbs, setupGetCommentsFromCode } = require('../default/codecrumbs');
const JAVA_SCRIPT_COMMENT_REGEX = /^([^\/\/]*)\/\/(.*)$/;
const getCrumbs = setupGetCrumbs(setupGetCommentsFromCode(JAVA_SCRIPT_COMMENT_REGEX));
const { getCrumbs } = require('../default/codecrumbs');
// replace with own implementation if needed
module.exports = {
getCrumbs
};

View File

@@ -1,7 +1,4 @@
const { setupGetCrumbs, setupGetCommentsFromCode } = require('../default/codecrumbs');
const KOTLIN_COMMENT_REGEX = /^([^\/\/]*)\/\/(.*)$/;
const getCrumbs = setupGetCrumbs(setupGetCommentsFromCode(KOTLIN_COMMENT_REGEX));
const { getCrumbs } = require('../default/codecrumbs');
// replace with own implementation if needed
module.exports = {

View File

@@ -0,0 +1,9 @@
const { setupGetCrumbs, setupGetCommentsFromCode } = require('../default/codecrumbs');
const LUA_COMMENT_REGEX = /^([^--]*)--(.*)$/;
const getCrumbs = setupGetCrumbs(setupGetCommentsFromCode(LUA_COMMENT_REGEX));
// replace with own implementation if needed
module.exports = {
getCrumbs
};

View File

@@ -0,0 +1,7 @@
const defaultDependencies = require('../default/dependencies');
// replace with own implementation if needed
module.exports = {
getImports: defaultDependencies.getImports,
getDependencies: defaultDependencies.getDependencies
};

View File

@@ -0,0 +1 @@
module.exports = /\.(lua|luac)$/;

View File

@@ -1,7 +1,4 @@
const { setupGetCrumbs, setupGetCommentsFromCode } = require('../default/codecrumbs');
const PHP_COMMENT_REGEX = /^([^\/\/]*)\/\/(.*)$/;
const getCrumbs = setupGetCrumbs(setupGetCommentsFromCode(PHP_COMMENT_REGEX));
const { getCrumbs } = require('../default/codecrumbs');
// replace with own implementation if needed
module.exports = {

View File

@@ -1,7 +1,70 @@
const defaultDependencies = require('../default/dependencies');
const path = require('path');
const namespaces = require('./namespaces');
const parser = require('./parser');
const getDependencies = async (entryPoint, projectDir) => {
const phpNamespaces = await namespaces.parse(projectDir);
const dependencies = {
[entryPoint]: phpNamespaces[entryPoint]
};
if (phpNamespaces[entryPoint]) {
phpNamespaces[entryPoint].importedModuleNames.forEach(moduleName => {
Object.keys(phpNamespaces).forEach(itemPath => {
if (phpNamespaces[itemPath].moduleName !== moduleName) {
return;
}
dependencies[itemPath] = phpNamespaces[itemPath];
});
});
}
return dependencies;
};
const getImports = (fileCode, itemPath) => {
const phpNamespaces = namespaces.getCache();
const parsed = parser.parseCode(fileCode, path.basename(itemPath));
const dependencies = [];
const findSourceFile = phpNamespace => {
return Object.keys(phpNamespaces).find(key => {
return phpNamespaces[key].moduleName === phpNamespace;
});
};
(parsed.children || []).forEach(parsedChild => {
(parsedChild.children || []).forEach(c => {
if (c.kind !== 'usegroup') {
return;
}
const dependence = {
importNodeLines: [c.loc.start.line, c.loc.end.line],
sourceFile: null,
specifiers: []
};
c.items.forEach(item => {
dependence.sourceFile = findSourceFile(item.name);
const importSpecifierName =
dependence && dependence.sourceFile && dependence.sourceFile.split('/').pop();
if (importSpecifierName) {
dependence.specifiers.push({
type: 'ImportSpecifier',
name: importSpecifierName
});
}
});
dependencies.push(dependence);
});
});
return dependencies.filter(({ sourceFile }) => !!sourceFile);
};
// replace with own implementation if needed
module.exports = {
getImports: defaultDependencies.getImports,
getDependencies: defaultDependencies.getDependencies
getImports: getImports,
getDependencies: getDependencies
};

View File

@@ -0,0 +1,54 @@
const readdirRecursive = require('fs-readdir-recursive');
const file = require('../../../utils/file');
const extensions = require('./extensions');
const path = require('path');
const parser = require('./parser');
let cache = {};
const addNamespaces = (namespaces, itemPath, parsed) =>
(parsed.children || []).filter(parsedChild => parsedChild.name).forEach(parsedChild => {
const namespace = {
moduleName: parsedChild.name,
importedModuleNames: []
};
(parsedChild.children || []).forEach(c => {
switch (c.kind) {
case 'usegroup':
c.items.forEach(item => {
namespace.importedModuleNames.push(item.name);
});
break;
case 'class':
case 'trait':
case 'interface':
namespace.moduleName = `${parsedChild.name}\\${c.name.name}`;
}
});
namespaces[itemPath] = namespace;
});
const parse = async projectDir => {
const namespaces = {};
const tasks = readdirRecursive(projectDir)
.filter(f => extensions.test('.' + f.split('.').pop()))
.map(async f => {
const separator = path.sep;
const itemPath = `${projectDir}${separator}${f.replace(/\//g, separator)}`;
const fileCode = await file.read(itemPath, 'utf8');
addNamespaces(namespaces, itemPath, parser.parseCode(fileCode, path.basename(f)));
});
await Promise.all(tasks);
cache = namespaces;
return namespaces;
};
const getCache = () => cache;
module.exports = {
parse,
getCache
};

View File

@@ -0,0 +1,12 @@
const Engine = require('php-parser');
const parser = new Engine({
parser: {
extractDoc: true,
php7: true
},
ast: {
withPositions: true
}
});
module.exports = parser

View File

@@ -1,7 +1,4 @@
const { setupGetCrumbs, setupGetCommentsFromCode } = require('../default/codecrumbs');
const TYPE_SCRIPT_COMMENT_REGEX = /^([^\/\/]*)\/\/(.*)$/;
const getCrumbs = setupGetCrumbs(setupGetCommentsFromCode(TYPE_SCRIPT_COMMENT_REGEX));
const { getCrumbs } = require('../default/codecrumbs');
// replace with own implementation if needed
module.exports = {

View File

@@ -10,9 +10,6 @@ const mediator = require('./mediator');
const sourceWatcher = require('./source-watcher');
const setup = (options, devOptions) => {
logger.fun(`>\n> Codecrumbs magic begins!\n>`);
logger.info(`> started with options: ${JSON.stringify(options)}`);
const {
projectNameAlias,
projectDir,
@@ -21,11 +18,17 @@ const setup = (options, devOptions) => {
tsConfigPath,
clientPort,
excludeDir,
ideCmd
ideCmd,
debugModeEnabled
} = options;
logger.setDebugModeEnabled(debugModeEnabled);
logger.fun(`>\n> Codecrumbs magic begins!\n>`);
logger.info(`> started with options: ${JSON.stringify(options)}`);
const PORT_IN_USE = 'open';
const HOST = '127.0.0.1';
const HOST = '0.0.0.0';
validateProjectPath(projectDir, entryPoint);
@@ -94,11 +97,11 @@ const alignPlatformPath = (p = '') =>
const validateProjectPath = (pDir, ePoint) => {
const paths = [];
if (!fs.existsSync(alignPlatformPath(pDir))) {
if (!checkIfPathExists(pDir)) {
paths.push(pDir);
}
if (!fs.existsSync(alignPlatformPath(ePoint))) {
if (!checkIfPathExists(ePoint)) {
paths.push(ePoint);
}
@@ -110,6 +113,9 @@ const validateProjectPath = (pDir, ePoint) => {
}
};
const checkIfPathExists = path => fs.existsSync(alignPlatformPath(path));
module.exports = {
checkIfPathExists,
setup
};

View File

@@ -1,6 +1,7 @@
const chalk = require('chalk');
const logAdapter = msg => console.log(msg);
let isDebugModeEnabled = false;
const logAdapter = (msg, force) => (isDebugModeEnabled || force) && console.log(msg);
module.exports = {
getText: e => {
@@ -13,6 +14,7 @@ module.exports = {
log: (...args) => logAdapter(chalk.blue.apply(chalk, args)),
info: (...args) => logAdapter(chalk.green.apply(chalk, args)),
warn: (...args) => logAdapter(chalk.yellow.apply(chalk, args)),
error: (...args) => logAdapter(chalk.red.apply(chalk, args)),
fun: (...args) => logAdapter(chalk.keyword('purple').apply(chalk, args))
error: (...args) => logAdapter(chalk.red.apply(chalk, args), true),
fun: (...args) => logAdapter(chalk.keyword('purple').apply(chalk, args), true),
setDebugModeEnabled: (debugModeEnabled) => isDebugModeEnabled = debugModeEnabled
};