Skip to content

Commit

Permalink
Implement validation for member-accessibility using JSON schema
Browse files Browse the repository at this point in the history
  • Loading branch information
edsrzf committed Apr 28, 2021
1 parent cb32d86 commit 14e037a
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 2 deletions.
2 changes: 2 additions & 0 deletions packages/ts-migrate-plugins/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,14 @@
"dependencies": {
"eslint": "^7.14.0",
"jscodeshift": "^0.12.0",
"json-schema": "^0.3.0",
"ts-migrate-server": "^0.1.18",
"typescript": "4.2.4"
},
"gitHead": "7acf6067f15c9bb367cda9c47fcfb4203dcc54f3",
"devDependencies": {
"@ts-morph/bootstrap": "^0.9.1",
"@types/json-schema": "^7.0.7",
"jest": "26.6.3"
}
}
44 changes: 42 additions & 2 deletions packages/ts-migrate-plugins/src/plugins/member-accessibility.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
/* eslint-disable no-bitwise */
import ts from 'typescript';
import { Plugin } from 'ts-migrate-server';
import { Plugin, PluginOptionsError } from 'ts-migrate-server';
import { JSONSchema7 } from 'json-schema';

import { validateOptions } from '../utils/validateOptions';

const accessibility = ['private' as const, 'protected' as const, 'public' as const];

const optionsSchema: JSONSchema7 = {
type: 'object',
properties: {
defaultAccessibility: { enum: accessibility },
privateRegex: { type: 'string' },
protectedRegex: { type: 'string' },
publicRegex: { type: 'string' },
},
additionalProperties: false,
};

type Options = {
defaultAccessibility?: 'private' | 'protected' | 'public';
defaultAccessibility?: typeof accessibility[number];
privateRegex?: string;
protectedRegex?: string;
publicRegex?: string;
};

const memberAccessibilityPlugin: Plugin<Options> = {
name: 'member-accessibility',

run({ sourceFile, text, options }) {
const result = ts.transform(sourceFile, [memberAccessibilityTransformerFactory(options)]);
const newSourceFile = result.transformed[0];
Expand All @@ -20,6 +37,29 @@ const memberAccessibilityPlugin: Plugin<Options> = {
const printer = ts.createPrinter();
return printer.printFile(newSourceFile);
},

validate(options: unknown): options is Options {
const valid = validateOptions(options, optionsSchema);

if (valid) {
// Validate regex property syntax.
// This can't be covered by JSON schema.
const validOptions = options as Options;
accessibility.forEach((accessibility) => {
const key = `${accessibility}Regex` as const;
const value = validOptions[key];
if (value) {
try {
RegExp(value);
} catch (e) {
throw new PluginOptionsError(`${key}: ${e.message}`);
}
}
});
}

return true;
},
};

export default memberAccessibilityPlugin;
Expand Down
16 changes: 16 additions & 0 deletions packages/ts-migrate-plugins/src/utils/validateOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { JSONSchema7, validate } from 'json-schema';
import { PluginOptionsError } from 'ts-migrate-server';

export function validateOptions(options: unknown, schema: JSONSchema7): boolean {
if (typeof options !== 'object' || !options) {
throw new PluginOptionsError('options must be an object');
}
const validation = validate(options, schema);
if (!validation.valid) {
const message = validation.errors
.map((error) => `${error.property}: ${error.message}`)
.join('\n');
throw new PluginOptionsError(message);
}
return true;
}
12 changes: 12 additions & 0 deletions packages/ts-migrate-plugins/tests/src/member-accessibility.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { PluginOptionsError } from 'ts-migrate-server';
import { mockPluginParams } from '../test-utils';
import memberAccessibilityPlugin from '../../src/plugins/member-accessibility';

Expand Down Expand Up @@ -44,4 +45,15 @@ const o = {

expect(result).toBe(text);
});

it.each([{}, { defaultAccessibility: 'private' }])('accepts valid options: %p', (options) => {
expect(memberAccessibilityPlugin.validate!(options)).toBe(true);
});

it.each([42, { additional: true }, { defaultAccessibility: 'static' }, { privateRegex: '+' }])(
'rejects invalid options: %p',
(options) => {
expect(() => memberAccessibilityPlugin.validate!(options)).toThrow(PluginOptionsError);
},
);
});
10 changes: 10 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2683,6 +2683,11 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd"
integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==

"@types/json-schema@^7.0.7":
version "7.0.7"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==

"@types/[email protected]":
version "0.0.30"
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.30.tgz#44cb52f32a809734ca562e685c6473b5754a7818"
Expand Down Expand Up @@ -6822,6 +6827,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=

json-schema@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.3.0.tgz#90a9c5054bd065422c00241851ce8d59475b701b"
integrity sha512-TYfxx36xfl52Rf1LU9HyWSLGPdYLL+SQ8/E/0yVyKG8wCCDaSrhPap0vEdlsZWRaS6tnKKLPGiEJGiREVC8kxQ==

json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
Expand Down

0 comments on commit 14e037a

Please sign in to comment.