We can use help in a bunch of areas and any help is appreciated. Our GitHub issues serve as a place for any discussion, whether it's bug reports, questions, project direction etc. As the project grows this policy may change.
Our Discord server is open for help and more adhoc discussion. All activity on the Discord is still moderated and will be strictly enforced under the project's Code of Conduct.
Getting started with developing Rome takes three commands. You will only need Node v14 or above.
git clone https://github.com/rome/tools
cd tools
./rome --help
No dependency installation step is required as we check in our node_modules
folder that contains only a copy of TypeScript and some definitions.
Use a backslash (\
) rather than a forward slash (/
) when running commands.
For example, to run help:
.\rome --help
or you can directly use rome
without any path referencing like below:
rome --help
If files specific to your local development environment should be ignored, please add these files to a global git ignore file rather than to a git ignore file within Rome.
You can find more information on this process here.
The Rome website is built with Eleventy. To start a development server you can run the following commands:
cd website
npm install
npm start
When working on Rome you will want to run the tests and linter to validate your changes. You can do both of these with a single command:
./rome ci
This is the main command we run when you submit a PR, so running it locally and making sure it passes will make it easier to review and merge your changes.
To automatically update test snapshots, apply formatting and autofixes, add the --fix
flag.
./rome ci --fix
You can alternatively run more specific commands if you need to, but they shouldn't be necessary.
To run just the linter use:
./rome check
And to automatically apply formatting and autofixes:
./rome check --apply
If you would like to run only the test runner:
./rome test
To run specific files:
./rome test path/to/files
And to update snapshots:
./rome test --update-snapshots
To enable logging:
./rome test --no-suppress-logs
If you are adding a new lint rule, or modifying some core code, you might need to regenerate some files. We have generated files to avoid having to write a lot of boilerplate and automate common tasks.
./script generate-all-files
Or if using Windows:
.\script generate-all-files
It's strongly advised to run this command before commit new changes.
Internally, the Rome team adheres as closely as possible to the conventional commit specification. Following this convention encourages commit best-practices and facilitates commit-powered features like change log generation.
The following commit prefixes are supported:
feat:
, a new featurefix:
, a bugfixdocs:
, a documentation updatetest
, a test updatechore:
, project housekeepingperf:
, project performancerefactor:
, refactor of the code without change in functionality
Below are examples of well-formatted commits:
feat(compiler): implement parsing for new type of files
fix: fix nasty unhandled error
docs: fix link to website page
test(lint): add more cases to handle invalid rules
When creating a new pull request, it's preferable to use a conventional commit-formatted title, as this title will be used as the default commit message on the squashed commit after merging.
Here are some other scripts that you might find useful.
This is used to generate new lint rules and boilerplate.
./script lint-create-rule [category]/[ruleName]
The category
is one of the lint category folders defined in internal/compiler/lint/rules
. Some of these represent specific languages, or general themes.
The ruleName
should start with either use
or no
.
For example, to create a rule in the js
category called useCamelCase
run:
./script lint-create-rule js/useCamelCase
The created files will be listed in the console output. See those files for inline comments on what to insert. Use other lint rules as a reference.
-
Forbid a concept
no<Concept>
When a rule's sole intention is to forbid a single concept - such as disallowing the use of
debugger
statements - the rule should be named using theno
prefix. For example, the rule to disallow the use ofdebugger
statements is namednoDebugger
. -
Mandate a concept
use<Concept>
When a rule's sole intention is to mandate a single concept - such as forcing the use of camel-casing - the rule should be named using the
use
prefix. For example, the rule to mandating the use of camel-cased variable names is nameduseCamelCase
.
This is used to generate new ast nodes and boilerplate.
./script ast-create-node [language]/[category]/[nodeType]
The language
is one of the language folders defined in [https://github.com/rome/tools/tree/main/internal/ast/
]
The category
is one of the category folders inside the language
folders.
./script ast-create-node js/typescript/JSArrayType
The created files will be displayed in the console output.
This is used to generate a new prefix boilerplate
./script compiler-create-prefix [prefixName]
Prefix names with dashes are preferable.
Rome uses its own test suite to run tests. Internally, we use different way to run tests.
Most of the parsers contain a file called index.test.ts
and a folder called test-fixtures
.
We have an internal utility function called declareParserTests
. When placed inside
a index.test.ts
file and called, it will browse the files and folders inside test-fixtures
.
When you want to test a new feature, generally when a new syntax is implemented, just create
a new folder inside test-fixtures
(doesn't matter where, you can also nest folders).
When you're satisfied with the level of folder, you have to create a file called input.*
.
The extension of
input.*
depends on the type of file you're testing
Once created the file, run ./rome test ./path/to/parser/index.test.ts
and Rome will create a snapshot
beside your input.*
file. If the new implementation has errors, the test won't pass.
On the other hand, you need to test also error cases; this is because Rome throw fancy diagnostics that we need to show to the developer, followed by the reason the grammar was incorrect.
In order to do so, you have to create a file called options.json
beside your input.*
file. Inside this
new JSON file, paste:
{
"throws": true
}
Doing so, Rome will expect diagnostics from your invalid syntax. If there aren't diagnostic, Rome will fail the test. Rome will create a snapshot where it will print the diagnostic. Please check the snapshot test because you will likely want to see the end result of your diagnostic and making that:
- the error message is clear enough;
- the diagnostic highlight correctly the error;
- the developer will understand what they need to do in order to fix the issue;
The diagnostics should look like this:
invalid/var/input.css:2:13 parse(css) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✖ Invalid custom property found inside the "var" function.
1 │ .style {
> 2 │ border: var(#fff);
│ ^^^^
3 │ border: var(calc(10px + 10px));
4 │ border: var(90rem);
Sometimes you need to test single functions in order to check if it handles edge cases.
Just create a file that has the suffix .test.ts
and Rome will pick it up automatically.
A boilerplate of your test could look like this:
import {test} from "rome";
import {toSnakeCase} from "./toSnakeCase";
test("toSnakeCase", async (t) => {
t.is(toSnakeCase("SomethingGood"), "something_good");
t.inlineSnapshot(toSnakeCase("SomethingGood"))
})
Check the interface TestHelper
to learn the available methods that the
testing suite provides.
At the moment integration tests are turned off,