Skip to content

Commit

Permalink
add rule for inefficient interface types (#115)
Browse files Browse the repository at this point in the history
* add rule for checking for inefficient interface types

* move interface type check to code style plugin and divide it into two rules

* add check for type attr existence

* add rules to readme, adjust messages

* adjust messages

* fix tests

* edit messages, fix readme

* fix linting errors, adjust range
  • Loading branch information
RokuAndrii authored Jul 24, 2024
1 parent 31764a4 commit 6943f2f
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 10 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,10 @@ Default rules:
"unreachable-code": "info",
"case-sensitivity": "warn",
"unused-variable": "warn",
"consistent-return": "error"
"consistent-return": "error",

"no-assocarray-component-field-type": "off",
"no-array-component-field-type": "off"
}
}
```
Expand Down Expand Up @@ -248,6 +251,10 @@ Default rules:
- `always`: ensures all white and black color-format values either match or are darker/ lighter than the minimum recommended values. For white the maximum value is `#EBEBEB` and for black the minimum value is `#161616`
- `off`: do not validate (**default**)

- `no-assocarray-component-field-type`: Using 'assocarray' type in component markup can result in inefficient copying of data during transfer to the render thread. Use 'node' type if possible for more efficient transfer of data from the task thread to the render thread (`error | warn | info | off`)

- `no-array-component-field-type`: Using 'array' type in component markup can result in inefficient copying of data during transfer to the render thread. Use 'node' type if possible for more efficient transfer of data from the task thread to the render thread (`error | warn | info | off`)

### Strictness rules

- `type-annotations`: validation of presence of `as` type annotations, for function
Expand Down Expand Up @@ -325,4 +332,4 @@ Running `bslint` with `--checkUsage` parameter will attempt to identify unused c
- Any script/component not walked will produce a warning.

## Changelog
Click [here](CHANGELOG.md) to view the changelog
Click [here](CHANGELOG.md) to view the changelog
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export type BsLintConfig = Pick<BsConfig, 'project' | 'rootDir' | 'files' | 'cwd
'color-alpha'?: RuleColorAlpha;
'color-alpha-defaults'?: RuleColorAlphaDefaults;
'color-cert'?: RuleColorCertCompliant;
'no-assocarray-component-field-type'?: RuleSeverity;
'no-array-component-field-type'?: RuleSeverity;
};
globals?: string[];
ignores?: string[];
Expand Down Expand Up @@ -82,6 +84,8 @@ export interface BsLintRules {
colorAlpha: RuleColorAlpha;
colorAlphaDefaults: RuleColorAlphaDefaults;
colorCertCompliant: RuleColorCertCompliant;
noAssocarrayComponentFieldType: BsLintSeverity;
noArrayComponentFieldType: BsLintSeverity;
}

export { Linter };
Expand Down
18 changes: 17 additions & 1 deletion src/plugins/codeStyle/diagnosticMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export enum CodeStyleError {
ColorCase = 'LINT3020',
ColorAlpha = 'LINT3021',
ColorAlphaDefaults = 'LINT3022',
ColorCertCompliant = 'LINT3023'
ColorCertCompliant = 'LINT3023',
NoAssocarrayFieldType = 'LINT3024',
NoArrayFieldType = 'LINT3025'
}

const CS = 'Code style:';
Expand Down Expand Up @@ -199,5 +201,19 @@ export const messages = {
source: 'bslint',
message: `${CS} File should follow Roku broadcast safe color cert requirement`,
range
}),
noAssocarrayFieldType: (range: Range, severity: DiagnosticSeverity) => ({
message: `Avoid using field type 'assocarray'`,
code: CodeStyleError.NoAssocarrayFieldType,
severity: severity,
source: 'bslint',
range
}),
noArrayFieldType: (range: Range, severity: DiagnosticSeverity) => ({
message: `Avoid using field type 'array'`,
code: CodeStyleError.NoArrayFieldType,
severity: severity,
source: 'bslint',
range
})
};
31 changes: 31 additions & 0 deletions src/plugins/codeStyle/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ describe('codeStyle', () => {
expect(actual).deep.equal(expected);
});


describe('enforce no todo', () => {
it('default todo pattern', async () => {
const diagnostics = await linter.run({
Expand Down Expand Up @@ -534,6 +535,36 @@ describe('codeStyle', () => {
});
});

it('enforce no assocarray component field type', async () => {
const diagnostics = await linter.run({
...project1,
files: ['components/interfaceTest.xml'],
rules: {
'no-assocarray-component-field-type': 'info'
}
} as any);
const actual = fmtDiagnostics(diagnostics);
const expected = [
`06:LINT3024:Avoid using field type 'assocarray'`
];
expect(actual).deep.equal(expected);
});

it('enforce no array component field type', async () => {
const diagnostics = await linter.run({
...project1,
files: ['components/interfaceTest.xml'],
rules: {
'no-array-component-field-type': 'info'
}
} as any);
const actual = fmtDiagnostics(diagnostics);
const expected = [
`04:LINT3025:Avoid using field type 'array'`
];
expect(actual).deep.equal(expected);
});

describe('AA style', () => {
it('collects wrapping AA members indexes', () => {
const { statements } = Parser.parse(`
Expand Down
75 changes: 70 additions & 5 deletions src/plugins/codeStyle/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
import { BscFile, BsDiagnostic, createVisitor, FunctionExpression, isBrsFile, isGroupingExpression, TokenKind, WalkMode, CancellationTokenSource, DiagnosticSeverity, OnGetCodeActionsEvent, isCommentStatement, AALiteralExpression, AAMemberExpression } from 'brighterscript';
import {
BscFile,
XmlFile,
BsDiagnostic,
createVisitor,
FunctionExpression,
isBrsFile,
isXmlFile,
isGroupingExpression,
TokenKind,
WalkMode,
CancellationTokenSource,
DiagnosticSeverity,
OnGetCodeActionsEvent,
isCommentStatement,
AALiteralExpression,
AAMemberExpression,
BrsFile
} from 'brighterscript';
import { RuleAAComma } from '../..';
import { addFixesToEvent } from '../../textEdit';
import { PluginContext } from '../../util';
Expand All @@ -18,13 +36,43 @@ export default class CodeStyle {
extractFixes(addFixes, event.diagnostics);
}

afterFileValidate(file: BscFile) {
if (!isBrsFile(file) || this.lintContext.ignores(file)) {
return;
validateXMLFile(file: XmlFile) {
const diagnostics: Omit<BsDiagnostic, 'file'>[] = [];
const { noArrayComponentFieldType, noAssocarrayComponentFieldType } = this.lintContext.severity;

const validateArrayComponentFieldType = noArrayComponentFieldType !== DiagnosticSeverity.Hint;
const validateAssocarrayComponentFieldType = noAssocarrayComponentFieldType !== DiagnosticSeverity.Hint;

for (const field of file.parser?.ast?.component?.api?.fields ?? []) {
const { tag, attributes } = field;
if (tag.text === 'field') {
const typeAttribute = attributes.find(({ key }) => key.text === 'type');

const typeValue = typeAttribute?.value.text;
if (typeValue === 'array' && validateArrayComponentFieldType) {
diagnostics.push(
messages.noArrayFieldType(
typeAttribute.value.range,
noArrayComponentFieldType
)
);
} else if (typeValue === 'assocarray' && validateAssocarrayComponentFieldType) {
diagnostics.push(
messages.noAssocarrayFieldType(
typeAttribute.value.range,
noAssocarrayComponentFieldType
)
);
}
}
}

return diagnostics;
}

validateBrsFile(file: BrsFile) {
const diagnostics: (Omit<BsDiagnostic, 'file'>)[] = [];
const { severity, fix } = this.lintContext;
const { severity } = this.lintContext;
const { inlineIfStyle, blockIfStyle, conditionStyle, noPrint, noTodo, noStop, aaCommaStyle, eolLast, colorFormat } = severity;
const validatePrint = noPrint !== DiagnosticSeverity.Hint;
const validateTodo = noTodo !== DiagnosticSeverity.Hint;
Expand Down Expand Up @@ -163,12 +211,29 @@ export default class CodeStyle {
this.validateFunctionStyle(fun, diagnostics);
}

return diagnostics;
}

afterFileValidate(file: BscFile) {
if (this.lintContext.ignores(file)) {
return;
}

const diagnostics: (Omit<BsDiagnostic, 'file'>)[] = [];
if (isXmlFile(file)) {
diagnostics.push(...this.validateXMLFile(file));
} else if (isBrsFile(file)) {
diagnostics.push(...this.validateBrsFile(file));
}

// add file reference
let bsDiagnostics: BsDiagnostic[] = diagnostics.map(diagnostic => ({
...diagnostic,
file
}));

const { fix } = this.lintContext;

// apply fix
if (fix) {
bsDiagnostics = extractFixes(this.lintContext.addFixes, bsDiagnostics);
Expand Down
8 changes: 6 additions & 2 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ export function getDefaultRules(): BsLintConfig['rules'] {
'anon-function-style': 'auto',
'aa-comma-style': 'no-dangling',
'type-annotations': 'off',
'no-print': 'off'
'no-print': 'off',
'no-assocarray-component-field-type': 'off',
'no-array-component-field-type': 'off'
};
}

Expand Down Expand Up @@ -162,7 +164,9 @@ function rulesToSeverity(rules: BsLintConfig['rules']) {
colorCase: rules['color-case'],
colorAlpha: rules['color-alpha'],
colorAlphaDefaults: rules['color-alpha-defaults'],
colorCertCompliant: rules['color-cert']
colorCertCompliant: rules['color-cert'],
noAssocarrayComponentFieldType: ruleToSeverity(rules['no-assocarray-component-field-type']),
noArrayComponentFieldType: ruleToSeverity(rules['no-array-component-field-type'])
};
}

Expand Down
8 changes: 8 additions & 0 deletions test/project1/components/interfaceTest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<component name="interfaceTest" extends="Group">
<interface>
<field id="test" type="array" />
<field id="test2" type="node" />
<field id="test3" type="assocarray" />
</interface>
</component>

0 comments on commit 6943f2f

Please sign in to comment.