Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
nulltoken committed Feb 25, 2020
1 parent 7e166ae commit e566d4d
Show file tree
Hide file tree
Showing 16 changed files with 1,956 additions and 36 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"scripts": {
"build.binary": "pkg . --output ./binaries/spectral",
"build.clean": "rimraf ./coverage && rimraf ./dist && rimraf ./rulesets && rimraf ./__karma__/__fixtures__",
"build.oas-functions": "rollup -c",
"build.functions": "rollup -c",
"build": "tsc -p ./tsconfig.build.json",
"cli": "node -r ts-node/register -r tsconfig-paths/register src/cli/index.ts",
"cli:debug": "node -r ts-node/register -r tsconfig-paths/register --inspect-brk src/cli/index.ts",
Expand All @@ -44,9 +44,9 @@
"lint.fix": "yarn lint --fix",
"lint": "tsc --noEmit && tslint 'src/**/*.ts'",
"copy.html-templates": "copyfiles -u 1 \"./src/formatters/html/*.html\" \"./dist/\"",
"postbuild.oas-functions": "copyfiles -u 1 \"dist/rulesets/oas*/functions/*.js\" ./",
"postbuild": "yarn build.oas-functions && yarn generate-assets",
"prebuild": "yarn build.clean && copyfiles -u 1 \"src/rulesets/oas*/**/*.json\" dist && copyfiles -u 1 \"src/rulesets/oas*/**/*.json\" ./ && yarn copy.html-templates",
"postbuild.functions": "copyfiles -u 1 \"dist/rulesets/{o,a}as/functions/*.js\" ./",
"postbuild": "yarn build.functions && yarn generate-assets",
"prebuild": "yarn build.clean && copyfiles -u 1 \"src/rulesets/{o,a}as/**/*.json\" dist && copyfiles -u 1 \"src/rulesets/{o,a}as/**/*.json\" ./ && yarn copy.html-templates",
"prebuild.binary": "yarn build",
"pretest.karma": "node ./scripts/generate-karma-fixtures.js && yarn pretest",
"pretest": "node ./scripts/generate-assets.js",
Expand Down
1 change: 1 addition & 0 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { terser } from 'rollup-plugin-terser';

const BASE_PATH = process.cwd();
const directory = 'dist/rulesets/oas/functions';
// TODO: Add aas
const targetDir = path.join(BASE_PATH, directory);

const functions = [];
Expand Down
6 changes: 4 additions & 2 deletions scripts/generate-assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ const target = path.join(baseDir, `assets.json`);
const assets = {};

(async () => {
await processDirectory(assets, path.join(__dirname, '../rulesets/oas'));
await writeFileAsync(target, JSON.stringify(assets, null, 2));
['oas', 'aas'].forEach(async (kind) => {
await processDirectory(assets, path.join(__dirname, `../rulesets/${kind}`));
await writeFileAsync(target, JSON.stringify(assets, null, 2));
})
})();

async function processDirectory(assets, dir) {
Expand Down
6 changes: 3 additions & 3 deletions scripts/generate-karma-fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ if (!fs.existsSync(baseDir)) {
fs.mkdirSync(baseDir);
}

for (const spec of ['']) {
const target = path.join(baseDir, `oas${spec}-functions.json`);
const fnsPath = path.join(__dirname, `../rulesets/oas${spec}/functions`);
for (const rulesetName of ['oas', 'aas']) {
const target = path.join(baseDir, `${rulesetName}-functions.json`);
const fnsPath = path.join(__dirname, `../rulesets/${rulesetName}/functions`);
const bundledFns = {};

if (fs.existsSync(fnsPath)) {
Expand Down
18 changes: 12 additions & 6 deletions setupKarma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FetchMockSandbox } from 'fetch-mock';

const oasRuleset = JSON.parse(JSON.stringify(require('./rulesets/oas/index.json')));
const oasFunctions = JSON.parse(JSON.stringify(require('./__karma__/__fixtures__/oas-functions.json')));
const aasFunctions = JSON.parse(JSON.stringify(require('./__karma__/__fixtures__/aas-functions.json')));
const oas2Schema = JSON.parse(JSON.stringify(require('./rulesets/oas/schemas/schema.oas2.json')));
const oas3Schema = JSON.parse(JSON.stringify(require('./rulesets/oas/schemas/schema.oas3.json')));

Expand All @@ -28,12 +29,17 @@ beforeEach(() => {
body: JSON.parse(JSON.stringify(oas3Schema)),
});

for (const [name, fn] of Object.entries<string>(oasFunctions)) {
fetchMock.get(`https://unpkg.com/@stoplight/spectral/rulesets/oas/functions/${name}`, {
status: 200,
body: fn,
});
}
[
['oas', oasFunctions],
['aas', aasFunctions],
].forEach(([rulesetName, funcs]) => {
for (const [name, fn] of Object.entries<string>(funcs)) {
fetchMock.get(`https://unpkg.com/@stoplight/spectral/rulesets/${rulesetName}/functions/${name}`, {
status: 200,
body: fn,
});
}
});

fetchMock.get('http://json-schema.org/draft-04/schema', {
status: 200,
Expand Down
211 changes: 211 additions & 0 deletions src/__tests__/__fixtures__/aas/streetlight.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
%YAML 1.2
---
asyncapi: '2.0.0'
info:
title: Streetlights API
version: '1.0.0'
description: |
The Smartylighting Streetlights API allows you to remotely manage the city lights.
### Check out its awesome features:
* Turn a specific streetlight on/off 🌃
* Dim a specific streetlight 😎
* Receive real-time information about environmental lighting conditions 📈
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0

servers:
production:
url: test.mosquitto.org:{port}
protocol: mqtt
description: Test broker
variables:
port:
description: Secure connection (TLS) is available through port 8883.
default: '1883'
enum:
- '1883'
- '8883'
security:
- apiKey: []
- supportedOauthFlows:
- streetlights:on
- streetlights:off
- streetlights:dim
- openIdConnectWellKnown: []

defaultContentType: application/json

channels:
smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured:
description: The topic on which measured values may be produced and consumed.
parameters:
streetlightId:
$ref: '#/components/parameters/streetlightId'
publish:
summary: Inform about environmental lighting conditions of a particular streetlight.
operationId: receiveLightMeasurement
traits:
- $ref: '#/components/operationTraits/kafka'
message:
$ref: '#/components/messages/lightMeasured'

smartylighting/streetlights/1/0/action/{streetlightId}/turn/on:
parameters:
streetlightId:
$ref: '#/components/parameters/streetlightId'
subscribe:
operationId: turnOn
traits:
- $ref: '#/components/operationTraits/kafka'
message:
$ref: '#/components/messages/turnOnOff'

smartylighting/streetlights/1/0/action/{streetlightId}/turn/off:
parameters:
streetlightId:
$ref: '#/components/parameters/streetlightId'
subscribe:
operationId: turnOff
traits:
- $ref: '#/components/operationTraits/kafka'
message:
$ref: '#/components/messages/turnOnOff'

smartylighting/streetlights/1/0/action/{streetlightId}/dim:
parameters:
streetlightId:
$ref: '#/components/parameters/streetlightId'
subscribe:
operationId: dimLight
traits:
- $ref: '#/components/operationTraits/kafka'
message:
$ref: '#/components/messages/dimLight'

components:
messages:
lightMeasured:
name: lightMeasured
title: Light measured
summary: Inform about environmental lighting conditions of a particular streetlight.
contentType: application/json
traits:
- $ref: '#/components/messageTraits/commonHeaders'
payload:
$ref: "#/components/schemas/lightMeasuredPayload"
turnOnOff:
name: turnOnOff
title: Turn on/off
summary: Command a particular streetlight to turn the lights on or off.
traits:
- $ref: '#/components/messageTraits/commonHeaders'
payload:
$ref: "#/components/schemas/turnOnOffPayload"
dimLight:
name: dimLight
title: Dim light
summary: Command a particular streetlight to dim the lights.
traits:
- $ref: '#/components/messageTraits/commonHeaders'
payload:
$ref: "#/components/schemas/dimLightPayload"

schemas:
lightMeasuredPayload:
type: object
properties:
lumens:
type: integer
minimum: 0
description: Light intensity measured in lumens.
sentAt:
$ref: "#/components/schemas/sentAt"
turnOnOffPayload:
type: object
properties:
command:
type: string
enum:
- on
- off
description: Whether to turn on or off the light.
sentAt:
$ref: "#/components/schemas/sentAt"
dimLightPayload:
type: object
properties:
percentage:
type: integer
description: Percentage to which the light should be dimmed to.
minimum: 0
maximum: 100
sentAt:
$ref: "#/components/schemas/sentAt"
sentAt:
type: string
format: date-time
description: Date and time when the message was sent.

securitySchemes:
apiKey:
type: apiKey
in: user
description: Provide your API key as the user and leave the password empty.
supportedOauthFlows:
type: oauth2
description: Flows to support OAuth 2.0
flows:
implicit:
authorizationUrl: 'https://authserver.example/auth'
scopes:
'streetlights:on': Ability to switch lights on
'streetlights:off': Ability to switch lights off
'streetlights:dim': Ability to dim the lights
password:
tokenUrl: 'https://authserver.example/token'
scopes:
'streetlights:on': Ability to switch lights on
'streetlights:off': Ability to switch lights off
'streetlights:dim': Ability to dim the lights
clientCredentials:
tokenUrl: 'https://authserver.example/token'
scopes:
'streetlights:on': Ability to switch lights on
'streetlights:off': Ability to switch lights off
'streetlights:dim': Ability to dim the lights
authorizationCode:
authorizationUrl: 'https://authserver.example/auth'
tokenUrl: 'https://authserver.example/token'
refreshUrl: 'https://authserver.example/refresh'
scopes:
'streetlights:on': Ability to switch lights on
'streetlights:off': Ability to switch lights off
'streetlights:dim': Ability to dim the lights
openIdConnectWellKnown:
type: openIdConnect
openIdConnectUrl: 'https://authserver.example/.well-known'

parameters:
streetlightId:
description: The ID of the streetlight.
schema:
type: string

messageTraits:
commonHeaders:
headers:
type: object
properties:
my-app-header:
type: integer
minimum: 0
maximum: 100

operationTraits:
kafka:
bindings:
kafka:
clientId: my-app-id
48 changes: 28 additions & 20 deletions src/__tests__/spectral.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,22 @@ import { Spectral } from '../spectral';
import { IResolver, IRunRule, RuleFunction } from '../types';

const oasRuleset = JSON.parse(JSON.stringify(require('../rulesets/oas/index.json')));
const aasRuleset = JSON.parse(JSON.stringify(require('../rulesets/aas/index.json')));
const oasRulesetRules: Dictionary<IRunRule, string> = oasRuleset.rules;
const aasRulesetRules: Dictionary<IRunRule, string> = aasRuleset.rules;

describe('spectral', () => {
describe('loadRuleset', () => {
test('should support loading built-in rulesets', async () => {
test.each([
['spectral:oas', oasRulesetRules],
['spectral:aas', aasRulesetRules],
])('should support loading "%s" built-in ruleset', async (rulesetName, rules) => {
const s = new Spectral();
await s.loadRuleset('spectral:oas');
await s.loadRuleset(rulesetName);

expect(s.rules).toEqual(
expect.objectContaining(
Object.entries(oasRulesetRules).reduce<Dictionary<IRunRule, string>>((oasRules, [name, rule]) => {
Object.entries(rules).reduce<Dictionary<IRunRule, string>>((oasRules, [name, rule]) => {
oasRules[name] = {
name,
...rule,
Expand All @@ -34,24 +39,27 @@ describe('spectral', () => {
);
});

test('should support loading multiple times the built-in ruleset', async () => {
const s = new Spectral();
await s.loadRuleset(['spectral:oas', 'spectral:oas']);
test.each([['spectral:oas'], ['spectral:aas']])(
'should support loading multiple times the built-in ruleset "%s"',
async rulesetName => {
const s = new Spectral();
await s.loadRuleset([rulesetName, rulesetName]);

expect(s.rules).toEqual(
Object.entries(oasRulesetRules).reduce<Dictionary<IRunRule, string>>((oasRules, [name, rule]) => {
oasRules[name] = {
name,
...rule,
formats: expect.arrayContaining([expect.any(String)]),
severity: expect.any(Number),
then: expect.any(Object),
};

return oasRules;
}, {}),
);
});
expect(s.rules).toEqual(
Object.entries(oasRulesetRules).reduce<Dictionary<IRunRule, string>>((oasRules, [name, rule]) => {
oasRules[name] = {
name,
...rule,
formats: expect.arrayContaining([expect.any(String)]),
severity: expect.any(Number),
then: expect.any(Object),
};

return oasRules;
}, {}),
);
},
);
});

describe('setRules & mergeRules', () => {
Expand Down
1 change: 1 addition & 0 deletions src/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ function resolveSpectralRuleset(ruleset: string) {

export const RESOLVE_ALIASES: Dictionary<string, string> = {
'spectral:oas': resolveSpectralRuleset('oas'),
'spectral:aas': resolveSpectralRuleset('aas'),
};

export const STATIC_ASSETS: Dictionary<string> = {};
2 changes: 2 additions & 0 deletions src/cli/services/linter/linter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Document } from '../../../document';
import {
isAsyncApiv2,
isJSONSchema,
isJSONSchemaDraft2019_09,
isJSONSchemaDraft4,
Expand All @@ -21,6 +22,7 @@ import { getResolver } from './utils/getResolver';
const KNOWN_FORMATS: Array<[string, FormatLookup, string]> = [
['oas2', isOpenApiv2, 'OpenAPI 2.0 (Swagger) detected'],
['oas3', isOpenApiv3, 'OpenAPI 3.x detected'],
['aas2', isAsyncApiv2, 'AsyncAPI 2.x detected'],
['json-schema', isJSONSchema, 'JSON Schema detected'],
['json-schema-loose', isJSONSchemaLoose, 'JSON Schema (loose) detected'],
['json-schema-draft4', isJSONSchemaDraft4, 'JSON Schema Draft 4 detected'],
Expand Down
Loading

0 comments on commit e566d4d

Please sign in to comment.