Skip to content

JavaScript Rules

This guide shows how to write a custom JavaScript rule that reads type information from typescript-go and runs on both .ts and .vue files.

You will build a js/unsafe-calls rule that reports any call where the called value has type any, then run it on the example files.

This example uses Vue so the same rule runs on a plain TypeScript file and an embedded-language file.

Terminal window
npm i -D golar @golar/vue vue

Create index.ts:

index.ts
export declare const fn: any
fn()

Create index.vue:

index.vue
<script lang="ts" setup>
import { fn } from './index.ts'
</script>
<template>
{{ fn() }}
</template>

Create js-rule.ts:

js-rule.ts
import { defineRule } from 'golar/unstable'
import {
isCallExpression,
TypeFlags,
type CallExpression,
} from 'golar/unstable-tsgo'
export const jsRule = defineRule({
name: 'js/unsafe-calls',
setup(context) {
context.sourceFile.forEachChild(function visit(node) {
if (isCallExpression(node)) {
checkCall(node)
}
node.forEachChild(visit)
})
function checkCall(node: CallExpression) {
const type = context.program.getTypeAtLocation(node.expression)
if (type == null) {
return
}
if ((type.flags & TypeFlags.Any) !== 0 && type.intrinsicName === 'any') {
context.report({
message: 'Unsafe any call.',
range: {
begin: node.expression.pos,
end: node.expression.end,
},
})
}
}
},
})

This rule works in three steps: traverse the file, ask Golar for the type of each called expression, and report an error if that type is any.

The important part is context.program.getTypeAtLocation(...). That is what makes the rule type-aware instead of syntax-only.

Create golar.config.ts:

golar.config.ts
import { defineConfig } from 'golar/unstable'
import '@golar/vue'
import { jsRule } from './js-rule.ts'
export default defineConfig({
lint: {
use: [
{
files: ['index.ts', 'index.vue'],
rules: [jsRule],
},
],
},
})

The lint.use entry tells Golar which files should use the rule.

Run Golar in the default mode:

Terminal window
npx golar

You should see js/unsafe-calls errors for both index.ts and index.vue.