Skip to content

Commit

Permalink
Merge pull request #53 from SpineEventEngine/go-refactor-embedding-pa…
Browse files Browse the repository at this point in the history
…ckage

[Go] Refactor `embedding` package
  • Loading branch information
olena-zmiiova authored Sep 26, 2024
2 parents dabd7b3 + 14acf54 commit 2f3d88a
Show file tree
Hide file tree
Showing 26 changed files with 952 additions and 1,042 deletions.
4 changes: 4 additions & 0 deletions embed-code-go/.golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ issues:
- revive
text: "dot-imports: should not use dot imports"
path: _test\.go
# We may have repeating lines in tests and it should be valid.
- linters:
- goconst
path: _test\.go
# Excluding test folder as tests are in progress of moving to the source files.
exclude-dirs:
- test/
Expand Down
2 changes: 1 addition & 1 deletion embed-code-go/analyzing/analyzing.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func extractAnalyticsForDocs(
var changedEmbeddingsLines, problemEmbeddingsLines []string

for _, docFile := range docFiles {
processor := embedding.NewEmbeddingProcessor(docFile, config)
processor := embedding.NewProcessor(docFile, config)
changedEmbeddings, err := processor.FindChangedEmbeddings()

// If there is an error during embedding, it is written to the analytics file.
Expand Down
Binary file modified embed-code-go/bin/embed-code-macos
Binary file not shown.
Binary file modified embed-code-go/bin/embed-code-ubuntu
Binary file not shown.
Binary file modified embed-code-go/bin/embed-code-win.exe
Binary file not shown.
106 changes: 106 additions & 0 deletions embed-code-go/embedding/embedding_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright 2020, TeamDev. All rights reserved.
//
// Redistribution and use in source and/or binary forms, with or without
// modification, must retain the above copyright notice and the following
// disclaimer.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package embedding_test

import (
"fmt"
"os"
"testing"

"embed-code/embed-code-go/configuration"
"embed-code/embed-code-go/embedding"
"embed-code/embed-code-go/embedding/parsing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestEmbedding(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Data Suite")
}

var _ = Describe("Embedding", func() {
var config configuration.Configuration

BeforeEach(func() {
currentDir, err := os.Getwd()
if err != nil {
Fail("unexpected error during the test setup: " + err.Error())
}
err = os.Chdir(currentDir)
if err != nil {
Fail("unexpected error during the test setup: " + err.Error())
}
config = buildConfigWithPreparedFragments()
})

It("should be up to date", func() {
docPath := fmt.Sprintf("%s/whole-file-fragment.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)

Expect(processor.Embed()).ShouldNot(HaveOccurred())
Expect(processor.IsUpToDate()).Should(BeTrue())
})

It("should be up to date as there is nothing to update", func() {
docPath := fmt.Sprintf("%s/no-embedding-doc.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)

Expect(processor.Embed()).ShouldNot(HaveOccurred())
Expect(processor.IsUpToDate()).Should(BeTrue())
})

It("should have error as it has invalid transition map", func() {
docPath := fmt.Sprintf("%s/split-lines.md", config.DocumentationRoot)

falseTransitions := parsing.TransitionMap{
parsing.Start: {parsing.RegularLine, parsing.Finish,
parsing.EmbedInstruction},
parsing.RegularLine: {parsing.Finish, parsing.EmbedInstruction,
parsing.RegularLine},
parsing.EmbedInstruction: {parsing.CodeFenceStart, parsing.BlankLine},
parsing.BlankLine: {parsing.CodeFenceStart, parsing.BlankLine},
parsing.CodeFenceStart: {parsing.CodeFenceEnd, parsing.CodeSampleLine},
parsing.CodeSampleLine: {parsing.CodeFenceEnd, parsing.CodeSampleLine},
parsing.CodeFenceEnd: {parsing.Finish, parsing.EmbedInstruction,
parsing.RegularLine},
}

falseProcessor := embedding.NewProcessorWithTransitions(docPath, config, falseTransitions)
Expect(falseProcessor.Embed()).Error().Should(HaveOccurred())
})

It("should successfully embed with multi lined tag", func() {
docPath := fmt.Sprintf("%s/multi-lined-tag.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
Expect(processor.Embed()).Error().ShouldNot(HaveOccurred())

Expect(processor.IsUpToDate()).Should(BeTrue())
})
})

func buildConfigWithPreparedFragments() configuration.Configuration {
var config = configuration.NewConfiguration()
config.DocumentationRoot = "../test/resources/docs"
config.CodeRoot = "../test/resources/code"
config.FragmentsDir = "../test/resources/prepared-fragments"

return config
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,28 @@ import (
"embed-code/embed-code-go/embedding/parsing"
)

// Describes an error which occurs if something goes wrong during embedding.
type EmbeddingError struct {
Context parsing.ParsingContext
// UnexpectedDiffError describes an error which occurs if outdated files are found during
// the checking.
type UnexpectedDiffError struct {
changedFiles []string
}

func (err EmbeddingError) Error() string {
errorString := fmt.Sprintf("embedding error for file `%s`.", err.Context.MarkdownFile)
func (e *UnexpectedDiffError) Error() string {
return fmt.Sprintf("unexpected diff: %v", e.changedFiles)
}

// UnexpectedProcessingError describes an error which occurs if something goes wrong
// during embedding.
type UnexpectedProcessingError struct {
Context parsing.Context
}

func (e UnexpectedProcessingError) Error() string {
errorString := fmt.Sprintf("embedding error for file `%s`.", e.Context.MarkdownFilePath)

if len(err.Context.EmbeddingsNotFound) > 0 {
if len(e.Context.EmbeddingsNotFound) > 0 {
embeddingsNotFoundStr := "\nMissing embeddings: \n"
for _, emb := range err.Context.EmbeddingsNotFound {
for _, emb := range e.Context.EmbeddingsNotFound {
embeddingsNotFoundStr += fmt.Sprintf(
"%s — %s\n",
emb.CodeFile,
Expand All @@ -43,15 +54,15 @@ func (err EmbeddingError) Error() string {
errorString += embeddingsNotFoundStr
}

if len(err.Context.UnacceptedEmbeddings) > 0 {
unacceptedEmbbeddingsStr := "\nUnaccepted embeddings: \n"
for _, emb := range err.Context.UnacceptedEmbeddings {
unacceptedEmbbeddingsStr += fmt.Sprintf(
if len(e.Context.UnacceptedEmbeddings) > 0 {
unacceptedEmbeddingStr := "\nUnaccepted embeddings: \n"
for _, emb := range e.Context.UnacceptedEmbeddings {
unacceptedEmbeddingStr += fmt.Sprintf(
"%s — %s\n",
emb.CodeFile,
emb.Fragment)
}
errorString += unacceptedEmbbeddingsStr
errorString += unacceptedEmbeddingStr
}

return errorString
Expand Down
24 changes: 10 additions & 14 deletions embed-code-go/embedding/parsing/blank_line.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,24 @@ import (
"embed-code/embed-code-go/configuration"
)

// Represents a blank line of a markdown.
type BlankLine struct{}
// BlankLineState represents a blank line of a markdown.
type BlankLineState struct{}

// Reports whether the current line is a blank line.
// Recognize reports whether the current line is blank.
//
// Checks if the current line is empty and not part of a code fence,
// and if there is an embedding. If these conditions are met, it returns true.
// Otherwise, it returns false.
func (b BlankLine) Recognize(context ParsingContext) bool {
if !context.ReachedEOF() && strings.TrimSpace(context.CurrentLine()) == "" {
// Checks if the current line is empty and not part of a code fence, and if there is an embedding.
// If these conditions are met, it returns true. Otherwise, it returns false.
func (b BlankLineState) Recognize(context Context) bool {
isEmptyString := strings.TrimSpace(context.CurrentLine()) == ""
if !context.ReachedEOF() && isEmptyString {
return !context.CodeFenceStarted && context.Embedding != nil
}

return false
}

// Processes a blank line of a markdown.
//
// Appends the current line of the context to the result, and moves to the next line.
//
// This implementation never returns an error.
func (b BlankLine) Accept(context *ParsingContext, _ configuration.Configuration) error {
// Accept appends the current line of the context to the result, and moves to the next line.
func (b BlankLineState) Accept(context *Context, _ configuration.Configuration) error {
line := context.CurrentLine()
context.Result = append(context.Result, line)
context.ToNextLine()
Expand Down
39 changes: 13 additions & 26 deletions embed-code-go/embedding/parsing/code_fence_end.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,40 +24,31 @@ import (
"embed-code/embed-code-go/configuration"
)

//
// Public methods
//

// Represents the end of a code fence.
type CodeFenceEnd struct{}
// CodeFenceEndState represents the end of a code fence.
type CodeFenceEndState struct{}

// Reports whether the current line is the end of a code fence.
//
// The line is a code fence end if:
// - the end is not reached;
// Recognize reports whether the current line meets this conditions:
// - the end of file is not reached;
// - the code fence has started;
// - the current line starts with the appropriate indentation and "```"
//
// context — a context of the parsing process.
func (c CodeFenceEnd) Recognize(context ParsingContext) bool {
if !context.ReachedEOF() {
indentation := strings.Repeat(" ", context.CodeFenceIndentation)

return context.CodeFenceStarted && strings.HasPrefix(context.CurrentLine(), indentation+"```")
func (c CodeFenceEndState) Recognize(context Context) bool {
if context.ReachedEOF() {
return false
}
indentation := strings.Repeat(" ", context.CodeFenceIndentation)

return false
return context.CodeFenceStarted && strings.HasPrefix(context.CurrentLine(), indentation+"```")
}

// Processes the end of a code fence by adding the current line to the result,
// resetting certain context variables, and moving to the next line.
// Accept adds the current line to the result, resets certain context variables, and moves to
// the next line.
//
// context — a context of the parsing process.
//
// config — a configuration of the embedding.
//
// Returns an error if the rendering was not successful.
func (c CodeFenceEnd) Accept(context *ParsingContext, _ configuration.Configuration) error {
func (c CodeFenceEndState) Accept(context *Context, _ configuration.Configuration) error {
line := context.CurrentLine()
err := renderSample(context)
context.SetEmbedding(nil)
Expand All @@ -73,16 +64,12 @@ func (c CodeFenceEnd) Accept(context *ParsingContext, _ configuration.Configurat
return err
}

//
// Private methods
//

// Renders the sample content of the embedding.
//
// context — a context of the parsing process.
//
// Returns an error if the reading of the embedding's content was not successful.
func renderSample(context *ParsingContext) error {
func renderSample(context *Context) error {
content, err := context.Embedding.Content()
if err != nil {
return err
Expand Down
28 changes: 8 additions & 20 deletions embed-code-go/embedding/parsing/code_fence_start.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,38 +24,26 @@ import (
"embed-code/embed-code-go/configuration"
)

// Represents the start of a code fence.
type CodeFenceStart struct{}
// CodeFenceStartState represents the StartState of a code fence.
type CodeFenceStartState struct{}

//
// Public methods
//

// Reports whether the current line is the start of a code fence.
//
// The line is a code fence start if the end is not reached and the current line starts with "```".
// Recognize reports whether the current line is not reached the end and starts with "```".
//
// context — a context of the parsing process.
func (c CodeFenceStart) Recognize(context ParsingContext) bool {
func (c CodeFenceStartState) Recognize(context Context) bool {
if !context.ReachedEOF() {
return strings.HasPrefix(strings.TrimSpace(context.CurrentLine()), "```")
}

return false
}

// Processes the start of a code fence.
//
// Appends the current line from the parsing context to the result,
// sets a flag to indicate that a code fence has started,
// calculates the indentation level of the code fence, and moves to the next line in the context.
// Accept appends the current line from the parsing context to the result, sets a flag to indicate
// that a code fence has started, calculates the indentation level of the code fence, and moves
// to the next line in the context.
//
// context — a context of the parsing process.
//
// config — a configuration of the embedding.
//
// This implementation never returns an error.
func (c CodeFenceStart) Accept(context *ParsingContext, _ configuration.Configuration) error {
func (c CodeFenceStartState) Accept(context *Context, _ configuration.Configuration) error {
line := context.CurrentLine()
context.Result = append(context.Result, line)
context.CodeFenceStarted = true
Expand Down
28 changes: 8 additions & 20 deletions embed-code-go/embedding/parsing/code_sample_line.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,23 @@

package parsing

import (
"embed-code/embed-code-go/configuration"
)
import "embed-code/embed-code-go/configuration"

// Represents a line of a code sample.
type CodeSampleLine struct{}
// CodeSampleLineState represents a line of a code sample.
type CodeSampleLineState struct{}

//
// Public methods
//

// Reports whether the current line is a code sample line.
//
// If codeFenceStarted is true and it's not the end of the file,
// the line is a code sample line.
// Recognize reports whether the current line is a code sample line: the code fence is started, and
// it is not the end of a file.
//
// context — a context of the parsing process.
func (c CodeSampleLine) Recognize(context ParsingContext) bool {
func (c CodeSampleLineState) Recognize(context Context) bool {
return !context.ReachedEOF() && context.CodeFenceStarted
}

// Moves to the next line.
// Accept moves to the next line.
//
// context — a context of the parsing process.
//
// config — a configuration of the embedding.
//
// This implementation never returns an error.
func (c CodeSampleLine) Accept(context *ParsingContext, _ configuration.Configuration) error {
func (c CodeSampleLineState) Accept(context *Context, _ configuration.Configuration) error {
context.ToNextLine()

return nil
Expand Down
Loading

0 comments on commit 2f3d88a

Please sign in to comment.