Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions tsc/internal/format/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ node the covers the span of text and recurses down through the node's children.
As it recurses, `processNode` is called on the children setting the indentation is decided and passed
through into each of that node's children.

The meat of formatting decisions is made via `processPair`, the pair here being the current node and the previous node. `processPair` which mutates the formatting context to represent the current place in the scanner and requests a set of rules which can be applied to the items via `createRulesMap`.
The meat of formatting decisions is made via `processPair`, the pair here being the current node and the previous node. `processPair` which mutates the formatting context to represent the current place in the scanner and requests a set of rules which can be applied to the items via `getRules`, from the map `buildRulesMap` builds once.

There are a lot of rules, which you can find in [rules.ts](./rules.ts) each one has a left and right reference to nodes or token ranges and note of what action should be applied by the formatter.
There are a lot of rules, which you can find in [rules.go](./rules.go) each one has a left and right reference to nodes or token ranges and note of what action should be applied by the formatter.

### Where is this used?

Expand Down
105 changes: 105 additions & 0 deletions tsc/internal/format/readme_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package format_test

import (
"go/ast"
"go/parser"
"go/token"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
)

var (
readmeLinkRe = regexp.MustCompile(`\]\(([^)#\s]+)(?:#[^)]*)?\)`)
readmeCodeRe = regexp.MustCompile("`([^`]+)`")
identRe = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*\*?$`)
)

// TestReadmeMatchesCode checks that README.md in this package does not refer to
// files or identifiers that no longer exist, such as names left over from the
// TypeScript 6 code base.
func TestReadmeMatchesCode(t *testing.T) {
t.Parallel()

content, err := os.ReadFile("README.md")
if err != nil {
t.Fatal(err)
}
readme := string(content)

for _, m := range readmeLinkRe.FindAllStringSubmatch(readme, -1) {
target := m[1]
if strings.Contains(target, "://") {
continue
}
if _, err := os.Stat(filepath.FromSlash(target)); err != nil {
t.Errorf("README.md links to %q, which does not exist", target)
}
}

names := packageNames(t)
for _, m := range readmeCodeRe.FindAllStringSubmatch(readme, -1) {
name := m[1]
if !identRe.MatchString(name) {
continue
}
if !names.has(name) {
t.Errorf("README.md mentions `%s`, which is not declared or used in this package", name)
}
}
}

type nameSet map[string]struct{}

// has reports whether name is in the set. A trailing "*" matches any name with that prefix.
func (s nameSet) has(name string) bool {
if prefix, ok := strings.CutSuffix(name, "*"); ok {
for n := range s {
if strings.HasPrefix(n, prefix) {
return true
}
}
return false
}
_, ok := s[name]
return ok
}

// packageNames collects the names declared in this package's non-test files,
// along with the names it uses from other packages (such as ast.SourceFile).
func packageNames(t *testing.T) nameSet {
t.Helper()
files, err := filepath.Glob("*.go")
if err != nil {
t.Fatal(err)
}
names := nameSet{}
fset := token.NewFileSet()
for _, file := range files {
if strings.HasSuffix(file, "_test.go") {
continue
}
f, err := parser.ParseFile(fset, file, nil, parser.SkipObjectResolution)
if err != nil {
t.Fatal(err)
}
ast.Inspect(f, func(n ast.Node) bool {
switch n := n.(type) {
case *ast.FuncDecl:
names[n.Name.Name] = struct{}{}
case *ast.TypeSpec:
names[n.Name.Name] = struct{}{}
case *ast.ValueSpec:
for _, id := range n.Names {
names[id.Name] = struct{}{}
}
case *ast.SelectorExpr:
names[n.Sel.Name] = struct{}{}
}
return true
})
}
return names
}