diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..6313b56
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=auto eol=lf
diff --git a/analyzing/analyzing.go b/analyzing/analyzing.go
index 80fb652..904fe10 100644
--- a/analyzing/analyzing.go
+++ b/analyzing/analyzing.go
@@ -3,7 +3,7 @@ package analyzing
import (
"fmt"
"os"
- "strings"
+ "path/filepath"
"embed-code/embed-code-go/configuration"
"embed-code/embed-code-go/embedding"
@@ -38,7 +38,7 @@ func AnalyzeAll(config configuration.Configuration) {
// Generates a path to a given file in the analytics directory.
func pathToFile(fileName string) string {
- return fmt.Sprintf("%s/%s", analyticsDir, fileName)
+ return filepath.Join(analyticsDir, fileName)
}
// Finds all documentation files for given config.
@@ -47,12 +47,14 @@ func findDocumentationFiles(config configuration.Configuration) []string {
docPatterns := config.DocIncludes
var documentationFiles []string
for _, pattern := range docPatterns {
- globString := strings.Join([]string{documentationRoot, pattern}, "/")
+ globString := filepath.Join(documentationRoot, filepath.FromSlash(pattern))
matches, err := doublestar.FilepathGlob(globString)
if err != nil {
panic(err)
}
- documentationFiles = append(documentationFiles, matches...)
+ for _, match := range matches {
+ documentationFiles = append(documentationFiles, filepath.ToSlash(match))
+ }
}
return documentationFiles
diff --git a/embedding/embedding_test.go b/embedding/embedding_test.go
index 7262c4e..0463ef7 100644
--- a/embedding/embedding_test.go
+++ b/embedding/embedding_test.go
@@ -107,6 +107,42 @@ var _ = Describe("Embedding", func() {
Expect(processor.IsUpToDate()).Should(BeTrue())
})
+ It("should embed with multi lined tag attributes", func() {
+ docPath := fmt.Sprintf("%s/multi-lined-valid-tag-attributes.md", config.DocumentationRoot)
+ processor := embedding.NewProcessor(docPath, config)
+ Expect(processor.Embed()).Error().ShouldNot(HaveOccurred())
+
+ Expect(processor.IsUpToDate()).Should(BeTrue())
+ })
+
+ It("should report a missing closing tag", func() {
+ docPath := fmt.Sprintf("%s/missing-closing-tag.md", config.DocumentationRoot)
+ processor := embedding.NewProcessor(docPath, config)
+
+ _, err := processor.Embed()
+
+ Expect(err).Should(HaveOccurred())
+ Expect(err.Error()).Should(ContainSubstring(
+ "missing-closing-tag.md:3`: " +
+ "failed to parse an embedding instruction: " +
+ "the `` tag is not closed",
+ ))
+ })
+
+ It("should report the XML parser error", func() {
+ docPath := fmt.Sprintf("%s/unclosed-nested-tag.md", config.DocumentationRoot)
+ processor := embedding.NewProcessor(docPath, config)
+
+ _, err := processor.Embed()
+
+ Expect(err).Should(HaveOccurred())
+ Expect(err.Error()).Should(ContainSubstring(
+ "unclosed-nested-tag.md:3`: " +
+ "failed to parse an embedding instruction: " +
+ "element closed by ",
+ ))
+ })
+
// TODO:olena-zmiiova:https://github.com/SpineEventEngine/embed-code/issues/65
It("should successfully embed to a file in a nested dir", func() {
Skip(
diff --git a/embedding/parsing/constants.go b/embedding/parsing/constants.go
index e1f9110..325ad86 100644
--- a/embedding/parsing/constants.go
+++ b/embedding/parsing/constants.go
@@ -18,8 +18,8 @@
package parsing
-// EmbeddingTag is a StartState of a tag where it requires to embed the code.
-const EmbeddingTag = "") &&
+ !strings.Contains(instruction, ""+EmbeddingTag+">") {
+ return fmt.Sprintf("the `<%s>` tag is not closed",
+ EmbeddingTag,
+ )
+ }
+ if parseErr != nil {
+ var syntaxErr *xml.SyntaxError
+ if errors.As(parseErr, &syntaxErr) {
+ return syntaxErr.Msg
+ }
+ return parseErr.Error()
+ }
+
+ return "invalid embedding instruction"
+}
diff --git a/embedding/parsing/xml_parse.go b/embedding/parsing/xml_parse.go
index 63840cc..4fe51b1 100644
--- a/embedding/parsing/xml_parse.go
+++ b/embedding/parsing/xml_parse.go
@@ -24,8 +24,6 @@ import (
"fmt"
)
-const xmlStringHeader string = "embed-code"
-
// Item needed for xml.Unmarshal parsing. The fields are filling up during the parsing.
//
// XMLName — a name of the tag in XML line.
@@ -74,9 +72,9 @@ func ParseXMLLine(xmlLine string) (map[string]string, error) {
return map[string]string{}, err
}
- if root.XMLName.Local != xmlStringHeader {
+ if root.XMLName.Local != EmbeddingTag {
return map[string]string{},
- fmt.Errorf("the provided line's header is not 'embed-code':\n%s", xmlLine)
+ fmt.Errorf("the provided line's header is not `%s`:\n%s", EmbeddingTag, xmlLine)
}
attributes := make(map[string]string)
diff --git a/embedding/processor.go b/embedding/processor.go
index 839fda0..b612947 100644
--- a/embedding/processor.go
+++ b/embedding/processor.go
@@ -217,13 +217,13 @@ func (p Processor) fillEmbeddingContext() (parsing.Context, error) {
for currentState != finishState {
accepted, newState, err := p.moveToNextState(¤tState, &context)
if err != nil {
- return context, fmt.Errorf(errorStr, absDocPath, context.CurrentEmbedding().SourceStartIndex-1, err)
+ return context, fmt.Errorf(errorStr, absDocPath, errorLine(context, err), err)
}
if !accepted {
currentState = &parsing.RegularLineState{}
context.ResolveUnacceptedEmbedding()
- return context, fmt.Errorf(errorStr, absDocPath, context.CurrentEmbedding().SourceStartIndex-1, err)
+ return context, fmt.Errorf(errorStr, absDocPath, errorLine(context, err), err)
}
currentState = *newState
}
@@ -231,6 +231,19 @@ func (p Processor) fillEmbeddingContext() (parsing.Context, error) {
return context, nil
}
+// errorLine returns the source line that should be used in the embedding error location.
+func errorLine(context parsing.Context, err error) int {
+ var parseErr parsing.InstructionParseError
+ if errors.As(err, &parseErr) {
+ return parseErr.Line
+ }
+ if context.EmbeddingsCount() > 0 {
+ return context.CurrentEmbedding().SourceStartIndex - 1
+ }
+
+ return context.CurrentIndex()
+}
+
// Moves to the next state accordingly to a transition map from the current state. Reports whether
// it successfully moved to the next state and returns the new state.
func (p Processor) moveToNextState(state *parsing.State, context *parsing.Context) (
@@ -289,12 +302,14 @@ func requiredDocs(config configuration.Configuration) []string {
func getFilesByPatterns(root string, patterns []string) ([]string, error) {
var result []string
for _, pattern := range patterns {
- globString := strings.Join([]string{root, pattern}, "/")
+ globString := filepath.Join(root, filepath.FromSlash(pattern))
matches, err := doublestar.FilepathGlob(globString)
if err != nil {
return nil, err
}
- result = append(result, matches...)
+ for _, match := range matches {
+ result = append(result, filepath.ToSlash(match))
+ }
}
return result, nil
diff --git a/files/files.go b/files/files.go
index 78b9ec8..0464acd 100644
--- a/files/files.go
+++ b/files/files.go
@@ -90,7 +90,7 @@ func BuildDocRelativePath(absolutePath string, config configuration.Configuratio
panic(err)
}
- return relativePath
+ return filepath.ToSlash(relativePath)
}
// EnsureDirExists creates dir at given path (relative or absolute) if it doesn't exist.
diff --git a/fragmentation/fragment_file.go b/fragmentation/fragment_file.go
index c3b465e..9794ca3 100644
--- a/fragmentation/fragment_file.go
+++ b/fragmentation/fragment_file.go
@@ -20,15 +20,16 @@ package fragmentation
import (
"crypto/sha256"
- _type "embed-code/embed-code-go/type"
"encoding/hex"
"fmt"
"os"
+ "path"
"path/filepath"
"strings"
config "embed-code/embed-code-go/configuration"
"embed-code/embed-code-go/files"
+ _type "embed-code/embed-code-go/type"
)
// FragmentFile is a file storing a single fragment from the file.
@@ -73,7 +74,9 @@ func NewFragmentFileFromAbsolute(
}
if strings.TrimSpace(codeRoot.Name) != "" {
- relativePath = filepath.Join(NamedPathPrefix+codeRoot.Name, relativePath)
+ relativePath = path.Join(NamedPathPrefix+codeRoot.Name, filepath.ToSlash(relativePath))
+ } else {
+ relativePath = filepath.ToSlash(relativePath)
}
return FragmentFile{
@@ -143,10 +146,10 @@ func (f FragmentFile) absolutePath() string {
}
if f.FragmentName == DefaultFragmentName {
- return filepath.Join(fragmentsAbsDir, f.CodePath)
+ return filepath.Join(fragmentsAbsDir, filepath.FromSlash(f.CodePath))
}
- withoutExtension := strings.TrimSuffix(f.CodePath, fileExtension)
+ withoutExtension := filepath.FromSlash(strings.TrimSuffix(f.CodePath, fileExtension))
filename := fmt.Sprintf("%s-%s", withoutExtension, f.fragmentHash())
return filepath.Join(fragmentsAbsDir, filename+fileExtension)
diff --git a/main.go b/main.go
index d78aabf..f40913a 100644
--- a/main.go
+++ b/main.go
@@ -28,7 +28,7 @@ import (
)
// Version of the embed-code application.
-const Version = "1.1.0"
+const Version = "1.1.1"
// The entry point for embed-code.
//
diff --git a/test/resources/docs/missing-closing-tag.md b/test/resources/docs/missing-closing-tag.md
new file mode 100644
index 0000000..50d9df6
--- /dev/null
+++ b/test/resources/docs/missing-closing-tag.md
@@ -0,0 +1,5 @@
+# Test missing closing tag
+
+
+```java
+```
diff --git a/test/resources/docs/multi-lined-valid-tag-attributes.md b/test/resources/docs/multi-lined-valid-tag-attributes.md
new file mode 100644
index 0000000..772e954
--- /dev/null
+++ b/test/resources/docs/multi-lined-valid-tag-attributes.md
@@ -0,0 +1,8 @@
+# Test multiline attributes
+
+
+```java
+```
diff --git a/test/resources/docs/unclosed-nested-tag.md b/test/resources/docs/unclosed-nested-tag.md
new file mode 100644
index 0000000..cbc1ff1
--- /dev/null
+++ b/test/resources/docs/unclosed-nested-tag.md
@@ -0,0 +1,5 @@
+# Test unclosed nested tag
+
+
+```java
+```