This document outlines how to contribute to this project, as well as an overview of the project layout and structure.
To run this project from source, you need to have the following installed:
Clone this repo, and then open it up in Visual Studio Code.
Install dependencies by running npm install
at the root of the project. If you run into issues (i.e. with ENOACCESS
) then try running npm install
in subdirectories first, then running it again at the root.
To run the extension in the extension development host, use Visual Studio Code's debug launcher to launch the "Extension" configuration.
Or, you can press F5 to launch it automatically.
Tests are all done using jest.
In loom-editor
, react-testing-library
is also used.
Tests are automatically run on all Pull Requests.
See Available scripts below for commands to run tests.
To contribute to this repo, fork it, make changes and open up a pull request against the main
branch.
Note: There are two nearly identical README.md
files in this repo; one at the root and one in the loom-extension
directory. The one at the root is mainly for showing on GitHub; the one in the loom-extension
directory is for the Visual Studio Code marketplace. All images in the loom-extension
's README.md
must be direct links to the image on GitHub and not a relative path, otherwise they will not properly work.
All scripts must be run at the root of the repo.
Because of the way that lerna works, most scripts cannot be run directly in sub-projects since the necessary dependencies are located in the root package.json
and are bootstrapped in the subprojects. See the Project Layout section for more information.
Command | Description |
---|---|
build build:common build:editor build:extension |
npm run build will build all sub-projects in the correct order.This is what is called when launching the extension. See launch.json .The other tasks are used to build specific sub-projects. In general, these need to be executed in a specific order for the extension to compile properly: build:common , then build:editor , then build:extension . |
test test:common test:editor test:extension |
npm test will run all tests in all sub-projects.This sets the environment variable CI=true . This is mainly because the create-react-app tests usually run in an interactive mode.To run the loom-editor tests interactively, run the following:cd loom-editor/ && ../node_modules/.bin/react-scripts test This will re-run tests for changed files in the editor in watch mode. |
package |
npm run package will build and package the extension. This just runs the package command in the loom-extension project. build must be called first. |
prettier |
npm run prettier will run Prettier on all files in the project and overwrite them if they need formatting changes. |
lint lint:common lint:editor lint:extension |
npm run lint will run eslint on all files in all sub-projects, as well as running prettier on all files in check mode (not overwriting them).This will fail if any files do not pass lint or have not been formatted with npm run prettier . |
Every pull request and merge to the main
branch has the continuous-integration-workflow.yml
run against it.
Running npm run version
in the root of the repo will ask for a new version via lerna. This will bump all of the package.json
files. This needs to be committed and pushed to the main
branch.
Creating a new release from GitHub should trigger the continuous-integration-workflow.yml
and publish the extension. The deploy key that vsce
uses to deploy the extension is stored as an encrypted secret in the repo's settings.
The steps in the Visual Studio Code "Publishing Extensions" docs should be followed to create a personal access token (PAT) in Azure Dev Ops in order to use vsce
to publish the extension.
Once logged in to the publisher via vsce
, running npm run publish
from the root of the repo will publish the current version of the extension.
To manually generate a .vsix
file, run npm run package
at the root of the repo.
Note: Sometimes, weird things can happen with lerna and node_modules
; if you run into weird issues here, try cd loom-extension && rm -rf node_modules && npm install
to clean things out and make sure you have all the dependencies needed.
This should generate a loom-extension-X.X.X.vsix
file. In general, it is a good idea to append the current Git commit to this filename. This is just a .zip
file, so if you want to upload it i.e. to GitHub to share in a comment, you can rename it to .zip
.
To install the .vsix
file, run code --install-extension {your .vsix file}
.
This project is a monorepo that is managed with lerna.
Where possible, dev dependencies are kept at the root level of the project.
All code is written in TypeScript.
There are three main components to this project...
loom-common
contains common code that is shared between loom-editor
and loom-extension
.
This includes:
EditorActions.ts
which is used to communicate between the editor and the extension (see the section on communication below)YarnNode.ts
which contains type definitions and some utility functions for parsing/generating Yarn nodesYarnParser.ts
which contains the code that parses a Yarn file into a list ofYarnNode
s.
loom-editor
is a React single-page app (SPA) created using create-react-app.
It uses react-d3-graph for node rendering and emotion for its styling.
It is worth noting that, while this is a React SPA, it can only be run within the context of the extension. Without the extension host, the SPA is essentially useless.
Icons come from the microsoft/vscode-codicons
repo, which is where the icons for Visual Studio Code come form.
loom-extension
contains the extension host code that Visual Studio Code runs when the extension is activated.
This is done using a webview with the custom editor API.
Basically, when you open a .yarn
file, the extension opens up a sandboxed Google Chrome window and loads the loom-editor
into it. Most of the config for this lives in the [extension's package.json](./loom-extension/package.json). It contributes a custom editor that activates when
.yarnor
.yarn.txt` files are opened.
extension.ts
is called when the extension activates and it registers a LoomEditorProvider
which uses the LoomWebviewPanel
to render the loom-editor
.
Currently, Visual Studio Code does not have a way for extensions to open up ephemeral files to be edited; as such, when opening a Yarn node, the extension host will actually write a file out to disc representing the Yarn node.
It does this in the node.js provided os.tmpdir()
, suffixed with a hashed string representing the node's location within the project structure.
After writing the file, it starts a node.js file watcher on it; whenever the file changes, updates are sent back to the extension and then subsequently back to the editor. It then opens the file in Visual Studio Code. This ends up working surprisingly well.
The extension tries its best to keep track of temporary files that it creates and delete them when the .yarn
file or the Visual Studio Code window is closed.
See TemporaryFiles.ts
for more information.
It's helpful to think of loom-extension
as the server and loom-editor
as the client. The extension has a representation of the currently open file open and the editor sends events to it to update specific nodes.
In the webview, window.vsCodeApi
is created by calling acquireVsCodeApi();
in LoomWebviewPanel
. This is basically hacked into the <head>
tag of the document.
The "Backing TextDocument
" is the actual .yarn
file that is currently being edited. When nodes are changed/added/removed, the LoomEditorProvider
is smart enough to know which exact lines to change in the text document for the node. This allows for native undo/redo for all changes that are applied to the document itself.
All messages being sent via window.vsCodeApi.postMessage
from the editor to the extension and all messages being sent via webview.postMessage
from the extension back to the editor defined in loom-common
as EditorActions
. This ensures type safety in all messages being sent back and forth.