diff --git a/.eslintignore b/.eslintignore index 7e54e3631..a11511b7c 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,2 @@ -**/*.spec.js \ No newline at end of file +dist/** +.github/** diff --git a/.eslintrc.json b/.eslintrc.json index b223ac86c..87bc4f2da 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,19 +2,27 @@ "env": { "browser": true, "es6": true, + "jest/globals": true, "node": true }, "parser": "@babel/eslint-parser", "parserOptions": { - "ecmaFeatures": { - "experimentalObjectRestSpread": true, - "jsx": true - }, - "sourceType": "module" + "ecmaFeatures": { + "experimentalObjectRestSpread": true, + "jsx": true + }, + "sourceType": "module" }, - "extends": ["prettier", "eslint:recommended"], - "plugins": ["prettier"], + "extends": ["eslint:recommended", "plugin:jsdoc/recommended", "plugin:prettier/recommended"], + "plugins": ["jest", "jsdoc", "prettier"], "rules": { - "prettier/prettier": ["error"] + "no-prototype-builtins": 0, + "no-unused-vars": 0, + "jsdoc/check-indentation": 0, + "jsdoc/check-alignment": 0, + "jsdoc/check-line-alignment": 0, + "jsdoc/multiline-blocks": 0, + "jsdoc/newline-after-description": 0, + "jsdoc/tag-lines": 0 } -} +} diff --git a/.github/workflows/lock-closed-issue.yml b/.github/workflows/lock-closed-issue.yml deleted file mode 100644 index 11c3f35dd..000000000 --- a/.github/workflows/lock-closed-issue.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Lock closed issue - -on: - issues: - types: [closed] - -jobs: - triage: - runs-on: ubuntu-latest - steps: - - uses: Dunning-Kruger/lock-issues@v1.1 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/pr-labeler-config-validator.yml b/.github/workflows/pr-labeler-config-validator.yml new file mode 100644 index 000000000..c54e6d13e --- /dev/null +++ b/.github/workflows/pr-labeler-config-validator.yml @@ -0,0 +1,13 @@ +name: Validate PR Labeler Configuration +on: [push, pull_request] + +jobs: + pr-labeler: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v2.3.4 + - name: Validate Configuration + uses: Yash-Singh1/pr-labeler-config-validator@releases/v0.0.3 + with: + configuration-path: .github/pr-labeler.yml diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 000000000..a3c12e267 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +yarn dlx lint-staged diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 000000000..f9b7eed74 --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,5 @@ +{ + "*": [ + "yarn lint:fix" + ] +} diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index e9eb8060d..000000000 --- a/.prettierrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "printWidth": 100, - "singleQuote": true, - "endOfLine": "auto" -} diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..8cadfefaf --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "endOfLine": "auto", + "plugins": [ + "prettier-plugin-jsdoc" + ], + "printWidth": 100, + "singleQuote": true +} \ No newline at end of file diff --git a/README.md b/README.md index d620bb8ee..6f52c6d7d 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ pie - [Live Editor](https://github.com/mermaid-js/mermaid-live-editor) - [HTTP Server](https://github.com/TomWright/mermaid-server) -## Contributors [![Help wanted](https://img.shields.io/github/labels/mermaid-js/mermaid/Help%20wanted!)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Help+wanted%21%22) [![Contributors](https://img.shields.io/github/contributors/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) [![Commits](https://img.shields.io/github/commit-activity/m/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) +## Contributors [![Good first issue](https://img.shields.io/github/labels/mermaid-js/mermaid/Good%20first%20issue%21)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+issue%21%22) [![Contributors](https://img.shields.io/github/contributors/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) [![Commits](https://img.shields.io/github/commit-activity/m/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) Mermaid is a growing community and is always accepting new contributors. There's a lot of different ways to help out and we're always looking for extra hands! Look at [this issue](https://github.com/mermaid-js/mermaid/issues/866) if you want to know where to start helping out. diff --git a/README.zh-CN.md b/README.zh-CN.md index 416589ee4..7252f3d34 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -201,7 +201,7 @@ pie - [Live Editor](https://github.com/mermaid-js/mermaid-live-editor) - [HTTP Server](https://github.com/TomWright/mermaid-server) -## 贡献者 [![Help wanted](https://img.shields.io/github/labels/mermaid-js/mermaid/Help%20wanted!)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Help+wanted%21%22) [![Contributors](https://img.shields.io/github/contributors/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) [![Commits](https://img.shields.io/github/commit-activity/m/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) +## 贡献者 [![Good first issue](https://img.shields.io/github/labels/mermaid-js/mermaid/Good%20first%20issue%21)](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+issue%21%22) [![Contributors](https://img.shields.io/github/contributors/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) [![Commits](https://img.shields.io/github/commit-activity/m/mermaid-js/mermaid)](https://github.com/mermaid-js/mermaid/graphs/contributors) Mermaid 是一个不断发展中的社区,并且还在接收新的贡献者。有很多不同的方式可以参与进来,而且我们还在寻找额外的帮助。如果你想知道如何开始贡献,请查看 [这个 issue](https://github.com/mermaid-js/mermaid/issues/866)。 diff --git a/__mocks__/MERMAID.js b/__mocks__/MERMAID.js index f844f1c55..58e31037a 100644 --- a/__mocks__/MERMAID.js +++ b/__mocks__/MERMAID.js @@ -1,3 +1,3 @@ -export const curveBasis = 'basis' -export const curveLinear = 'linear' -export const curveCardinal = 'cardinal' +export const curveBasis = 'basis'; +export const curveLinear = 'linear'; +export const curveCardinal = 'cardinal'; diff --git a/__mocks__/d3.js b/__mocks__/d3.js index caee810ad..c5c7deed8 100644 --- a/__mocks__/d3.js +++ b/__mocks__/d3.js @@ -1,11 +1,10 @@ -/* eslint-env jest */ let NewD3 = function () { - function returnThis () { - return this + function returnThis() { + return this; } return { append: function () { - return NewD3() + return NewD3(); }, lower: returnThis, attr: returnThis, @@ -16,41 +15,47 @@ let NewD3 = function () { getBBox: function () { return { height: 10, - width: 20 - } - } - } - } - } -} + width: 20, + }; + }, + }, + }, + }; +}; export const select = function () { - return new NewD3() -} + return new NewD3(); +}; export const selectAll = function () { - return new NewD3() -} + return new NewD3(); +}; -export const curveBasis = 'basis' -export const curveLinear = 'linear' -export const curveCardinal = 'cardinal' +export const curveBasis = 'basis'; +export const curveLinear = 'linear'; +export const curveCardinal = 'cardinal'; export const MockD3 = (name, parent) => { - const children = [] + const children = []; const elem = { - get __children () { return children }, - get __name () { return name }, - get __parent () { return parent } - } + get __children() { + return children; + }, + get __name() { + return name; + }, + get __parent() { + return parent; + }, + }; elem.append = (name) => { - const mockElem = MockD3(name, elem) - children.push(mockElem) - return mockElem - } - elem.lower = jest.fn(() => elem) - elem.attr = jest.fn(() => elem) - elem.text = jest.fn(() => elem) - elem.style = jest.fn(() => elem) - return elem -} + const mockElem = MockD3(name, elem); + children.push(mockElem); + return mockElem; + }; + elem.lower = jest.fn(() => elem); + elem.attr = jest.fn(() => elem); + elem.text = jest.fn(() => elem); + elem.style = jest.fn(() => elem); + return elem; +}; diff --git a/cypress.json b/cypress.json index a56d1ac68..5e0725b20 100644 --- a/cypress.json +++ b/cypress.json @@ -1 +1,3 @@ -{ "video": false } +{ + "video": false +} \ No newline at end of file diff --git a/cypress/.eslintrc.json b/cypress/.eslintrc.json new file mode 100644 index 000000000..fe68a538d --- /dev/null +++ b/cypress/.eslintrc.json @@ -0,0 +1,10 @@ +{ + "env": { + "cypress/globals": true + }, + "extends": ["plugin:cypress/recommended"], + "plugins": ["cypress"], + "rules":{ + "cypress/no-unnecessary-waiting": 0 + } +} diff --git a/cypress/examples/actions.spec.js b/cypress/examples/actions.spec.js index 20e12cc6d..5843547af 100644 --- a/cypress/examples/actions.spec.js +++ b/cypress/examples/actions.spec.js @@ -2,15 +2,16 @@ context('Actions', () => { beforeEach(() => { - cy.visit('https://example.cypress.io/commands/actions') - }) + cy.visit('https://example.cypress.io/commands/actions'); + }); // https://on.cypress.io/interacting-with-elements it('.type() - type into a DOM element', () => { // https://on.cypress.io/type cy.get('.action-email') - .type('fake@email.com').should('have.value', 'fake@email.com') + .type('fake@email.com') + .should('have.value', 'fake@email.com') // .type() with special character sequences .type('{leftarrow}{rightarrow}{uparrow}{downarrow}') @@ -24,48 +25,52 @@ context('Actions', () => { // Delay each keypress by 0.1 sec .type('slow.typing@email.com', { delay: 100 }) - .should('have.value', 'slow.typing@email.com') + .should('have.value', 'slow.typing@email.com'); cy.get('.action-disabled') // Ignore error checking prior to type // like whether the input is visible or disabled .type('disabled error checking', { force: true }) - .should('have.value', 'disabled error checking') - }) + .should('have.value', 'disabled error checking'); + }); it('.focus() - focus on a DOM element', () => { // https://on.cypress.io/focus - cy.get('.action-focus').focus() + cy.get('.action-focus') + .focus() .should('have.class', 'focus') - .prev().should('have.attr', 'style', 'color: orange;') - }) + .prev() + .should('have.attr', 'style', 'color: orange;'); + }); it('.blur() - blur off a DOM element', () => { // https://on.cypress.io/blur - cy.get('.action-blur').type('About to blur').blur() + cy.get('.action-blur') + .type('About to blur') + .blur() .should('have.class', 'error') - .prev().should('have.attr', 'style', 'color: red;') - }) + .prev() + .should('have.attr', 'style', 'color: red;'); + }); it('.clear() - clears an input or textarea element', () => { // https://on.cypress.io/clear - cy.get('.action-clear').type('Clear this text') + cy.get('.action-clear') + .type('Clear this text') .should('have.value', 'Clear this text') .clear() - .should('have.value', '') - }) + .should('have.value', ''); + }); it('.submit() - submit a form', () => { // https://on.cypress.io/submit - cy.get('.action-form') - .find('[type="text"]').type('HALFOFF') - cy.get('.action-form').submit() - .next().should('contain', 'Your form has been submitted!') - }) + cy.get('.action-form').find('[type="text"]').type('HALFOFF'); + cy.get('.action-form').submit().next().should('contain', 'Your form has been submitted!'); + }); it('.click() - click on a DOM element', () => { // https://on.cypress.io/click - cy.get('.action-btn').click() + cy.get('.action-btn').click(); // You can click on 9 specific positions of an element: // ----------------------------------- @@ -81,16 +86,16 @@ context('Actions', () => { // ----------------------------------- // clicking in the center of the element is the default - cy.get('#action-canvas').click() + cy.get('#action-canvas').click(); - cy.get('#action-canvas').click('topLeft') - cy.get('#action-canvas').click('top') - cy.get('#action-canvas').click('topRight') - cy.get('#action-canvas').click('left') - cy.get('#action-canvas').click('right') - cy.get('#action-canvas').click('bottomLeft') - cy.get('#action-canvas').click('bottom') - cy.get('#action-canvas').click('bottomRight') + cy.get('#action-canvas').click('topLeft'); + cy.get('#action-canvas').click('top'); + cy.get('#action-canvas').click('topRight'); + cy.get('#action-canvas').click('left'); + cy.get('#action-canvas').click('right'); + cy.get('#action-canvas').click('bottomLeft'); + cy.get('#action-canvas').click('bottom'); + cy.get('#action-canvas').click('bottomRight'); // .click() accepts an x and y coordinate // that controls where the click occurs :) @@ -102,90 +107,83 @@ context('Actions', () => { .click(100, 185) .click(125, 190) .click(150, 185) - .click(170, 165) + .click(170, 165); // click multiple elements by passing multiple: true - cy.get('.action-labels>.label').click({ multiple: true }) + cy.get('.action-labels>.label').click({ multiple: true }); // Ignore error checking prior to clicking - cy.get('.action-opacity>.btn').click({ force: true }) - }) + cy.get('.action-opacity>.btn').click({ force: true }); + }); it('.dblclick() - double click on a DOM element', () => { // https://on.cypress.io/dblclick // Our app has a listener on 'dblclick' event in our 'scripts.js' // that hides the div and shows an input on double click - cy.get('.action-div').dblclick().should('not.be.visible') - cy.get('.action-input-hidden').should('be.visible') - }) + cy.get('.action-div').dblclick().should('not.be.visible'); + cy.get('.action-input-hidden').should('be.visible'); + }); it('.check() - check a checkbox or radio element', () => { // https://on.cypress.io/check // By default, .check() will check all // matching checkbox or radio elements in succession, one after another - cy.get('.action-checkboxes [type="checkbox"]').not('[disabled]') - .check().should('be.checked') + cy.get('.action-checkboxes [type="checkbox"]').not('[disabled]').check().should('be.checked'); - cy.get('.action-radios [type="radio"]').not('[disabled]') - .check().should('be.checked') + cy.get('.action-radios [type="radio"]').not('[disabled]').check().should('be.checked'); // .check() accepts a value argument - cy.get('.action-radios [type="radio"]') - .check('radio1').should('be.checked') + cy.get('.action-radios [type="radio"]').check('radio1').should('be.checked'); // .check() accepts an array of values cy.get('.action-multiple-checkboxes [type="checkbox"]') - .check(['checkbox1', 'checkbox2']).should('be.checked') + .check(['checkbox1', 'checkbox2']) + .should('be.checked'); // Ignore error checking prior to checking - cy.get('.action-checkboxes [disabled]') - .check({ force: true }).should('be.checked') + cy.get('.action-checkboxes [disabled]').check({ force: true }).should('be.checked'); - cy.get('.action-radios [type="radio"]') - .check('radio3', { force: true }).should('be.checked') - }) + cy.get('.action-radios [type="radio"]').check('radio3', { force: true }).should('be.checked'); + }); it('.uncheck() - uncheck a checkbox element', () => { // https://on.cypress.io/uncheck // By default, .uncheck() will uncheck all matching // checkbox elements in succession, one after another - cy.get('.action-check [type="checkbox"]') - .not('[disabled]') - .uncheck().should('not.be.checked') + cy.get('.action-check [type="checkbox"]').not('[disabled]').uncheck().should('not.be.checked'); // .uncheck() accepts a value argument cy.get('.action-check [type="checkbox"]') .check('checkbox1') - .uncheck('checkbox1').should('not.be.checked') + .uncheck('checkbox1') + .should('not.be.checked'); // .uncheck() accepts an array of values cy.get('.action-check [type="checkbox"]') .check(['checkbox1', 'checkbox3']) - .uncheck(['checkbox1', 'checkbox3']).should('not.be.checked') + .uncheck(['checkbox1', 'checkbox3']) + .should('not.be.checked'); // Ignore error checking prior to unchecking - cy.get('.action-check [disabled]') - .uncheck({ force: true }).should('not.be.checked') - }) + cy.get('.action-check [disabled]').uncheck({ force: true }).should('not.be.checked'); + }); it('.select() - select an option in a