File size: 1,604 Bytes
048b1e8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import {
  createRule,
  getDiscriminator,
  getTypeName,
  isTemplateInstance,
  paramMessage,
} from '@typespec/compiler'
import { SyntaxKind } from '@typespec/compiler/ast'

export const compositionOverInheritanceRule = createRule({
  name: 'composition-over-inheritance',
  description:
    'Check that if a model is used in an operation and has derived models that it has a discriminator or recommend to use composition via spread or `is`.',
  severity: 'warning',
  messages: {
    default: paramMessage`Model '${'name'}' is extending '${'baseModel'}' that doesn't define a discriminator. If '${'baseModel'}' is meant to be used:
 - For composition consider using spread \`...\` or \`model is\` instead.
 - As a polymorphic relation, add the \`@discriminator\` decorator on the base model.`,
    instance: paramMessage`Model '${'name'}' is extending a template '${'baseModel'}'. Consider using composition with spread \`...\` or \`model is\` instead.`,
  },
  create(context) {
    return {
      model: (model) => {
        if (
          model.baseModel &&
          model.node?.kind === SyntaxKind.ModelStatement &&
          model.node.extends &&
          getDiscriminator(context.program, model.baseModel) === undefined
        ) {
          context.reportDiagnostic({
            messageId: isTemplateInstance(model.baseModel)
              ? 'instance'
              : 'default',
            format: {
              name: model.name,
              baseModel: getTypeName(model.baseModel),
            },
            target: model.node.extends,
          })
        }
      },
    }
  },
})