Repository: ysugimoto/falco
Pull request #190 (2023-10-07 12:13:59)

Divide snippet package
This PR implements:

-  fetching logging endpoint for a future work
-  divide Fastly managed snippets to `snippets` package


Patch:
diff --git a/cmd/falco/main.go b/cmd/falco/main.go
index bf3a7b4..e1e4a74 100644
--- a/cmd/falco/main.go
+++ b/cmd/falco/main.go
@@ -6,6 +6,7 @@ import (
 	"os"
 	"path/filepath"
 	"strings"
+	"time"
 
 	"encoding/json"
 
@@ -16,7 +17,9 @@ import (
 	"github.com/ysugimoto/falco/config"
 	ife "github.com/ysugimoto/falco/interpreter/function/errors"
 	"github.com/ysugimoto/falco/lexer"
+	"github.com/ysugimoto/falco/remote"
 	"github.com/ysugimoto/falco/resolver"
+	"github.com/ysugimoto/falco/snippets"
 	"github.com/ysugimoto/falco/terraform"
 	"github.com/ysugimoto/falco/tester"
 	"github.com/ysugimoto/falco/token"
@@ -72,7 +75,7 @@ func main() {
 		os.Exit(1)
 	}
 
-	var fetcher Fetcher
+	var fetcher snippets.Fetcher
 	var action string
 	// falco could lint multiple services so resolver should be a slice
 	var resolvers []resolver.Resolver
@@ -102,6 +105,23 @@ func main() {
 		}
 	}
 
+	if c.Remote {
+		if !c.Json {
+			writeln(cyan, "Remote option supplied. Fetching snippets from Fastly.")
+		}
+		// If remote flag is provided, fetch predefined data from Fastly.
+		//
+		// We communicate Fastly API with service id and api key,
+		// lookup fixed environment variable, FASTLY_SERVICE_ID and FASTLY_API_KEY
+		// So user needs to set them with "-r" argument.
+		if c.FastlyServiceID == "" || c.FastlyApiKey == "" {
+			writeln(red, "Both FASTLY_SERVICE_ID and FASTLY_API_KEY environment variables must be specified")
+			os.Exit(1)
+		}
+		// Create remote fetcher
+		fetcher = remote.NewFastlyApiFetcher(c.FastlyServiceID, c.FastlyApiKey, 5*time.Second)
+	}
+
 	if err != nil {
 		writeln(red, err.Error())
 		os.Exit(1)
@@ -109,6 +129,17 @@ func main() {
 
 	var shouldExit bool
 	for _, v := range resolvers {
+		if name := v.Name(); name != "" {
+			writeln(white, `Lint service of "%s"`, name)
+			writeln(white, strings.Repeat("=", 18+len(name)))
+
+			// If fetcher is instance of TerraformFetcher, set name to filter service
+			if fetcher != nil {
+				if t, ok := fetcher.(*terraform.TerraformFetcher); ok {
+					t.SetName(name)
+				}
+			}
+		}
 		runner, err := NewRunner(c, fetcher)
 		if err != nil {
 			writeln(red, err.Error())
@@ -124,10 +155,6 @@ func main() {
 		case subcommandStats:
 			exitErr = runStats(runner, v)
 		default:
-			if name := v.Name(); name != "" {
-				writeln(white, `Lint service of "%s"`, name)
-				writeln(white, strings.Repeat("=", 18+len(name)))
-			}
 			exitErr = runLint(runner, v)
 		}
 
diff --git a/cmd/falco/runner.go b/cmd/falco/runner.go
index 25261db..9c2686f 100644
--- a/cmd/falco/runner.go
+++ b/cmd/falco/runner.go
@@ -5,7 +5,6 @@ import (
 	"fmt"
 	"net/http"
 	"strings"
-	"time"
 
 	"github.com/fatih/color"
 	"github.com/pkg/errors"
@@ -19,8 +18,8 @@ import (
 	"github.com/ysugimoto/falco/linter"
 	"github.com/ysugimoto/falco/parser"
 	"github.com/ysugimoto/falco/plugin"
-	"github.com/ysugimoto/falco/remote"
 	"github.com/ysugimoto/falco/resolver"
+	"github.com/ysugimoto/falco/snippets"
 	"github.com/ysugimoto/falco/tester"
 	"github.com/ysugimoto/falco/types"
 )
@@ -77,7 +76,7 @@ type Runner struct {
 	transformers []*Transformer
 	overrides    map[string]linter.Severity
 	lexers       map[string]*lexer.Lexer
-	snippets     *context.FastlySnippet
+	snippets     *snippets.Snippets
 	config       *config.Config
 
 	level       Level
@@ -101,7 +100,7 @@ func (r *Runner) message(c *color.Color, format string, args ...interface{}) {
 	write(c, format, args...)
 }
 
-func NewRunner(c *config.Config, f Fetcher) (*Runner, error) {
+func NewRunner(c *config.Config, fetcher snippets.Fetcher) (*Runner, error) {
 	r := &Runner{
 		level:       LevelError,
 		overrides:   make(map[string]linter.Severity),
@@ -111,35 +110,16 @@ func NewRunner(c *config.Config, f Fetcher) (*Runner, error) {
 		parseErrors: make(map[string]*parser.ParseError),
 	}
 
-	if c.Remote {
-		r.message(cyan, "Remote option supplied. Fetching snippets from Fastly.\n")
-		// If remote flag is provided, fetch predefined data from Fastly.
-		//
-		// We communicate Fastly API with service id and api key,
-		// lookup fixed environment variable, FASTLY_SERVICE_ID and FASTLY_API_KEY
-		// So user needs to set them with "-r" argument.
-		if c.FastlyServiceID == "" || c.FastlyApiKey == "" {
-			return nil, errors.New("Both FASTLY_SERVICE_ID and FASTLY_API_KEY environment variables must be specified")
-		}
-		func() {
-			// Remote communication is optional so we keep processing even if remote communication is failed
-			// We allow each API call to take up to to 5 seconds
-			f := remote.NewFastlyApiFetcher(c.FastlyServiceID, c.FastlyApiKey, 5*time.Second)
-			snippets, err := NewSnippet(f).Fetch()
-			if err != nil {
-				r.message(red, err.Error()+"\n")
-			}
-			// Stack to runner field, combime before run()
-			r.snippets = snippets
-		}()
-	}
-
-	if f != nil {
-		snippets, err := NewSnippet(f).Fetch()
+	// If fetch interface is provided, communicate with it
+	if fetcher != nil {
+		s, err := snippets.Fetch(fetcher)
 		if err != nil {
 			r.message(red, err.Error()+"\n")
 		}
-		r.snippets = snippets
+		r.snippets = s
+		if err := r.snippets.FetchLogingEndpoint(fetcher); err != nil {
+			r.message(red, err.Error()+"\n")
+		}
 	}
 
 	// Check transformer exists and format to absolute path
@@ -198,7 +178,7 @@ func (r *Runner) Run(rslv resolver.Resolver) (*RunnerResult, error) {
 	options := []context.Option{context.WithResolver(rslv)}
 	// If remote snippets exists, prepare parse and prepend to main VCL
 	if r.snippets != nil {
-		options = append(options, context.WithFastlySnippets(r.snippets))
+		options = append(options, context.WithSnippets(r.snippets))
 	}
 
 	main, err := rslv.MainVCL()
@@ -410,7 +390,7 @@ func (r *Runner) Stats(rslv resolver.Resolver) (*StatsResult, error) {
 	options := []context.Option{context.WithResolver(rslv)}
 	// If remote snippets exists, prepare parse and prepend to main VCL
 	if r.snippets != nil {
-		options = append(options, context.WithFastlySnippets(r.snippets))
+		options = append(options, context.WithSnippets(r.snippets))
 	}
 
 	main, err := rslv.MainVCL()
@@ -450,7 +430,7 @@ func (r *Runner) Simulate(rslv resolver.Resolver) error {
 		icontext.WithMaxAcls(r.config.OverrideMaxAcls),
 	}
 	if r.snippets != nil {
-		options = append(options, icontext.WithFastlySnippets(r.snippets))
+		options = append(options, icontext.WithSnippets(r.snippets))
 	}
 	if sc.OverrideRequest != nil {
 		options = append(options, icontext.WithRequest(sc.OverrideRequest))
@@ -486,7 +466,7 @@ func (r *Runner) Test(rslv resolver.Resolver) (*tester.TestFactory, error) {
 		icontext.WithMaxAcls(r.config.OverrideMaxAcls),
 	}
 	if r.snippets != nil {
-		options = append(options, icontext.WithFastlySnippets(r.snippets))
+		options = append(options, icontext.WithSnippets(r.snippets))
 	}
 	if tc.OverrideRequest != nil {
 		options = append(options, icontext.WithRequest(tc.OverrideRequest))
diff --git a/context/context.go b/context/context.go
index 768105b..30d5d73 100644
--- a/context/context.go
+++ b/context/context.go
@@ -6,6 +6,7 @@ import (
 
 	"github.com/ysugimoto/falco/ast"
 	"github.com/ysugimoto/falco/resolver"
+	"github.com/ysugimoto/falco/snippets"
 	"github.com/ysugimoto/falco/types"
 )
 
@@ -116,7 +117,7 @@ type Context struct {
 	functions      Functions
 	Variables      Variables
 	resolver       resolver.Resolver
-	fastlySnippets *FastlySnippet
+	fastlySnippets *snippets.Snippets
 
 	// public fields
 	Acls              map[string]*types.Acl
@@ -176,9 +177,9 @@ func (c *Context) Resolver() resolver.Resolver {
 	return c.resolver
 }
 
-func (c *Context) Snippets() *FastlySnippet {
+func (c *Context) Snippets() *snippets.Snippets {
 	if c.fastlySnippets == nil {
-		c.fastlySnippets = &FastlySnippet{}
+		c.fastlySnippets = &snippets.Snippets{}
 	}
 	return c.fastlySnippets
 }
diff --git a/context/option.go b/context/option.go
index 35c98c5..ef42560 100644
--- a/context/option.go
+++ b/context/option.go
@@ -2,6 +2,7 @@ package context
 
 import (
 	"github.com/ysugimoto/falco/resolver"
+	"github.com/ysugimoto/falco/snippets"
 )
 
 type Option func(c *Context)
@@ -12,7 +13,7 @@ func WithResolver(rslv resolver.Resolver) Option {
 	}
 }
 
-func WithFastlySnippets(fs *FastlySnippet) Option {
+func WithSnippets(fs *snippets.Snippets) Option {
 	return func(c *Context) {
 		c.fastlySnippets = fs
 	}
diff --git a/context/snippet.go b/context/snippet.go
deleted file mode 100644
index 72e3858..0000000
--- a/context/snippet.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package context
-
-type FastlySnippetItem struct {
-	Data string
-	Name string
-}
-
-type FastlySnippet struct {
-	Dictionaries    []FastlySnippetItem
-	Acls            []FastlySnippetItem
-	Backends        []FastlySnippetItem
-	ScopedSnippets  map[string][]FastlySnippetItem
-	IncludeSnippets map[string]FastlySnippetItem
-}
-
-func (f *FastlySnippet) EmbedSnippets() []FastlySnippetItem {
-	var snippets []FastlySnippetItem
-
-	// Embed Dictionaries
-	snippets = append(snippets, f.Dictionaries...)
-	// Embed Acls
-	snippets = append(snippets, f.Acls...)
-	// Embed Backends
-	snippets = append(snippets, f.Backends...)
-
-	// And also we need to embed VCL snippets which is registered as "init" type
-	if scoped, ok := f.ScopedSnippets["init"]; ok {
-		snippets = append(snippets, scoped...)
-	}
-
-	return snippets
-}
diff --git a/go.mod b/go.mod
index ec579a2..fa87234 100644
--- a/go.mod
+++ b/go.mod
@@ -2,8 +2,6 @@ module github.com/ysugimoto/falco
 
 go 1.21
 
-toolchain go1.21.1
-
 require (
 	github.com/avct/uasurfer v0.0.0-20191028135549-26b5daa857f1
 	github.com/fatih/color v1.12.0
@@ -34,6 +32,7 @@ require (
 	github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
 	github.com/gdamore/encoding v1.0.0 // indirect
 	github.com/go-ini/ini v1.67.0 // indirect
+	github.com/k0kubun/pp v3.0.1+incompatible // indirect
 	github.com/kr/text v0.2.0 // indirect
 	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
 	github.com/mattn/go-isatty v0.0.12 // indirect
diff --git a/go.sum b/go.sum
index 26989b7..ee43e3f 100644
--- a/go.sum
+++ b/go.sum
@@ -23,6 +23,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40=
+github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
diff --git a/interpreter/context/context.go b/interpreter/context/context.go
index dddab67..c28dacc 100644
--- a/interpreter/context/context.go
+++ b/interpreter/context/context.go
@@ -6,10 +6,10 @@ import (
 
 	"github.com/ysugimoto/falco/ast"
 	"github.com/ysugimoto/falco/config"
-	"github.com/ysugimoto/falco/context"
 	"github.com/ysugimoto/falco/interpreter/cache"
 	"github.com/ysugimoto/falco/interpreter/value"
 	"github.com/ysugimoto/falco/resolver"
+	"github.com/ysugimoto/falco/snippets"
 )
 
 // Reserved vcl names in Fastly
@@ -43,7 +43,7 @@ var (
 
 type Context struct {
 	Resolver            resolver.Resolver
-	FastlySnippets      *context.FastlySnippet
+	FastlySnippets      *snippets.Snippets
 	Acls                map[string]*value.Acl
 	Backends            map[string]*value.Backend
 	Tables              map[string]*ast.TableDeclaration
diff --git a/interpreter/context/option.go b/interpreter/context/option.go
index d65fefd..baa5e44 100644
--- a/interpreter/context/option.go
+++ b/interpreter/context/option.go
@@ -2,8 +2,8 @@ package context
 
 import (
 	"github.com/ysugimoto/falco/config"
-	"github.com/ysugimoto/falco/context"
 	"github.com/ysugimoto/falco/resolver"
+	"github.com/ysugimoto/falco/snippets"
 )
 
 type Option func(c *Context)
@@ -14,7 +14,7 @@ func WithResolver(rslv resolver.Resolver) Option {
 	}
 }
 
-func WithFastlySnippets(fs *context.FastlySnippet) Option {
+func WithSnippets(fs *snippets.Snippets) Option {
 	return func(c *Context) {
 		c.FastlySnippets = fs
 	}
diff --git a/linter/linter.go b/linter/linter.go
index 0084afe..201840a 100644
--- a/linter/linter.go
+++ b/linter/linter.go
@@ -11,6 +11,7 @@ import (
 	"github.com/ysugimoto/falco/context"
 	"github.com/ysugimoto/falco/lexer"
 	"github.com/ysugimoto/falco/parser"
+	"github.com/ysugimoto/falco/snippets"
 	"github.com/ysugimoto/falco/token"
 	"github.com/ysugimoto/falco/types"
 )
@@ -344,8 +345,8 @@ func (l *Linter) resolveSnippetInclusion(
 ) []ast.Statement {
 
 	var statements []ast.Statement
-	snippets := ctx.Snippets().IncludeSnippets
-	snip, ok := snippets[strings.TrimPrefix(include.Module.Value, "snippet::")]
+	s := ctx.Snippets().IncludeSnippets
+	snip, ok := s[strings.TrimPrefix(include.Module.Value, "snippet::")]
 	if !ok {
 		e := &LintError{
 			Severity: ERROR,
@@ -911,15 +912,15 @@ func (l *Linter) lintFastlyBoilerPlateMacro(sub *ast.SubroutineDeclaration, ctx
 	phrase := strings.ToUpper("FASTLY " + scope)
 
 	// prepare scoped snippets
-	snippets, ok := ctx.Snippets().ScopedSnippets[scope]
+	scopedSnippets, ok := ctx.Snippets().ScopedSnippets[scope]
 	if !ok {
-		snippets = []context.FastlySnippetItem{}
+		scopedSnippets = []snippets.SnippetItem{}
 	}
 
 	var resolved []ast.Statement
 	// visit all statement comments and find "FASTLY [phase]" comment
 	if hasFastlyBoilerPlateMacro(sub.Block.InfixComment(), phrase) {
-		for _, s := range snippets {
+		for _, s := range scopedSnippets {
 			resolved = append(resolved, l.loadSnippetVCL("snippet::"+s.Name, s.Data)...)
 		}
 		sub.Block.Statements = append(resolved, sub.Block.Statements...)
@@ -930,7 +931,7 @@ func (l *Linter) lintFastlyBoilerPlateMacro(sub *ast.SubroutineDeclaration, ctx
 	for _, stmt := range sub.Block.Statements {
 		if hasFastlyBoilerPlateMacro(stmt.LeadingComment(), phrase) && !found {
 			// Macro found but embedding snippets should do only once
-			for _, s := range snippets {
+			for _, s := range scopedSnippets {
 				resolved = append(resolved, l.loadSnippetVCL("snippet::"+s.Name, s.Data)...)
 			}
 			found = true
diff --git a/remote/client.go b/remote/client.go
index cb74459..f32f4ee 100644
--- a/remote/client.go
+++ b/remote/client.go
@@ -11,6 +11,7 @@ import (
 	"net/http"
 
 	"github.com/pkg/errors"
+	"golang.org/x/sync/errgroup"
 )
 
 const (
@@ -236,3 +237,64 @@ func (c *FastlyClient) getDynamicSnippetContent(ctx context.Context, snippetId s
 
 	return &snippet.Content, nil
 }
+
+var fastlyRealtimeLoggingTypes = []string{
+	"bigquery",
+	"cloudfiles",
+	"datadog",
+	"digitalocean",
+	"elasticsearch",
+	"ftp",
+	"gcs",
+	"pubsub",
+	"https",
+	"heroku",
+	"honeycomb",
+	"kafka",
+	"kinesis",
+	"logshuttle",
+	"loggly",
+	"azureblob",
+	"newrelic",
+	"newrelicotlp",
+	"openstack",
+	"papertrail",
+	"s3",
+	"sftp",
+	"scalyr",
+	"splunk",
+	"sumologic",
+	"syslog",
+}
+
+type listLoggingEndpointResponse struct {
+	Name string `json:"name"`
+}
+
+func (c *FastlyClient) ListLoggingEndpoints(ctx context.Context, version int64) ([]string, error) {
+	var endpoints []string
+	var eg errgroup.Group
+
+	basePath := fmt.Sprintf("/service/%s/version/%d/logging", c.serviceId, version)
+	for i := range fastlyRealtimeLoggingTypes {
+		eg.Go(c.listLoggingEndpoint(ctx, endpoints, basePath+"/"+fastlyRealtimeLoggingTypes[i]))
+	}
+
+	if err := eg.Wait(); err != nil {
+		return nil, err
+	}
+	return endpoints, nil
+}
+
+func (c *FastlyClient) listLoggingEndpoint(ctx context.Context, endpoints []string, path string) func() error {
+	return func() error {
+		var resp []listLoggingEndpointResponse
+		if err := c.request(ctx, path, &resp); err != nil {
+			return err
+		}
+		for i := range resp {
+			endpoints = append(endpoints, resp[i].Name)
+		}
+		return nil
+	}
+}
diff --git a/remote/fetcher.go b/remote/fetcher.go
index 3a3b9cd..dc0cb84 100644
--- a/remote/fetcher.go
+++ b/remote/fetcher.go
@@ -136,3 +136,15 @@ func (f *FastlyApiFetcher) Snippets() ([]*types.RemoteVCL, error) {
 	}
 	return r, nil
 }
+
+func (f *FastlyApiFetcher) LoggingEndpoints() ([]string, error) {
+	c, timeout := context.WithTimeout(_context.Background(), f.timeout)
+	defer timeout()
+
+	version, err := f.getVersion(c)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to get latest version %w", err)
+	}
+
+	return f.client.ListLoggingEndpoints(c, version)
+}
diff --git a/cmd/falco/snippet.go b/snippets/fetch.go
similarity index 52%
rename from cmd/falco/snippet.go
rename to snippets/fetch.go
index fe04160..da34be3 100644
--- a/cmd/falco/snippet.go
+++ b/snippets/fetch.go
@@ -1,106 +1,61 @@
-package main
+package snippets
 
 import (
 	"bytes"
 	"fmt"
-	"regexp"
+	"html/template"
 	"sort"
 	"strings"
 
-	"text/template"
-
-	"github.com/ysugimoto/falco/context"
 	"github.com/ysugimoto/falco/remote"
 	"github.com/ysugimoto/falco/types"
+	"golang.org/x/sync/errgroup"
 )
 
-var tableTemplate = `
-table {{ .Name }} {
-	{{- range .Items }}
-	"{{ .Key }}": "{{ .Value }}",
-	{{- end }}
-}
-`
-
-var aclTemplate = `
-acl {{ .Name }} {
-	{{- range .Entries }}
-	{{ if .Negated }}!{{ end }}"{{ .Ip }}"{{ if .Subnet }}/{{ .Subnet }}{{ end }};{{ if .Comment }}  # {{ .Comment }}{{ end }}
-	{{- end }}
-}
-`
-
-var backendTemplate = `
-backend F_{{ .Name }} {}
-`
-
-var directorTemplate = `
-director {{ .Name }} {{ .Type | printtype }} {
-	{{- range .Backends }}
-	{ .backend = {{ . }}; .weight = 1; }
-	{{- end }}
-}
-`
-
-var invalid *regexp.Regexp
-
-func init() {
-	invalid = regexp.MustCompile(`\W`)
+type Fetcher interface {
+	Backends() ([]*types.RemoteBackend, error)
+	Dictionaries() ([]*types.RemoteDictionary, error)
+	Acls() ([]*types.RemoteAcl, error)
+	Snippets() ([]*types.RemoteVCL, error)
+	LoggingEndpoints() ([]string, error)
 }
 
-func TerraformBackendNameSanitizer(name string) string {
-	s := invalid.ReplaceAllString(name, "_")
-	return s
-}
-
-type Snippet struct {
-	fetcher Fetcher
-}
-
-func NewSnippet(f Fetcher) *Snippet {
-	return &Snippet{
-		fetcher: f,
+func Fetch(fetcher Fetcher) (*Snippets, error) {
+	snippets := &Snippets{
+		ScopedSnippets:   make(map[string][]SnippetItem),
+		IncludeSnippets:  make(map[string]SnippetItem),
+		LoggingEndpoints: make(map[string]struct{}),
 	}
-}
-
-func (s *Snippet) Fetch() (*context.FastlySnippet, error) {
-	var fs context.FastlySnippet
-	var err error
 
-	write(white, "Fetching Edge Dictionaries...")
-	fs.Dictionaries, err = s.fetchEdgeDictionary()
-	if err != nil {
-		return nil, err
-	}
-	writeln(white, "Done")
-
-	write(white, "Fatching Access Control Lists...")
-	fs.Acls, err = s.fetchAccessControl()
-	if err != nil {
-		return nil, err
-	}
-	writeln(white, "Done")
-
-	write(white, "Fatching Backends...")
-	fs.Backends, err = s.fetchBackend()
-	if err != nil {
-		return nil, err
-	}
-	writeln(white, "Done")
+	var eg errgroup.Group
+	fmt.Print("Fething snippets...")
+	eg.Go(func() (err error) {
+		snippets.Dictionaries, err = fetchEdgeDictionary(fetcher)
+		return err
+	})
+	eg.Go(func() (err error) {
+		snippets.Acls, err = fetchAccessControl(fetcher)
+		return err
+	})
+	eg.Go(func() (err error) {
+		snippets.Backends, err = fetchBackend(fetcher)
+		return err
+	})
+	eg.Go(func() (err error) {
+		snippets.ScopedSnippets, snippets.IncludeSnippets, err = fetchVCLSnippets(fetcher)
+		return err
+	})
 
-	write(white, "Fatching Snippets...")
-	fs.ScopedSnippets, fs.IncludeSnippets, err = s.fetchVCLSnippets()
-	if err != nil {
+	if err := eg.Wait(); err != nil {
+		fmt.Println("Error!")
 		return nil, err
 	}
-	writeln(white, "Done")
-
-	return &fs, nil
+	fmt.Println("Done.")
+	return snippets, nil
 }
 
-// Fetch remote Edge dictionary items
-func (s *Snippet) fetchEdgeDictionary() ([]context.FastlySnippetItem, error) {
-	dicts, err := s.fetcher.Dictionaries()
+func fetchEdgeDictionary(fetcher Fetcher) ([]SnippetItem, error) {
+	dicts, err := fetcher.Dictionaries()
 	if err != nil {
 		return nil, fmt.Errorf("Failed to get edge dictionaries %w", err)
 	}
@@ -110,23 +65,22 @@ func (s *Snippet) fetchEdgeDictionary() ([]context.FastlySnippetItem, error) {
 		return nil, fmt.Errorf("Failed to compilte table template: %w", err)
 	}
 
-	var snippets []context.FastlySnippetItem
+	var snippets []SnippetItem
 	for _, dict := range dicts {
 		buf := new(bytes.Buffer)
 		if err := tmpl.Execute(buf, dict); err != nil {
 			return nil, fmt.Errorf("Failed to render table template: %w", err)
 		}
-		snippets = append(snippets, context.FastlySnippetItem{
-			Name: fmt.Sprintf("EdgeDictionary:%s", dict.Name),
+		snippets = append(snippets, SnippetItem{
+			Name: fmt.Sprintf("Remote.EdgeDictionary:%s", dict.Name),
 			Data: buf.String(),
 		})
 	}
 	return snippets, nil
 }
 
-// Fetch remote Access Control entries
-func (s *Snippet) fetchAccessControl() ([]context.FastlySnippetItem, error) {
-	acls, err := s.fetcher.Acls()
+func fetchAccessControl(fetcher Fetcher) ([]SnippetItem, error) {
+	acls, err := fetcher.Acls()
 	if err != nil {
 		return nil, fmt.Errorf("Failed to get ACLs: %w", err)
 	}
@@ -136,23 +90,23 @@ func (s *Snippet) fetchAccessControl() ([]context.FastlySnippetItem, error) {
 		return nil, fmt.Errorf("Failed to compile acl template: %w", err)
 	}
 
-	var snippets []context.FastlySnippetItem
+	var snippets []SnippetItem
 	for _, a := range acls {
 		buf := new(bytes.Buffer)
 		if err := tmpl.Execute(buf, a); err != nil {
 			return nil, fmt.Errorf("Failed to render acl template: %w", err)
 		}
-		snippets = append(snippets, context.FastlySnippetItem{
-			Name: fmt.Sprintf("ACL:%s", a.Name),
+		snippets = append(snippets, SnippetItem{
+			Name: fmt.Sprintf("Remote.Acl:%s", a.Name),
 			Data: buf.String(),
 		})
 	}
 	return snippets, nil
 }
 
-func (s *Snippet) fetchBackend() ([]context.FastlySnippetItem, error) {
-	var snippets []context.FastlySnippetItem
-	backends, err := s.fetcher.Backends()
+func fetchBackend(fetcher Fetcher) ([]SnippetItem, error) {
+	var snippets []SnippetItem
+	backends, err := fetcher.Backends()
 	if err != nil {
 		return nil, fmt.Errorf("Failed to get Backends: %w", err)
 	}
@@ -170,15 +124,15 @@ func (s *Snippet) fetchBackend() ([]context.FastlySnippetItem, error) {
 		if err := backTmpl.Execute(buf, b); err != nil {
 			return nil, fmt.Errorf("failed to render backend template: %w", err)
 		}
-		snippets = append(snippets, context.FastlySnippetItem{
-			Name: fmt.Sprintf("BACKEND:%s", b.Name),
+		snippets = append(snippets, SnippetItem{
+			Name: fmt.Sprintf("Remote.Backend:%s", b.Name),
 			Data: buf.String(),
 		})
 	}
 
 	// Generate director snippet only when at least one backend is declared
 	if len(backends) > 0 {
-		directors, err := s.renderBackendShields(backends)
+		directors, err := renderBackendShields(backends)
 		if err != nil {
 			return nil, err
 		}
@@ -188,7 +142,7 @@ func (s *Snippet) fetchBackend() ([]context.FastlySnippetItem, error) {
 	return snippets, nil
 }
 
-func (s *Snippet) renderBackendShields(backends []*types.RemoteBackend) ([]context.FastlySnippetItem, error) {
+func renderBackendShields(backends []*types.RemoteBackend) ([]SnippetItem, error) {
 	printType := func(dtype remote.DirectorType) string {
 		switch dtype {
 		case remote.Random:
@@ -214,7 +168,7 @@ func (s *Snippet) renderBackendShields(backends []*types.RemoteBackend) ([]conte
 		}
 	}
 
-	var snippets []context.FastlySnippetItem
+	var snippets []SnippetItem
 	// We need to pick an arbitrary backend to avoid an undeclared linter error
 	shieldBackend := "F_" + backends[0].Name
 	for sd := range shieldDirectors {
@@ -227,8 +181,8 @@ func (s *Snippet) renderBackendShields(backends []*types.RemoteBackend) ([]conte
 		if err := dirTmpl.Execute(buf, d); err != nil {
 			return nil, fmt.Errorf("failed to render director template: %w", err)
 		}
-		snippets = append(snippets, context.FastlySnippetItem{
-			Name: fmt.Sprintf("DIRECTOR:%s", d.Name),
+		snippets = append(snippets, SnippetItem{
+			Name: fmt.Sprintf("Remote.Director:%s", d.Name),
 			Data: buf.String(),
 		})
 	}
@@ -236,13 +190,13 @@ func (s *Snippet) renderBackendShields(backends []*types.RemoteBackend) ([]conte
 	return snippets, nil
 }
 
-func (s *Snippet) fetchVCLSnippets() (
-	map[string][]context.FastlySnippetItem,
-	map[string]context.FastlySnippetItem,
+func fetchVCLSnippets(fetcher Fetcher) (
+	map[string][]SnippetItem,
+	map[string]SnippetItem,
 	error,
 ) {
 
-	snippets, err := s.fetcher.Snippets()
+	snippets, err := fetcher.Snippets()
 	if err != nil {
 		return nil, nil, fmt.Errorf("Failed to get VCL snippets: %w", err)
 	}
@@ -252,12 +206,12 @@ func (s *Snippet) fetchVCLSnippets() (
 		return snippets[i].Priority > snippets[j].Priority
 	})
 
-	scoped := make(map[string][]context.FastlySnippetItem)
-	include := make(map[string]context.FastlySnippetItem)
+	scoped := make(map[string][]SnippetItem)
+	include := make(map[string]SnippetItem)
 	for _, snip := range snippets {
 		// "none" type means that user could include the snippet arbitrary
 		if snip.Type == "none" {
-			include[snip.Name] = context.FastlySnippetItem{
+			include[snip.Name] = SnippetItem{
 				Name: snip.Name,
 				Data: snip.Content,
 			}
@@ -265,9 +219,9 @@ func (s *Snippet) fetchVCLSnippets() (
 		}
 		// Otherwise, factory with type (phase) name
 		if _, ok := scoped[snip.Type]; !ok {
-			scoped[snip.Type] = []context.FastlySnippetItem{}
+			scoped[snip.Type] = []SnippetItem{}
 		}
-		scoped[snip.Type] = append(scoped[snip.Type], context.FastlySnippetItem{
+		scoped[snip.Type] = append(scoped[snip.Type], SnippetItem{
 			Name: snip.Name,
 			Data: snip.Content,
 		})
diff --git a/snippets/helper.go b/snippets/helper.go
new file mode 100644
index 0000000..778dd12
--- /dev/null
+++ b/snippets/helper.go
@@ -0,0 +1,10 @@
+package snippets
+
+import "regexp"
+
+var invalid *regexp.Regexp = regexp.MustCompile(`\W`)
+
+func TerraformBackendNameSanitizer(name string) string {
+	s := invalid.ReplaceAllString(name, "_")
+	return s
+}
diff --git a/snippets/snippets.go b/snippets/snippets.go
new file mode 100644
index 0000000..809dc7b
--- /dev/null
+++ b/snippets/snippets.go
@@ -0,0 +1,50 @@
+package snippets
+
+type SnippetItem struct {
+	Data string
+	Name string
+}
+
+type Snippets struct {
+	Dictionaries     []SnippetItem
+	Acls             []SnippetItem
+	Backends         []SnippetItem
+	ScopedSnippets   map[string][]SnippetItem
+	IncludeSnippets  map[string]SnippetItem
+	LoggingEndpoints map[string]struct{}
+}
+
+func (s *Snippets) EmbedSnippets() []SnippetItem {
+	var snippets []SnippetItem
+
+	// Embed Dictionaries
+	snippets = append(snippets, s.Dictionaries...)
+	// Embed Acls
+	snippets = append(snippets, s.Acls...)
+	// Embed Backends
+	snippets = append(snippets, s.Backends...)
+
+	// And also we need to embed VCL snippets which is registered as "init" type
+	if scoped, ok := s.ScopedSnippets["init"]; ok {
+		snippets = append(snippets, scoped...)
+	}
+
+	return snippets
+}
+
+// Fastly logging endpoints is not used on linting and interpreter,
+// but we need to be able to factory all endpoints for future works.
+// Fastly's logging endpoints API is divided for each services like BigQuery, S3, etc..
+// It means we need to make many API calls so implement as Snippets pointer method.
+func (s *Snippets) FetchLogingEndpoint(fetcher Fetcher) error {
+	endpoints, err := fetcher.LoggingEndpoints()
+	if err != nil {
+		return err
+	}
+
+	// Convert map to key access
+	for i := range endpoints {
+		s.LoggingEndpoints[endpoints[i]] = struct{}{}
+	}
+	return nil
+}
diff --git a/snippets/template.go b/snippets/template.go
new file mode 100644
index 0000000..1ced090
--- /dev/null
+++ b/snippets/template.go
@@ -0,0 +1,29 @@
+package snippets
+
+var tableTemplate = `
+table {{ .Name }} {
+	{{- range .Items }}
+	"{{ .Key }}": "{{ .Value }}",
+	{{- end }}
+}
+`
+
+var aclTemplate = `
+acl {{ .Name }} {
+	{{- range .Entries }}
+	{{ if .Negated }}!{{ end }}"{{ .Ip }}"{{ if .Subnet }}/{{ .Subnet }}{{ end }};{{ if .Comment }}  # {{ .Comment }}{{ end }}
+	{{- end }}
+}
+`
+
+var backendTemplate = `
+backend F_{{ .Name }} {}
+`
+
+var directorTemplate = `
+director {{ .Name }} {{ .Type | printtype }} {
+	{{- range .Backends }}
+	{ .backend = {{ . }}; .weight = 1; }
+	{{- end }}
+}
+`
diff --git a/terraform/fetcher.go b/terraform/fetcher.go
index 3c23aea..3cd32fd 100644
--- a/terraform/fetcher.go
+++ b/terraform/fetcher.go
@@ -5,7 +5,8 @@ import (
 )
 
 type TerraformFetcher struct {
-	services []*FastlyService
+	services    []*FastlyService
+	currentName string
 }
 
 func NewTerraformFetcher(s []*FastlyService) *TerraformFetcher {
@@ -14,9 +15,25 @@ func NewTerraformFetcher(s []*FastlyService) *TerraformFetcher {
 	}
 }
 
+func (f *TerraformFetcher) SetName(name string) {
+	f.currentName = name
+}
+
+func (f *TerraformFetcher) filterService() []*FastlyService {
+	if f.currentName == "" {
+		return f.services
+	}
+	for _, s := range f.services {
+		if s.Name == f.currentName {
+			return []*FastlyService{s}
+		}
+	}
+	return []*FastlyService{}
+}
+
 func (f *TerraformFetcher) Backends() ([]*types.RemoteBackend, error) {
 	var b []*types.RemoteBackend
-	for _, s := range f.services {
+	for _, s := range f.filterService() {
 		for _, serviceBackend := range s.Backends {
 			b = append(b, &types.RemoteBackend{
 				Name:   serviceBackend.Name,
@@ -29,7 +46,7 @@ func (f *TerraformFetcher) Backends() ([]*types.RemoteBackend, error) {
 
 func (f *TerraformFetcher) Dictionaries() ([]*types.RemoteDictionary, error) {
 	var d []*types.RemoteDictionary
-	for _, s := range f.services {
+	for _, s := range f.filterService() {
 		for _, sDictionary := range s.Dictionaries {
 			d = append(d, &types.RemoteDictionary{
 				Name: sDictionary.Name,
@@ -41,7 +58,7 @@ func (f *TerraformFetcher) Dictionaries() ([]*types.RemoteDictionary, error) {
 
 func (f *TerraformFetcher) Acls() ([]*types.RemoteAcl, error) {
 	var a []*types.RemoteAcl
-	for _, s := range f.services {
+	for _, s := range f.filterService() {
 		for _, sACL := range s.Acls {
 			a = append(a, &types.RemoteAcl{
 				Name: sACL.Name,
@@ -53,7 +70,7 @@ func (f *TerraformFetcher) Acls() ([]*types.RemoteAcl, error) {
 
 func (f *TerraformFetcher) Snippets() ([]*types.RemoteVCL, error) {
 	var v []*types.RemoteVCL
-	for _, s := range f.services {
+	for _, s := range f.filterService() {
 		for _, vcl := range s.Snippets {
 			v = append(v, &types.RemoteVCL{
 				Name:     vcl.Name,
@@ -65,3 +82,11 @@ func (f *TerraformFetcher) Snippets() ([]*types.RemoteVCL, error) {
 	}
 	return v, nil
 }
+
+func (f *TerraformFetcher) LoggingEndpoints() ([]string, error) {
+	var v []string
+	for _, s := range f.filterService() {
+		v = append(v, s.LoggingEndpoints...)
+	}
+	return v, nil
+}
diff --git a/terraform/terraform.go b/terraform/terraform.go
index 08fcd29..75d9df7 100644
--- a/terraform/terraform.go
+++ b/terraform/terraform.go
@@ -35,6 +35,10 @@ type TerraformSnippet struct {
 	Priority int64
 }
 
+type TerraformLoggingEndpoint struct {
+	Name string
+}
+
 // TODO(davinci26): We can unmarshall all the properties from the TF file
 // and lint them to make sure they have sane values.
 type TerraformBackend struct {
@@ -43,12 +47,13 @@ type TerraformBackend struct {
 }
 
 type FastlyService struct {
-	Name         string
-	Vcls         []*TerraformVcl
-	Backends     []*TerraformBackend
-	Acls         []*TerraformAcl
-	Dictionaries []*TerraformDictionary
-	Snippets     []*TerraformSnippet
+	Name             string
+	Vcls             []*TerraformVcl
+	Backends         []*TerraformBackend
+	Acls             []*TerraformAcl
+	Dictionaries     []*TerraformDictionary
+	Snippets         []*TerraformSnippet
+	LoggingEndpoints []string
 }
 
 type TerraformPlannedResource struct {
@@ -61,6 +66,33 @@ type TerraformPlannedResource struct {
 		Backend    []*TerraformBackend    `json:"backend"`
 		Dictionary []*TerraformDictionary `json:"dictionary"`
 		Snippets   []*TerraformSnippet    `json:"snippet"`
+
+		// Various kinds of realtime logging endpoints
+		LoggingBigQuerty     []*TerraformLoggingEndpoint `json:"logging_bigqeury"`
+		LoggingBlobStorage   []*TerraformLoggingEndpoint `json:"logging_blobstorage"`
+		LoggingCloudFiles    []*TerraformLoggingEndpoint `json:"logging_cloudfiles"`
+		LoggingDatadog       []*TerraformLoggingEndpoint `json:"logging_datadog"`
+		LoggingDigitalOpean  []*TerraformLoggingEndpoint `json:"logging_digitalocean"`
+		LoggingElasticsearch []*TerraformLoggingEndpoint `json:"logging_elasticsearch"`
+		LoggingFtp           []*TerraformLoggingEndpoint `json:"logging_ftp"`
+		LoggingGcs           []*TerraformLoggingEndpoint `json:"logging_gcs"`
+		LoggingGooglePubSub  []*TerraformLoggingEndpoint `json:"logging_googlepubsub"`
+		LoggingHeroku        []*TerraformLoggingEndpoint `json:"logging_heroku"`
+		LoggingHttps         []*TerraformLoggingEndpoint `json:"logging_https"`
+		LoggingKafka         []*TerraformLoggingEndpoint `json:"logging_kafka"`
+		LoggingKinesis       []*TerraformLoggingEndpoint `json:"logging_kinesis"`
+		LoggingLogEntries    []*TerraformLoggingEndpoint `json:"logging_logentries"`
+		LoggingLoggly        []*TerraformLoggingEndpoint `json:"logging_loggly"`
+		LoggingLogShuttle    []*TerraformLoggingEndpoint `json:"logging_logshuttle"`
+		LoggingNewRelic      []*TerraformLoggingEndpoint `json:"logging_newrelic"`
+		LoggingOpenStack     []*TerraformLoggingEndpoint `json:"logging_openstack"`
+		LoggingPaperTrail    []*TerraformLoggingEndpoint `json:"logging_papertrail"`
+		LoggingS3            []*TerraformLoggingEndpoint `json:"logging_s3"`
+		LoggingScalyr        []*TerraformLoggingEndpoint `json:"logging_scalyr"`
+		LoggingSftp          []*TerraformLoggingEndpoint `json:"logging_sftp"`
+		LoggingSplunk        []*TerraformLoggingEndpoint `json:"logging_splunk"`
+		LoggingSumoLogic     []*TerraformLoggingEndpoint `json:"logging_sumologic"`
+		LoggingSyslog        []*TerraformLoggingEndpoint `json:"logging_syslog"`
 	} `json:"values"`
 }
 
@@ -99,12 +131,13 @@ func UnmarshalTerraformPlannedInput(buf []byte) ([]*FastlyService, error) {
 			}
 
 			services = append(services, &FastlyService{
-				Name:         v.Values.Name,
-				Vcls:         v.Values.Vcl,
-				Acls:         v.Values.Acl,
-				Backends:     v.Values.Backend,
-				Dictionaries: v.Values.Dictionary,
-				Snippets:     v.Values.Snippets,
+				Name:             v.Values.Name,
+				Vcls:             v.Values.Vcl,
+				Acls:             v.Values.Acl,
+				Backends:         v.Values.Backend,
+				Dictionaries:     v.Values.Dictionary,
+				Snippets:         v.Values.Snippets,
+				LoggingEndpoints: factoryLoggingEndpoints(v),
 			})
 		}
 	}
@@ -117,12 +150,13 @@ func UnmarshalTerraformPlannedInput(buf []byte) ([]*FastlyService, error) {
 			}
 
 			services = append(services, &FastlyService{
-				Name:         v.Values.Name,
-				Vcls:         v.Values.Vcl,
-				Acls:         v.Values.Acl,
-				Backends:     v.Values.Backend,
-				Dictionaries: v.Values.Dictionary,
-				Snippets:     v.Values.Snippets,
+				Name:             v.Values.Name,
+				Vcls:             v.Values.Vcl,
+				Acls:             v.Values.Acl,
+				Backends:         v.Values.Backend,
+				Dictionaries:     v.Values.Dictionary,
+				Snippets:         v.Values.Snippets,
+				LoggingEndpoints: factoryLoggingEndpoints(v),
 			})
 		}
 	}
@@ -138,3 +172,80 @@ func isFastlyVCLServiceResource(r *TerraformPlannedResource) bool {
 	return r.ProviderName == fastlyTerraformProviderName &&
 		(r.Type == fastlyVCLServiceType || r.Type == fastlyVCLServiceTypeV1)
 }
+
+func factoryLoggingEndpoints(resource *TerraformPlannedResource) []string {
+	var endpoints []string
+	for _, v := range resource.Values.LoggingBigQuerty {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingBlobStorage {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingCloudFiles {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingDatadog {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingDigitalOpean {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingElasticsearch {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingFtp {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingGcs {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingGooglePubSub {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingHeroku {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingHttps {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingKafka {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingKinesis {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingLogEntries {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingLoggly {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingLogShuttle {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingNewRelic {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingOpenStack {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingPaperTrail {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingS3 {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingScalyr {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingSplunk {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingSumoLogic {
+		endpoints = append(endpoints, v.Name)
+	}
+	for _, v := range resource.Values.LoggingSyslog {
+		endpoints = append(endpoints, v.Name)
+	}
+	return endpoints
+}


Test patch:
diff --git a/cmd/falco/runner_test.go b/cmd/falco/runner_test.go
index 747ea5e..6c5330e 100644
--- a/cmd/falco/runner_test.go
+++ b/cmd/falco/runner_test.go
@@ -51,7 +51,7 @@ func loadRepoExampleTestMetadata() []RepoExampleTestMetadata {
 	}
 }
 
-func loadFromTfJson(fileName string, t *testing.T) ([]resolver.Resolver, Fetcher) {
+func loadFromTfJson(fileName string, t *testing.T) ([]resolver.Resolver, *terraform.TerraformFetcher) {
 	buf, err := os.ReadFile(fileName)
 	if err != nil {
 		t.Fatalf("Unexpected error %s reading file %s ", fileName, err)
diff --git a/linter/linter_test.go b/linter/linter_test.go
index d6ab9b4..6781b4d 100644
--- a/linter/linter_test.go
+++ b/linter/linter_test.go
@@ -10,6 +10,7 @@ import (
 	"github.com/ysugimoto/falco/lexer"
 	"github.com/ysugimoto/falco/parser"
 	"github.com/ysugimoto/falco/resolver"
+	"github.com/ysugimoto/falco/snippets"
 	"github.com/ysugimoto/falco/types"
 )
 
@@ -2500,8 +2501,8 @@ sub vcl_recv {
 }
 
 func TestFastlyScopedSnippetInclusion(t *testing.T) {
-	snippets := &context.FastlySnippet{
-		ScopedSnippets: map[string][]context.FastlySnippetItem{
+	snippets := &snippets.Snippets{
+		ScopedSnippets: map[string][]snippets.SnippetItem{
 			"recv": {
 				{
 					Name: "recv_injection",
@@ -2517,12 +2518,12 @@ sub vcl_recv {
    return (pass);
 }
 `
-	assertError(t, input, context.WithFastlySnippets(snippets))
+	assertError(t, input, context.WithSnippets(snippets))
 }
 
 func TestFastlySnippetInclusion(t *testing.T) {
-	snippets := &context.FastlySnippet{
-		IncludeSnippets: map[string]context.FastlySnippetItem{
+	snippets := &snippets.Snippets{
+		IncludeSnippets: map[string]snippets.SnippetItem{
 			"recv_injection": {
 				Name: "recv_injection",
 				Data: `set req.http.InjectedViaMacro = 1;`,
@@ -2537,7 +2538,7 @@ sub vcl_recv {
    }
 }
 `
-	assertError(t, input, context.WithFastlySnippets(snippets))
+	assertError(t, input, context.WithSnippets(snippets))
 }
 
 func TestFastlyInfoH2FingerPrintCouldLint(t *testing.T) {