mirror of
https://github.com/sasjs/lint.git
synced 2025-12-10 17:34:36 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb7f70e83a | ||
|
|
7f9ed5e61e | ||
|
|
63255fa3c8 | ||
|
|
00af205a55 | ||
|
|
e74663ba54 | ||
|
|
a9cb4d8dac | ||
|
|
ed58b288b5 | ||
|
|
be173d2e2b | ||
|
|
3e4809c352 | ||
|
|
f0ab349bf7 | ||
|
|
0c5588023d | ||
|
|
8badfd9358 | ||
| 0dfd1fb85b |
23
README.md
23
README.md
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
Our goal is to help SAS developers everywhere spend less time on code reviews, bug fixing and arguing about standards - and more time delivering extraordinary business value.
|
Our goal is to help SAS developers everywhere spend less time on code reviews, bug fixing and arguing about standards - and more time delivering extraordinary business value.
|
||||||
|
|
||||||
|
*Note:* The SASjs project and its repositories are not affiliated with SAS Institute.
|
||||||
|
|
||||||
# Linting
|
# Linting
|
||||||
|
|
||||||
@sasjs/lint is used by the following products:
|
@sasjs/lint is used by the following products:
|
||||||
@@ -252,6 +254,21 @@ This will highlight lines with trailing spaces. Trailing spaces serve no useful
|
|||||||
- Default: true
|
- Default: true
|
||||||
- severity: WARNING
|
- severity: WARNING
|
||||||
|
|
||||||
|
### hasRequiredMacroOptions
|
||||||
|
|
||||||
|
This will require macros to have the options listed as "requiredMacroOptions." This is helpful if you want to ensure all macros are SECURE.
|
||||||
|
|
||||||
|
- Default: false
|
||||||
|
- severity: WARNING
|
||||||
|
|
||||||
|
Example
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"hasRequiredMacroOptions": true,
|
||||||
|
"requiredMacroOptions": ["SECURE", "SRC"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## severityLevel
|
## severityLevel
|
||||||
|
|
||||||
This setting allows the default severity to be adjusted. This is helpful when running the lint in a pipeline or git hook. Simply list the rules you would like to adjust along with the desired setting ("warn" or "error"), eg as follows:
|
This setting allows the default severity to be adjusted. This is helpful when running the lint in a pipeline or git hook. Simply list the rules you would like to adjust along with the desired setting ("warn" or "error"), eg as follows:
|
||||||
@@ -290,6 +307,12 @@ We're looking to implement the following rules:
|
|||||||
|
|
||||||
We are also investigating some harder stuff, such as automatic indentation and code layout
|
We are also investigating some harder stuff, such as automatic indentation and code layout
|
||||||
|
|
||||||
|
# Further resources
|
||||||
|
|
||||||
|
* Using the linter on terminal: https://vid.4gl.io/w/vmJspCjcBoc5QtzwZkZRvi
|
||||||
|
* Longer intro to sasjs lint: https://vid.4gl.io/w/nDtkQFV1E8rtaa2BuM6U5s
|
||||||
|
* CLI docs: https://cli.sasjs.io/lint
|
||||||
|
|
||||||
# Sponsorship & Contributions
|
# Sponsorship & Contributions
|
||||||
|
|
||||||
SASjs is an open source framework! Contributions are welcomed. If you would like to see a feature, because it would be useful in your project, but you don't have the requisite (Typescript) experience - then how about you engage us on a short project and we build it for you?
|
SASjs is an open source framework! Contributions are welcomed. If you would like to see a feature, because it would be useful in your project, but you don't have the requisite (Typescript) experience - then how about you engage us on a short project and we build it for you?
|
||||||
|
|||||||
@@ -22,7 +22,9 @@
|
|||||||
"noTrailingSpaces": true,
|
"noTrailingSpaces": true,
|
||||||
"lineEndings": "off",
|
"lineEndings": "off",
|
||||||
"strictMacroDefinition": true,
|
"strictMacroDefinition": true,
|
||||||
"ignoreList": ["sajsbuild", "sasjsresults"]
|
"ignoreList": ["sajsbuild", "sasjsresults"],
|
||||||
|
"hasRequiredMacroOptions": false,
|
||||||
|
"requiredMacroOptions": []
|
||||||
},
|
},
|
||||||
"examples": [
|
"examples": [
|
||||||
{
|
{
|
||||||
@@ -43,7 +45,9 @@
|
|||||||
"hasMacroParentheses": true,
|
"hasMacroParentheses": true,
|
||||||
"lineEndings": "crlf",
|
"lineEndings": "crlf",
|
||||||
"strictMacroDefinition": true,
|
"strictMacroDefinition": true,
|
||||||
"ignoreList": ["sajsbuild", "sasjsresults"]
|
"ignoreList": ["sajsbuild", "sasjsresults"],
|
||||||
|
"hasRequiredMacroOptions": false,
|
||||||
|
"requiredMacroOptions": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -204,6 +208,22 @@
|
|||||||
"default": ["sasjsbuild/", "sasjsresults/"],
|
"default": ["sasjsbuild/", "sasjsresults/"],
|
||||||
"examples": ["sasjs/tests", "tmp/scratch.sas"]
|
"examples": ["sasjs/tests", "tmp/scratch.sas"]
|
||||||
},
|
},
|
||||||
|
"hasRequiredMacroOptions": {
|
||||||
|
"$id": "#/properties/hasRequiredMacroOptions",
|
||||||
|
"type": "boolean",
|
||||||
|
"title": "hasRequiredMacroOptions",
|
||||||
|
"description": "Enforces required macro options as defined by requiredMacroOptions",
|
||||||
|
"default": false,
|
||||||
|
"examples": [true, false]
|
||||||
|
},
|
||||||
|
"requiredMacroOptions": {
|
||||||
|
"$id": "#/properties/requiredMacroOptions",
|
||||||
|
"type": "array",
|
||||||
|
"title": "requiredMacroOptions",
|
||||||
|
"description": "An array of macro options to require all macros to include.",
|
||||||
|
"default": [],
|
||||||
|
"examples": ["['SECURE']", "['SRC', 'STMT']"]
|
||||||
|
},
|
||||||
"severityLevel": {
|
"severityLevel": {
|
||||||
"$id": "#/properties/severityLevel",
|
"$id": "#/properties/severityLevel",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -320,6 +340,13 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["error", "warn"],
|
"enum": ["error", "warn"],
|
||||||
"default": "warn"
|
"default": "warn"
|
||||||
|
},
|
||||||
|
"hasRequiredMacroOptions": {
|
||||||
|
"$id": "#/properties/severityLevel/hasRequiredMacroOptions",
|
||||||
|
"title": "hasRequiredMacroOptions",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["error", "warn"],
|
||||||
|
"default": "warn"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const lintFile = async (
|
|||||||
filePath: string,
|
filePath: string,
|
||||||
configuration?: LintConfig
|
configuration?: LintConfig
|
||||||
): Promise<Diagnostic[]> => {
|
): Promise<Diagnostic[]> => {
|
||||||
if (await isIgnored(filePath)) return []
|
if (await isIgnored(filePath, configuration)) return []
|
||||||
|
|
||||||
const config = configuration || (await getLintConfig())
|
const config = configuration || (await getLintConfig())
|
||||||
const text = await readFile(filePath)
|
const text = await readFile(filePath)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const lintFolder = async (
|
|||||||
const config = configuration || (await getLintConfig())
|
const config = configuration || (await getLintConfig())
|
||||||
let diagnostics: Map<string, Diagnostic[]> = new Map<string, Diagnostic[]>()
|
let diagnostics: Map<string, Diagnostic[]> = new Map<string, Diagnostic[]>()
|
||||||
|
|
||||||
if (await isIgnored(folderPath)) return diagnostics
|
if (await isIgnored(folderPath, config)) return diagnostics
|
||||||
|
|
||||||
const fileNames = await listSasFiles(folderPath)
|
const fileNames = await listSasFiles(folderPath)
|
||||||
await asyncForEach(fileNames, async (fileName) => {
|
await asyncForEach(fileNames, async (fileName) => {
|
||||||
|
|||||||
123
src/rules/file/hasRequiredMacroOptions.spec.ts
Normal file
123
src/rules/file/hasRequiredMacroOptions.spec.ts
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
import { LintConfig, Severity } from '../../types'
|
||||||
|
import { hasRequiredMacroOptions } from './hasRequiredMacroOptions'
|
||||||
|
|
||||||
|
describe('hasRequiredMacroOptions - test', () => {
|
||||||
|
it('should return an empty array when the content has the required macro option(s)', () => {
|
||||||
|
const contentSecure = '%macro somemacro/ SECURE;'
|
||||||
|
const configSecure = new LintConfig({
|
||||||
|
hasRequiredMacroOptions: true,
|
||||||
|
requiredMacroOptions: ['SECURE']
|
||||||
|
})
|
||||||
|
expect(hasRequiredMacroOptions.test(contentSecure, configSecure)).toEqual(
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
|
||||||
|
const contentSecureSrc = '%macro somemacro/ SECURE SRC;'
|
||||||
|
const configSecureSrc = new LintConfig({
|
||||||
|
hasRequiredMacroOptions: true,
|
||||||
|
requiredMacroOptions: ['SECURE', 'SRC']
|
||||||
|
})
|
||||||
|
expect(
|
||||||
|
hasRequiredMacroOptions.test(contentSecureSrc, configSecureSrc)
|
||||||
|
).toEqual([])
|
||||||
|
|
||||||
|
const configEmpty = new LintConfig({
|
||||||
|
hasRequiredMacroOptions: true,
|
||||||
|
requiredMacroOptions: ['']
|
||||||
|
})
|
||||||
|
expect(hasRequiredMacroOptions.test(contentSecureSrc, configEmpty)).toEqual(
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an array with a single diagnostic when Macro does not contain the required option', () => {
|
||||||
|
const configSecure = new LintConfig({
|
||||||
|
hasRequiredMacroOptions: true,
|
||||||
|
requiredMacroOptions: ['SECURE']
|
||||||
|
})
|
||||||
|
|
||||||
|
const contentMinXOperator = '%macro somemacro(var1, var2)/minXoperator;'
|
||||||
|
expect(
|
||||||
|
hasRequiredMacroOptions.test(contentMinXOperator, configSecure)
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
message: `Macro 'somemacro' does not contain the required option 'SECURE'`,
|
||||||
|
lineNumber: 1,
|
||||||
|
startColumnNumber: 0,
|
||||||
|
endColumnNumber: 0,
|
||||||
|
severity: Severity.Warning
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const contentSecureSplit = '%macro somemacro(var1, var2)/ SE CURE;'
|
||||||
|
expect(
|
||||||
|
hasRequiredMacroOptions.test(contentSecureSplit, configSecure)
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
message: `Macro 'somemacro' does not contain the required option 'SECURE'`,
|
||||||
|
lineNumber: 1,
|
||||||
|
startColumnNumber: 0,
|
||||||
|
endColumnNumber: 0,
|
||||||
|
severity: Severity.Warning
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const contentNoOption = '%macro somemacro(var1, var2);'
|
||||||
|
expect(hasRequiredMacroOptions.test(contentNoOption, configSecure)).toEqual(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
message: `Macro 'somemacro' does not contain the required option 'SECURE'`,
|
||||||
|
lineNumber: 1,
|
||||||
|
startColumnNumber: 0,
|
||||||
|
endColumnNumber: 0,
|
||||||
|
severity: Severity.Warning
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an array with a two diagnostics when Macro does not contain the required options', () => {
|
||||||
|
const configSrcStmt = new LintConfig({
|
||||||
|
hasRequiredMacroOptions: true,
|
||||||
|
requiredMacroOptions: ['SRC', 'STMT'],
|
||||||
|
severityLevel: { hasRequiredMacroOptions: 'warn' }
|
||||||
|
})
|
||||||
|
const contentMinXOperator = '%macro somemacro(var1, var2)/minXoperator;'
|
||||||
|
expect(
|
||||||
|
hasRequiredMacroOptions.test(contentMinXOperator, configSrcStmt)
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
message: `Macro 'somemacro' does not contain the required option 'SRC'`,
|
||||||
|
lineNumber: 1,
|
||||||
|
startColumnNumber: 0,
|
||||||
|
endColumnNumber: 0,
|
||||||
|
severity: Severity.Warning
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: `Macro 'somemacro' does not contain the required option 'STMT'`,
|
||||||
|
lineNumber: 1,
|
||||||
|
startColumnNumber: 0,
|
||||||
|
endColumnNumber: 0,
|
||||||
|
severity: Severity.Warning
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return an array with a one diagnostic when Macro contains 1 of 2 required options', () => {
|
||||||
|
const configSrcStmt = new LintConfig({
|
||||||
|
hasRequiredMacroOptions: true,
|
||||||
|
requiredMacroOptions: ['SRC', 'STMT'],
|
||||||
|
severityLevel: { hasRequiredMacroOptions: 'error' }
|
||||||
|
})
|
||||||
|
const contentSrc = '%macro somemacro(var1, var2)/ SRC;'
|
||||||
|
expect(hasRequiredMacroOptions.test(contentSrc, configSrcStmt)).toEqual([
|
||||||
|
{
|
||||||
|
message: `Macro 'somemacro' does not contain the required option 'STMT'`,
|
||||||
|
lineNumber: 1,
|
||||||
|
startColumnNumber: 0,
|
||||||
|
endColumnNumber: 0,
|
||||||
|
severity: Severity.Error
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
52
src/rules/file/hasRequiredMacroOptions.ts
Normal file
52
src/rules/file/hasRequiredMacroOptions.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { Diagnostic, LintConfig, Macro, Severity } from '../../types'
|
||||||
|
import { FileLintRule } from '../../types/LintRule'
|
||||||
|
import { LintRuleType } from '../../types/LintRuleType'
|
||||||
|
import { parseMacros } from '../../utils/parseMacros'
|
||||||
|
|
||||||
|
const name = 'hasRequiredMacroOptions'
|
||||||
|
const description = 'Enforce required macro options'
|
||||||
|
const message = 'Macro defined without required options'
|
||||||
|
|
||||||
|
const processOptions = (
|
||||||
|
macro: Macro,
|
||||||
|
diagnostics: Diagnostic[],
|
||||||
|
config?: LintConfig
|
||||||
|
): void => {
|
||||||
|
const optionsPresent = macro.declaration.split('/')?.[1]?.trim() ?? ''
|
||||||
|
const severity = config?.severityLevel[name] || Severity.Warning
|
||||||
|
|
||||||
|
config?.requiredMacroOptions.forEach((option) => {
|
||||||
|
if (!optionsPresent.includes(option)) {
|
||||||
|
diagnostics.push({
|
||||||
|
message: `Macro '${macro.name}' does not contain the required option '${option}'`,
|
||||||
|
lineNumber: macro.startLineNumbers[0],
|
||||||
|
startColumnNumber: 0,
|
||||||
|
endColumnNumber: 0,
|
||||||
|
severity
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const test = (value: string, config?: LintConfig) => {
|
||||||
|
const diagnostics: Diagnostic[] = []
|
||||||
|
|
||||||
|
const macros = parseMacros(value, config)
|
||||||
|
|
||||||
|
macros.forEach((macro) => {
|
||||||
|
processOptions(macro, diagnostics, config)
|
||||||
|
})
|
||||||
|
|
||||||
|
return diagnostics
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lint rule that checks if a macro has the required options
|
||||||
|
*/
|
||||||
|
export const hasRequiredMacroOptions: FileLintRule = {
|
||||||
|
type: LintRuleType.File,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
message,
|
||||||
|
test
|
||||||
|
}
|
||||||
@@ -4,3 +4,4 @@ export { hasMacroParentheses } from './hasMacroParentheses'
|
|||||||
export { lineEndings } from './lineEndings'
|
export { lineEndings } from './lineEndings'
|
||||||
export { noNestedMacros } from './noNestedMacros'
|
export { noNestedMacros } from './noNestedMacros'
|
||||||
export { strictMacroDefinition } from './strictMacroDefinition'
|
export { strictMacroDefinition } from './strictMacroDefinition'
|
||||||
|
export { hasRequiredMacroOptions } from './hasRequiredMacroOptions'
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { hasRequiredMacroOptions } from '../rules/file'
|
||||||
import { LineEndings } from './LineEndings'
|
import { LineEndings } from './LineEndings'
|
||||||
import { LintConfig } from './LintConfig'
|
import { LintConfig } from './LintConfig'
|
||||||
import { LintRuleType } from './LintRuleType'
|
import { LintRuleType } from './LintRuleType'
|
||||||
@@ -168,6 +169,7 @@ describe('LintConfig', () => {
|
|||||||
hasMacroNameInMend: true,
|
hasMacroNameInMend: true,
|
||||||
noNestedMacros: true,
|
noNestedMacros: true,
|
||||||
hasMacroParentheses: true,
|
hasMacroParentheses: true,
|
||||||
|
hasRequiredMacroOptions: true,
|
||||||
noGremlins: true,
|
noGremlins: true,
|
||||||
lineEndings: 'lf'
|
lineEndings: 'lf'
|
||||||
})
|
})
|
||||||
@@ -187,7 +189,7 @@ describe('LintConfig', () => {
|
|||||||
expect(config.lineLintRules[5].name).toEqual('noGremlins')
|
expect(config.lineLintRules[5].name).toEqual('noGremlins')
|
||||||
expect(config.lineLintRules[5].type).toEqual(LintRuleType.Line)
|
expect(config.lineLintRules[5].type).toEqual(LintRuleType.Line)
|
||||||
|
|
||||||
expect(config.fileLintRules.length).toEqual(6)
|
expect(config.fileLintRules.length).toEqual(7)
|
||||||
expect(config.fileLintRules[0].name).toEqual('lineEndings')
|
expect(config.fileLintRules[0].name).toEqual('lineEndings')
|
||||||
expect(config.fileLintRules[0].type).toEqual(LintRuleType.File)
|
expect(config.fileLintRules[0].type).toEqual(LintRuleType.File)
|
||||||
expect(config.fileLintRules[1].name).toEqual('hasDoxygenHeader')
|
expect(config.fileLintRules[1].name).toEqual('hasDoxygenHeader')
|
||||||
@@ -200,6 +202,8 @@ describe('LintConfig', () => {
|
|||||||
expect(config.fileLintRules[4].type).toEqual(LintRuleType.File)
|
expect(config.fileLintRules[4].type).toEqual(LintRuleType.File)
|
||||||
expect(config.fileLintRules[5].name).toEqual('strictMacroDefinition')
|
expect(config.fileLintRules[5].name).toEqual('strictMacroDefinition')
|
||||||
expect(config.fileLintRules[5].type).toEqual(LintRuleType.File)
|
expect(config.fileLintRules[5].type).toEqual(LintRuleType.File)
|
||||||
|
expect(config.fileLintRules[6].name).toEqual('hasRequiredMacroOptions')
|
||||||
|
expect(config.fileLintRules[6].type).toEqual(LintRuleType.File)
|
||||||
|
|
||||||
expect(config.pathLintRules.length).toEqual(2)
|
expect(config.pathLintRules.length).toEqual(2)
|
||||||
expect(config.pathLintRules[0].name).toEqual('noSpacesInFileNames')
|
expect(config.pathLintRules[0].name).toEqual('noSpacesInFileNames')
|
||||||
@@ -207,4 +211,25 @@ describe('LintConfig', () => {
|
|||||||
expect(config.pathLintRules[1].name).toEqual('lowerCaseFileNames')
|
expect(config.pathLintRules[1].name).toEqual('lowerCaseFileNames')
|
||||||
expect(config.pathLintRules[1].type).toEqual(LintRuleType.Path)
|
expect(config.pathLintRules[1].type).toEqual(LintRuleType.Path)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should throw an error with an invalid value for requiredMacroOptions', () => {
|
||||||
|
expect(
|
||||||
|
() =>
|
||||||
|
new LintConfig({
|
||||||
|
hasRequiredMacroOptions: true,
|
||||||
|
requiredMacroOptions: 'test'
|
||||||
|
})
|
||||||
|
).toThrowError(
|
||||||
|
`Property "requiredMacroOptions" can only be an array of strings.`
|
||||||
|
)
|
||||||
|
expect(
|
||||||
|
() =>
|
||||||
|
new LintConfig({
|
||||||
|
hasRequiredMacroOptions: true,
|
||||||
|
requiredMacroOptions: ['test', 2]
|
||||||
|
})
|
||||||
|
).toThrowError(
|
||||||
|
`Property "requiredMacroOptions" has invalid type of values. It can only contain strings.`
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import {
|
|||||||
noNestedMacros,
|
noNestedMacros,
|
||||||
hasMacroParentheses,
|
hasMacroParentheses,
|
||||||
lineEndings,
|
lineEndings,
|
||||||
strictMacroDefinition
|
strictMacroDefinition,
|
||||||
|
hasRequiredMacroOptions
|
||||||
} from '../rules/file'
|
} from '../rules/file'
|
||||||
import {
|
import {
|
||||||
indentationMultiple,
|
indentationMultiple,
|
||||||
@@ -40,6 +41,7 @@ export class LintConfig {
|
|||||||
readonly lineEndings: LineEndings = LineEndings.LF
|
readonly lineEndings: LineEndings = LineEndings.LF
|
||||||
readonly defaultHeader: string = getDefaultHeader()
|
readonly defaultHeader: string = getDefaultHeader()
|
||||||
readonly severityLevel: { [key: string]: Severity } = {}
|
readonly severityLevel: { [key: string]: Severity } = {}
|
||||||
|
readonly requiredMacroOptions: string[] = []
|
||||||
|
|
||||||
constructor(json?: any) {
|
constructor(json?: any) {
|
||||||
if (json?.ignoreList) {
|
if (json?.ignoreList) {
|
||||||
@@ -132,6 +134,31 @@ export class LintConfig {
|
|||||||
this.fileLintRules.push(strictMacroDefinition)
|
this.fileLintRules.push(strictMacroDefinition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (json?.hasRequiredMacroOptions) {
|
||||||
|
this.fileLintRules.push(hasRequiredMacroOptions)
|
||||||
|
|
||||||
|
if (json?.requiredMacroOptions) {
|
||||||
|
if (
|
||||||
|
Array.isArray(json.requiredMacroOptions) &&
|
||||||
|
json.requiredMacroOptions.length > 0
|
||||||
|
) {
|
||||||
|
json.requiredMacroOptions.forEach((item: any) => {
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
this.requiredMacroOptions.push(item)
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Property "requiredMacroOptions" has invalid type of values. It can only contain strings.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Property "requiredMacroOptions" can only be an array of strings.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (json?.noGremlins !== false) {
|
if (json?.noGremlins !== false) {
|
||||||
this.lineLintRules.push(noGremlins)
|
this.lineLintRules.push(noGremlins)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user