Skip to content

Language support tables #2010

Open
Open
@pokey

Description

@pokey

The problem

As a contributor, it is hard to know exactly what needs to be implemented for a new language, or what is missing from an existing language. As a user, it is hard to know what our support level is for an existing language.

I really like the support tables in #1911 and #1962. We should formalize these somehow with the following goals:

  • make it easier for people to contribute languages
  • make it easier for contributors to see what's missing for a given language
  • make it harder to forget to write tests
  • make it easier for users to know what a given language supports

The solution

There are multiple levels of this solution, in increasing levels of investment

1. Add support tables to our new language PR template

This is the lowest overhead, and has the benefit that it's easy for the contributor and core maintainers to update as a PR progresses.

The drawback is that it's not helpful for users, and doesn't help as much after the initial PR. It's also not formalized in any way

2. Manually add support tables to per-language pages (#1642)

This solution is probably the highest overhead for new language contributors, but doesn't require much investment on our part, and is helpful both for users and for contributors seeing where a language is currently

It also isn't automatically enforced in any way, so could get stale / be wrong just like 1) above

We'd also want to add a checkbox to the PR template saying we've updated this page. Probably just the new-language template but could be the general template

3. Add structured representation of language scope support

We could add types that represent different aspects of scope support. Something like the following

const scopeSupportFacets = [
  "list",
  "list.interior",
  "map",
  "map.interior",
  "collectionKey",
  "namedFunction",
  "namedFunction.interior",
  "functionName",
  "anonymousFunction",
  "anonymousFunction.interior",
  "name",
  "value.assignment",
  "value.assignment.removal",
  "value.return",
  "value.return.removal",
  "value.collectionItem",
  "value.collectionItem.removal",
  "statement",
  "ifStatement",
  "condition.if",
  "condition.while",
  "condition.doWhile",
  "condition.for",
  "condition.ternary",
  "branch",
  "comment.line",
  "comment.block",
  "string.singleLine",
  "string.multiLine",
  "textFragment",
  "functionCall",
  "functionCallee",
  "argumentOrParameter.argument",
  "argumentOrParameter.argument.removal",
  "argumentOrParameter.parameter",
  "argumentOrParameter.parameter.removal",
  "class",
  "class.interior",
  "className",
  "type",
] as const;

type ScopeSupportFacet = (typeof scopeSupportFacets)[number];

interface ScopeSupportFacetInfo {
  label: string;
  description: string;
  scopeType: SimpleScopeTypeType;
}

const scopeSupportFacetInfos: Record<ScopeSupportFacet, ScopeSupportFacetInfo> =
  {
    list: {
      label: "List",
      description: "A list of items",
      scopeType: "list",
    },
    "list.interior": {
      label: "List interior",
      description: "Excludes the opening and closing delimiters of the list",
      scopeType: "list",
    },
    map: {
      label: "Map",
      description: "A map of key-value pairs",
      scopeType: "map",
    },
    "map.interior": {
      label: "Map interior",
      description: "Excludes the opening and closing delimiters of the map",
      scopeType: "map",
    },
  };

enum ScopeSupportFacetLevel {
  supported,
  unsupported,
  notApplicable,
}

type LanguageScopeSupportFacetMap = Record<
  ScopeSupportFacet,
  ScopeSupportFacetLevel
>;

const { supported, unsupported, notApplicable } = ScopeSupportFacetLevel;

// Example support table for a language
const typescriptSupport: LanguageScopeSupportFacetMap = {
  list: supported,
  "list.interior": supported,
  map: supported,
  "map.interior": supported,
  collectionKey: supported,
  namedFunction: supported,
  "namedFunction.interior": supported,
  functionName: supported,
  anonymousFunction: supported,
  "anonymousFunction.interior": supported,
  name: supported,
  "value.assignment": supported,
  "value.assignment.removal": supported,
  "value.return": supported,
  "value.return.removal": supported,
  "value.collectionItem": supported,
  "value.collectionItem.removal": supported,
  statement: supported,
  ifStatement: supported,
  "condition.if": supported,
  "condition.while": supported,
  "condition.doWhile": supported,
  "condition.for": unsupported,
  "condition.ternary": notApplicable,
};

The strong typing would force us not to forget any scopes. The above would be the source of truth from which we could generate the following:

  • Support tables for docs: add per-language pages #1642
  • Language support tables for scope pages in our docs
  • Examples of different aspects of support in our docs, using test cases

We could also check that test cases exist by adding an optional supportFacet field to our recorded test cases, and then checking in CI for a test case that mentions any support face that is marked as supported

Metadata

Metadata

Assignees

No one assigned

    Labels

    code qualityImprovements to code quality

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions