Skip to content

Latest commit

 

History

History
160 lines (93 loc) · 12.7 KB

CONTRIBUTING.md

File metadata and controls

160 lines (93 loc) · 12.7 KB

Contributing to Yarn Loom

This document outlines how to contribute to this project, as well as an overview of the project layout and structure.

Requirements

To run this project from source, you need to have the following installed:

Getting Started

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.

Testing

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.

How to Contribute

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.

Available scripts

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.

CI/CD

Every pull request and merge to the main branch has the continuous-integration-workflow.yml run against it.

Releases

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.

Automatic Release

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.

Manual Release

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.

Packaging 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}.

Project Layout

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

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 nodes
  • YarnParser.ts which contains the code that parses a Yarn file into a list of YarnNodes.

loom-editor

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

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.

Temporary files and editing specific nodes

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.

Communication between loom-extension and loom-editor

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.

Diagram of communication between extension and editor

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.