Skip to content
Merged
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
25 changes: 16 additions & 9 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,22 @@ const (
// CheckCodeSamples returns documentation files that are not up-to-date with code files.
//
// config — a configuration for checking code samples.
func CheckCodeSamples(config configuration.Configuration) []string {
func CheckCodeSamples(config configuration.Configuration) ([]string, error) {
return embedding.CheckUpToDate(config)
}

// EmbedCodeSamples embeds code fragments in documentation files.
//
// config — a configuration for embedding.
func EmbedCodeSamples(config configuration.Configuration) EmbedCodeSamplesResult {
embeddingResult := embedding.EmbedAll(config)
func EmbedCodeSamples(config configuration.Configuration) (EmbedCodeSamplesResult, error) {
embeddingResult, err := embedding.EmbedAll(config)
if err != nil {
return EmbedCodeSamplesResult{}, err
}

return EmbedCodeSamplesResult{
embeddingResult,
}
}, nil
}

// ReadArgs reads user-specified args from the command line.
Expand Down Expand Up @@ -154,7 +158,10 @@ func ReadArgs() Config {
//
// Returns filled Config.
func FillArgsFromConfigFile(args Config) (Config, error) {
configFields := readConfigFields(args.ConfigPath)
configFields, err := readConfigFields(args.ConfigPath)
if err != nil {
return args, err
}
slog.Info(fmt.Sprintf(
"Loaded config file `%s`. Found %d embedding setup(s).",
logging.FileReference(args.ConfigPath), len(configFields.Embeddings),
Expand Down Expand Up @@ -288,17 +295,17 @@ func parseListArgument(listArgument string) []string {
// configFilePath — a path to a yaml configuration file.
//
// Returns a filled ConfigFields struct.
func readConfigFields(configFilePath string) Config {
func readConfigFields(configFilePath string) (Config, error) {
content, err := os.ReadFile(configFilePath)
if err != nil {
panic(err)
return Config{}, err
}

configFields := Config{}
err = yaml.Unmarshal(content, &configFields)
if err != nil {
panic(err)
return Config{}, err
}

return configFields
return configFields, nil
}
91 changes: 51 additions & 40 deletions embedding/embedding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,15 @@ var _ = Describe("Embedding", func() {

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

Expect(processor.Embed()).Error().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)
processor := newProcessor(docPath, config)

Expect(processor.Embed()).Error().ShouldNot(HaveOccurred())
Expect(processor.IsUpToDate()).Should(BeTrue())
Expand All @@ -91,21 +91,21 @@ var _ = Describe("Embedding", func() {
parsing.RegularLine: {parsing.CodeFenceEnd},
}

falseProcessor := embedding.NewProcessorWithTransitions(docPath, config, falseTransitions)
falseProcessor := 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)
processor := newProcessor(docPath, config)
Expect(processor.Embed()).Error().ShouldNot(HaveOccurred())

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

It("should embed directly from source", func() {
docPath := fmt.Sprintf("%s/doc.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
processor := newProcessor(docPath, config)

Expect(processor.Embed()).Error().ShouldNot(HaveOccurred())

Expand All @@ -116,20 +116,23 @@ var _ = Describe("Embedding", func() {
config.DocIncludes = []string{"doc.md"}
docPath := fmt.Sprintf("%s/doc.md", config.DocumentationRoot)

Expect(embedding.CheckUpToDate(config)).Should(ContainElement(docPath))
outdatedFiles, err := embedding.CheckUpToDate(config)

Expect(err).ShouldNot(HaveOccurred())
Expect(outdatedFiles).Should(ContainElement(docPath))
})

It("should ignore embed-code samples inside markdown code fences", func() {
docPath := fmt.Sprintf("%s/embed-code-sample-in-fence.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
processor := newProcessor(docPath, config)

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

It("should detect markdown fences by triple-or-more backticks only", func() {
docPath := fmt.Sprintf("%s/triple-backticks-only-fence.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
processor := newProcessor(docPath, config)

Expect(processor.Embed()).Error().ShouldNot(HaveOccurred())

Expand All @@ -143,16 +146,10 @@ var _ = Describe("Embedding", func() {
It("should report all check errors", func() {
config.DocIncludes = []string{"missing-closing-tag.md", "unclosed-nested-tag.md"}

var recovered any
func() {
defer func() {
recovered = recover()
}()
embedding.CheckUpToDate(config)
}()
_, err := embedding.CheckUpToDate(config)

Expect(recovered).ShouldNot(BeNil())
Expect(fmt.Sprint(recovered)).Should(And(
Expect(err).Should(HaveOccurred())
Expect(err.Error()).Should(And(
ContainSubstring("missing-closing-tag.md"),
ContainSubstring("the `<embed-code>` tag is not closed"),
ContainSubstring("unclosed-nested-tag.md"),
Expand All @@ -163,16 +160,10 @@ var _ = Describe("Embedding", func() {
It("should report all pattern matching errors", func() {
config.DocIncludes = []string{"missing-start-pattern.md", "missing-end-pattern.md"}

var recovered any
func() {
defer func() {
recovered = recover()
}()
embedding.CheckUpToDate(config)
}()
_, err := embedding.CheckUpToDate(config)

Expect(recovered).ShouldNot(BeNil())
Expect(fmt.Sprint(recovered)).Should(And(
Expect(err).Should(HaveOccurred())
Expect(err.Error()).Should(And(
ContainSubstring("missing-start-pattern.md:3"),
ContainSubstring(
"no line in code file `file://",
Expand All @@ -191,7 +182,7 @@ var _ = Describe("Embedding", func() {

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)
processor := newProcessor(docPath, config)
Expect(processor.Embed()).Error().ShouldNot(HaveOccurred())

Expect(processor.IsUpToDate()).Should(BeTrue())
Expand All @@ -200,7 +191,7 @@ var _ = Describe("Embedding", func() {
It("should embed a method with escaped newline patterns", func() {
config.DocIncludes = []string{"escaped-newline-pattern.md"}
docPath := fmt.Sprintf("%s/escaped-newline-pattern.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
processor := newProcessor(docPath, config)

Expect(processor.Embed()).Error().ShouldNot(HaveOccurred())

Expand All @@ -215,7 +206,7 @@ var _ = Describe("Embedding", func() {
It("should embed a method with exact escaped newline patterns", func() {
config.DocIncludes = []string{"escaped-newline-exact-pattern.md"}
docPath := fmt.Sprintf("%s/escaped-newline-exact-pattern.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
processor := newProcessor(docPath, config)

Expect(processor.Embed()).Error().ShouldNot(HaveOccurred())

Expand All @@ -230,7 +221,7 @@ var _ = Describe("Embedding", func() {
It("should embed matching lines with an escaped newline line pattern", func() {
config.DocIncludes = []string{"escaped-newline-line-pattern.md"}
docPath := fmt.Sprintf("%s/escaped-newline-line-pattern.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
processor := newProcessor(docPath, config)

Expect(processor.Embed()).Error().ShouldNot(HaveOccurred())

Expand All @@ -245,7 +236,7 @@ var _ = Describe("Embedding", func() {
It("should embed a line with an escaped newline literal pattern", func() {
config.DocIncludes = []string{"escaped-newline-literal-pattern.md"}
docPath := fmt.Sprintf("%s/escaped-newline-literal-pattern.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
processor := newProcessor(docPath, config)

Expect(processor.Embed()).Error().ShouldNot(HaveOccurred())

Expand All @@ -258,7 +249,7 @@ var _ = Describe("Embedding", func() {

It("should report a missing closing tag", func() {
docPath := fmt.Sprintf("%s/missing-closing-tag.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
processor := newProcessor(docPath, config)

_, err := processor.Embed()

Expand All @@ -272,7 +263,7 @@ var _ = Describe("Embedding", func() {

It("should report the XML parser error", func() {
docPath := fmt.Sprintf("%s/unclosed-nested-tag.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
processor := newProcessor(docPath, config)

_, err := processor.Embed()

Expand All @@ -286,7 +277,7 @@ var _ = Describe("Embedding", func() {

It("should report a missing code fence after the instruction", func() {
docPath := fmt.Sprintf("%s/missing-code-fence.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
processor := newProcessor(docPath, config)

_, err := processor.Embed()

Expand All @@ -299,7 +290,7 @@ var _ = Describe("Embedding", func() {

It("should report an unclosed code fence after the instruction", func() {
docPath := fmt.Sprintf("%s/unclosed-code-fence.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
processor := newProcessor(docPath, config)

_, err := processor.Embed()

Expand All @@ -315,20 +306,19 @@ var _ = Describe("Embedding", func() {
config.DocIncludes = []string{"nested-dir-1/nested-dir-2/nested-dir-doc.md"}
docPath := fmt.Sprintf("%s/nested-dir-1/nested-dir-2/nested-dir-doc.md",
config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
processor := newProcessor(docPath, config)

Expect(func() {
embedding.EmbedAll(config)
}).NotTo(Panic())
_, err := embedding.EmbedAll(config)

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

It("should not embed to a file matched the `doc-excludes` pattern", func() {
config.DocExcludes = []string{"**/excluded-doc.*"}

docPath := fmt.Sprintf("%s/excluded-doc.md", config.DocumentationRoot)
processor := embedding.NewProcessor(docPath, config)
processor := newProcessor(docPath, config)

context, err := processor.Embed()

Expand All @@ -348,6 +338,27 @@ func buildConfigWithSourceFiles() configuration.Configuration {
return config
}

func newProcessor(
docPath string,
config configuration.Configuration,
) embedding.Processor {
processor, err := embedding.NewProcessor(docPath, config)

Expect(err).ShouldNot(HaveOccurred())
return processor
}

func newProcessorWithTransitions(
docPath string,
config configuration.Configuration,
transitions parsing.TransitionMap,
) embedding.Processor {
processor, err := embedding.NewProcessorWithTransitions(docPath, config, transitions)

Expect(err).ShouldNot(HaveOccurred())
return processor
}

func copyDirRecursive(sourceDirPath string, targetDirPath string) {
info, err := os.Stat(sourceDirPath)
if err != nil {
Expand Down
19 changes: 12 additions & 7 deletions embedding/parsing/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,18 @@ type ParsingContext struct {

// NewContext Creates and returns a new Context struct with initial values for markdownFile, source,
// lineIndex, and result.
func NewContext(markdownFile string) Context {
func NewContext(markdownFile string) (Context, error) {
source, err := readLines(markdownFile)
if err != nil {
return Context{}, err
}

return Context{
MarkdownFilePath: markdownFile,
Result: make([]string, 0),
source: readLines(markdownFile),
source: source,
lineIndex: 0,
}
}, nil
}

// NewEmptyContext creates a Context for a documentation file that was not parsed.
Expand Down Expand Up @@ -231,16 +236,16 @@ func (c *Context) readEmbeddingResult(context ParsingContext) []string {
return c.Result[context.resultStartIndex:context.resultEndIndex]
}

// Returns the content of a file placed at filepath as a list of strings.
func readLines(filepath string) []string {
// readLines returns the content of a file placed at filepath as a list of strings.
func readLines(filepath string) ([]string, error) {
bytes, err := os.ReadFile(filepath)
if err != nil {
panic(err)
return nil, err
}
str := string(bytes)
lines := regexp.MustCompile("\r?\n").Split(str, -1)

return lines
return lines, nil
}

func isStringSlicesEqual(first, second []string) bool {
Expand Down
Loading
Loading