Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JavaScript example of a linter plugin. #168

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lint/examples/javascript/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
pbjs-genfiles/
14 changes: 14 additions & 0 deletions lint/examples/javascript/.eslintrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
extends:
- 'eslint:recommended'
- 'plugin:node/recommended'
- prettier
plugins:
- node
- prettier
rules:
prettier/prettier: error
block-scoped-var: error
eqeqeq: error
no-warning-comments: warn
no-console: off
3 changes: 3 additions & 0 deletions lint/examples/javascript/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
pbjs-genfiles/*
package-lock.json
2 changes: 2 additions & 0 deletions lint/examples/javascript/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
pbjs-genfiles/
8 changes: 8 additions & 0 deletions lint/examples/javascript/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
bracketSpacing: false
printWidth: 80
semi: true
singleQuote: true
tabWidth: 2
trailingComma: es5
useTabs: false
113 changes: 113 additions & 0 deletions lint/examples/javascript/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# JavaScript Linter Plugin Sample

This directory contains a sample JavaScript program that works
as a plugin for the registry tool.

** WARNING: this is probably fragile and poorly-written JavaScript - PRs and issues are welcome! **

## Protocol Buffer Support

Message serialization requires JavaScript support code which is generated by
`pbjs` tool (part of [protobuf.js](https://www.npmjs.com/package/protobufjs)).
The generation will be done automatically after `npm install` and the resulting
`.js` file will be placed into `pbjs-genfiles/` folder.

## Instructions

To run the sample, first clone the `registry` project into your home directory.
We'll need this to get protos used by the plugin.

Then clone this repository and `cd` to this directory.

Build the code:
```
npm install
```

Install the styleguide into your registry:
```
registry apply -f sample-styleguide.yaml
```

To run the linter, first edit `registry-lint-js` to use the full absolute
path to `src/index.js`.

Copy `registry-lint-js` somewhere on your search path ("." won't work,
when the linter is run, it runs in a temporary directory containing the
downloaded spec).

Compute conformance with `registry compute conformance`. For example:
```
registry compute conformance apis/wordnik.com/versions/4.0/specs/openapi
```

Be sure that your target spec's MIME type is included in the style guide's
`mimetypes` list.

View the results of your run with `registry get`.
```
registry get apis/wordnik.com/versions/4.0/specs/openapi/artifacts/conformance-sample-styleguide -o yaml
```

Here's what I get for that:
```
$ registry get apis/wordnik.com/versions/4.0/specs/openapi/artifacts/conformance-sample-styleguide -o yaml
apiVersion: apigeeregistry/v1
kind: ConformanceReport
metadata:
name: conformance-sample-styleguide
parent: apis/wordnik.com/versions/4.0/specs/openapi
data:
styleguide: projects/menagerie/locations/global/artifacts/sample-styleguide
guidelineReportGroups:
- state: STATE_UNSPECIFIED
guidelineReports: []
- state: PROPOSED
guidelineReports: []
- state: ACTIVE
guidelineReports:
- guidelineId: active
ruleReportGroups:
- severity: SEVERITY_UNSPECIFIED
ruleReports: []
- severity: ERROR
ruleReports:
- ruleId: description-less-than-1000-chars
spec: projects/menagerie/locations/global/apis/wordnik.com/versions/4.0/specs/openapi@e70a3cc7
file: swagger.yaml
suggestion: keep API-ing!
location:
startPosition:
lineNumber: 2
columnNumber: 3
endPosition:
lineNumber: 4
columnNumber: 5
displayName: Description Maximum Length
description: Descriptions should not be too long.
docUri: https://github.com/apigee/registry
- ruleId: description-contains-no-tags
spec: projects/menagerie/locations/global/apis/wordnik.com/versions/4.0/specs/openapi@e70a3cc7
file: swagger.yaml
suggestion: keep API-ing!
location:
startPosition:
lineNumber: 2
columnNumber: 3
endPosition:
lineNumber: 4
columnNumber: 5
displayName: Description Tags
description: Descriptions should not contain HTML tags.
docUri: https://github.com/apigee/registry
- severity: WARNING
ruleReports: []
- severity: INFO
ruleReports: []
- severity: HINT
ruleReports: []
- state: DEPRECATED
guidelineReports: []
- state: DISABLED
guidelineReports: []
```
26 changes: 26 additions & 0 deletions lint/examples/javascript/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "registry-lint-js",
"version": "0.0.1",
"description": "Example Linter plugin written in JavaScript",
"main": "src/index.js",
"scripts": {
"lint": "eslint src/*.js",
"compile-proto": "mkdir -p pbjs-genfiles && pbjs -p ~/registry google/cloud/apigeeregistry/v1/style/lint.proto -o ./pbjs-genfiles/proto.js -t static-module",
"postinstall": "npm run compile-proto",
"prettier": "prettier --write **/*.js",
"start": "node src/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Google LLC",
"license": "Apache-2.0",
"dependencies": {
"protobufjs": "^6.8.8"
},
"devDependencies": {
"eslint": "^5.16.0",
"eslint-config-prettier": "^4.3.0",
"eslint-plugin-node": "^9.1.0",
"eslint-plugin-prettier": "^3.1.0",
"prettier": "^1.17.1"
}
}
3 changes: 3 additions & 0 deletions lint/examples/javascript/registry-lint-js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

node /home/FIXME/registry-experimental/lint/examples/javascript/src/index.js
41 changes: 41 additions & 0 deletions lint/examples/javascript/sample-styleguide.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
apiVersion: apigeeregistry/v1
kind: StyleGuide
metadata:
name: sample-styleguide
data:
displayName: sample styleguide
mimeTypes:
- application/x.openapi+gzip;version=3.0.0
- application/x.openapi+gzip;version=3.0.1
- application/x.openapi+gzip;version=3.0.2
- application/x.openapi+gzip;version=3.0.3
- application/x.openapi+gzip;version=3.1.0
- application/x.openapi;version=3
- application/x.openapi+gzip;version=2.0
- application/x.openapi+gzip;version=2
- application/x.openapi;version=2
- application/x.openapi+gzip
- application/x.openapi
guidelines:
- id: active
displayName: Active checks
description: Checks that are ACTIVE.
rules:
- id: description-less-than-1000-chars
displayName: Description Maximum Length
description: Descriptions should not be too long.
linter: js
linterRulename: description-less-than-1000-chars
severity: ERROR
docUri: https://github.com/apigee/registry
- id: description-contains-no-tags
displayName: Description Tags
description: Descriptions should not contain HTML tags.
linter: js
linterRulename: description-contains-no-tags
severity: ERROR
docUri: https://github.com/apigee/registry
state: ACTIVE
linters:
- name: js
uri: https://github.com/apigee/registry
77 changes: 77 additions & 0 deletions lint/examples/javascript/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// This loads definitions of the structs in our protocol buffer models.
const Style = require('../pbjs-genfiles/proto').google.cloud.apigeeregistry.v1.style;

async function main() {

// The plugin expects a request message on stdin.
process.stdin.on("data", data => {

// The request should be an encoded LinterRequest.
// Decode it.
const request = Style.LinterRequest.decode(
data
);

// Log it.
process.stderr.write(JSON.stringify(request) + "\n");

// We're going to make up some fake results.
// Here we one sample violation of each rule that was listed in the request.
problems = request.ruleIds.map(x => Style.LintProblem.fromObject({
"ruleId": x,
"message": "it is violated",
"suggestion": "keep API-ing!",
"location": {
"startPosition": {
"lineNumber": 2,
"columnNumber": 3
},
"endPosition": {
"lineNumber": 4,
"columnNumber": 5,
}
}
}))

// The request included a directory that contains the spec to lint,
// but we would have to look there to get its file name.
// Assume for now that we are linting a file named "swagger.yaml".
file = Style.LintFile.fromObject({
"filePath": request.specDirectory + "/swagger.yaml",
"problems": problems
});

// Put this all together in a response message.
response = Style.LinterResponse.fromObject({
"lint": {
"name": "registry-lint.js",
"files": [file]
}
});

// Log the response message.
process.stderr.write(JSON.stringify(response) + "\n");

// Encode the response and write it to stdout.
const responseBuffer = Style.LinterResponse.encode(
response
).finish();
process.stdout.write(responseBuffer)

// We're done.
process.exit();
})

// We just need this to wait until the handler above finishes.
await sleep(1000);
}

main().catch(err => {
console.error(err);
});

function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}