From 8893d8e2307b7dd05152984b95cd445698254181 Mon Sep 17 00:00:00 2001 From: Thomas Neidhart Date: Sun, 13 Aug 2023 11:16:33 +0200 Subject: [PATCH 1/2] Optimize runtime complexity of linter when passing in multiple snippets. --- linter/linter.go | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/linter/linter.go b/linter/linter.go index 1437ba1f0..c7838848d 100644 --- a/linter/linter.go +++ b/linter/linter.go @@ -2,12 +2,13 @@ package linter import ( - "io" - jsonnet "github.com/google/go-jsonnet" "github.com/google/go-jsonnet/ast" "github.com/google/go-jsonnet/internal/errors" "github.com/google/go-jsonnet/internal/parser" + "io" + "path/filepath" + "strings" "github.com/google/go-jsonnet/linter/internal/common" "github.com/google/go-jsonnet/linter/internal/traversal" @@ -45,14 +46,6 @@ type nodeWithLocation struct { // Lint analyses a node and reports any issues it encounters to an error writer. func lint(vm *jsonnet.VM, nodes []nodeWithLocation, errWriter *ErrorWriter) { - roots := make(map[string]ast.Node) - for _, node := range nodes { - roots[node.path] = node.node - } - for _, node := range nodes { - getImports(vm, node, roots, errWriter) - } - variablesInFile := make(map[string]common.VariableInfo) std := common.Variable{ @@ -65,16 +58,20 @@ func lint(vm *jsonnet.VM, nodes []nodeWithLocation, errWriter *ErrorWriter) { return variables.FindVariables(node.node, variables.Environment{"std": &std, "$std": &std}) } - for importedPath, rootNode := range roots { - variablesInFile[importedPath] = *findVariables(nodeWithLocation{rootNode, importedPath}) - } + for _, node := range nodes { + roots := make(map[string]ast.Node) + roots[node.path] = node.node + getImports(vm, node, roots, errWriter) - vars := make(map[string]map[ast.Node]*common.Variable) - for importedPath, info := range variablesInFile { - vars[importedPath] = info.VarAt - } + for importedPath, rootNode := range roots { + variablesInFile[importedPath] = *findVariables(nodeWithLocation{rootNode, importedPath}) + } + + vars := make(map[string]map[ast.Node]*common.Variable) + for importedPath, info := range variablesInFile { + vars[importedPath] = info.VarAt + } - for _, node := range nodes { variableInfo := findVariables(node) for _, v := range variableInfo.Variables { @@ -85,6 +82,20 @@ func lint(vm *jsonnet.VM, nodes []nodeWithLocation, errWriter *ErrorWriter) { ec := common.ErrCollector{} types.Check(node.node, roots, vars, func(currentPath, importedPath string) ast.Node { + // try to resolve the imported node from the already calculated list of roots + // if this fails, reimport the node + idx := strings.LastIndex(currentPath, "/") + var currentDir = "" + if idx != -1 { + currentDir = currentPath[:idx] + } + + relativePath := filepath.Join(currentDir, importedPath) + node := roots[relativePath] + if node != nil { + return node + } + node, _, err := vm.ImportAST(currentPath, importedPath) if err != nil { return nil From 23a013c3a59532ccfea84e55d1b85aedc7858180 Mon Sep 17 00:00:00 2001 From: John Bartholomew Date: Tue, 27 Jan 2026 18:32:08 +0000 Subject: [PATCH 2/2] linter: rely on ImportAST internal caching, isolate variables for each snippet --- linter/linter.go | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/linter/linter.go b/linter/linter.go index c7838848d..0d83e5174 100644 --- a/linter/linter.go +++ b/linter/linter.go @@ -2,13 +2,12 @@ package linter import ( + "io" + jsonnet "github.com/google/go-jsonnet" "github.com/google/go-jsonnet/ast" "github.com/google/go-jsonnet/internal/errors" "github.com/google/go-jsonnet/internal/parser" - "io" - "path/filepath" - "strings" "github.com/google/go-jsonnet/linter/internal/common" "github.com/google/go-jsonnet/linter/internal/traversal" @@ -46,25 +45,22 @@ type nodeWithLocation struct { // Lint analyses a node and reports any issues it encounters to an error writer. func lint(vm *jsonnet.VM, nodes []nodeWithLocation, errWriter *ErrorWriter) { - variablesInFile := make(map[string]common.VariableInfo) - std := common.Variable{ Name: "std", Occurences: nil, VariableKind: common.VarStdlib, } - findVariables := func(node nodeWithLocation) *common.VariableInfo { - return variables.FindVariables(node.node, variables.Environment{"std": &std, "$std": &std}) - } + stdEnv := variables.Environment{"std": &std, "$std": &std} for _, node := range nodes { roots := make(map[string]ast.Node) roots[node.path] = node.node getImports(vm, node, roots, errWriter) + variablesInFile := make(map[string]common.VariableInfo) for importedPath, rootNode := range roots { - variablesInFile[importedPath] = *findVariables(nodeWithLocation{rootNode, importedPath}) + variablesInFile[importedPath] = *variables.FindVariables(rootNode, stdEnv) } vars := make(map[string]map[ast.Node]*common.Variable) @@ -72,9 +68,7 @@ func lint(vm *jsonnet.VM, nodes []nodeWithLocation, errWriter *ErrorWriter) { vars[importedPath] = info.VarAt } - variableInfo := findVariables(node) - - for _, v := range variableInfo.Variables { + for _, v := range variablesInFile[node.path].Variables { if len(v.Occurences) == 0 && v.VariableKind == common.VarRegular && v.Name != "$" { errWriter.writeError(vm, errors.MakeStaticError("Unused variable: "+string(v.Name), v.LocRange)) } @@ -82,20 +76,6 @@ func lint(vm *jsonnet.VM, nodes []nodeWithLocation, errWriter *ErrorWriter) { ec := common.ErrCollector{} types.Check(node.node, roots, vars, func(currentPath, importedPath string) ast.Node { - // try to resolve the imported node from the already calculated list of roots - // if this fails, reimport the node - idx := strings.LastIndex(currentPath, "/") - var currentDir = "" - if idx != -1 { - currentDir = currentPath[:idx] - } - - relativePath := filepath.Join(currentDir, importedPath) - node := roots[relativePath] - if node != nil { - return node - } - node, _, err := vm.ImportAST(currentPath, importedPath) if err != nil { return nil