Skip to content

Commit 4ae65d7

Browse files
committed
v0.3.0: Sync/Cast _liquid preamble block support
- Add `_liquid` block to prime templates: defines Liquid variables shared across all canonical block renders during sync. - Strip `_skip` and `_liquid` meta-blocks from output during init. - Expand cast_spec and add liquid_preamble_spec (263 examples, 0 failures). - Update README docs for `_liquid` preamble and `_skip` block behaviors. - Add limited Markdown skimming to SourceSkim. - Create skim_markup.rb to replace skim_asciidoc.rb (deprecated) - Bump version: 0.2.1 -> 0.3.0.
1 parent 25509a5 commit 4ae65d7

19 files changed

Lines changed: 1061 additions & 168 deletions

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
asciisourcerer (0.2.1)
4+
asciisourcerer (0.3.0)
55
asciidoctor (~> 2.0)
66
asciidoctor-html5s (~> 0.5)
77
jekyll (~> 4.4)

README.adoc

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ endif::[]
3737
:this_prod_name: {this_proj_name}
3838
// end::universal-settings[]
3939
:this_prod_vrsn_major: 0
40-
:this_prod_vrsn_minor: 2
40+
:this_prod_vrsn_minor: 3
4141
:this_prod_vrsn_majmin: {this_prod_vrsn_major}.{this_prod_vrsn_minor}
42-
:this_prod_vrsn_patch: 1
42+
:this_prod_vrsn_patch: 0
4343
:this_prod_vrsn: {this_prod_vrsn_majmin}.{this_prod_vrsn_patch}
44-
:next_prod_vrsn: 0.3.0
44+
:next_prod_vrsn: 0.4.0
4545
// end::global-settings[]
4646
:toc: macro
4747
:toclevels: 4
@@ -99,7 +99,7 @@ AsciiDoc-to-Markdown conversion::
9999
Convert AsciiDoc documents to Markdown for agentic consumption, with a focus on preserving semantic structure and document frontmatter.
100100
See <<markdowngrade>>.
101101

102-
AsciiDoc source inspection::
102+
AsciiDoc and Markdown source inspection::
103103
Skim AsciiDoc documents to produce machine-oriented outlines of sections, code blocks, tables, and other semantic elements for tooling and agent consumption.
104104
See <<source-skim>>.
105105

@@ -300,20 +300,21 @@ Override it per call with the `canonical_prefix:` keyword argument.
300300
Canonical blocks use AsciiDoc-style `tag::`/`end::` markers embedded inside comments.
301301
Three comment styles are recognized so the same prime can manage files of any type:
302302

303-
[cols="3m,5m",options="header"]
303+
[cols="3,5m",options="header"]
304304
|===
305305
| Style | Example
306-
| HTML / Markdown comment
307-
| <!-- tag::universal-intro[] -->
308-
| AsciiDoc line comment
306+
| HTML / Markdown
307+
| <!-- tag::universal-intro[] +++-->+++
308+
| AsciiDoc / JavaScript
309309
| // tag::universal-intro[]
310-
| Shell / Ruby / YAML comment
310+
| Shell / Ruby / YAML / INI
311311
| # tag::universal-intro[]
312312
|===
313313

314-
The trailing `[]` is optional in all three styles.
314+
A block with tag names beginning with the configured prefix (default `universal-`) is treated as canonical and managed by Sync/Cast.
315+
316+
Any block wrapped in `tag::_skip[]` and `end::_skip[]` will _not_ be passed from prime to target even during the init operation.
315317

316-
A tag whose name begins with the configured prefix (default `universal-`) is treated as canonical and managed by Sync/Cast.
317318
All other tagged regions in a target file are left entirely alone, and their presence beside a canonical block never triggers a warning.
318319

319320
[[sync-cast-operations]]
@@ -322,6 +323,8 @@ All other tagged regions in a target file are left entirely alone, and their pre
322323
init::
323324
One-time operation that renders the prime template (the whole file, not just canonical blocks) through Liquid and writes the result as a new target file.
324325
Use this to bootstrap a repo-local copy of a project template.
326+
+
327+
NOTE: Only blocks marked `_skip` are not carried over.
325328

326329
sync::
327330
Ongoing operation that scans for canonical blocks, replaces their content with the prime version (after optional Liquid rendering), and leaves everything else verbatim.
@@ -354,6 +357,18 @@ This is {{ data.variables.name }} version {{ data.variables.version }}.
354357
<!-- end::universal-intro[] -->
355358
----
356359

360+
Since each block is rendered independently, variables cannot reference content from other blocks.
361+
Use a segment wrapped in `_liquid` tags to set variables inline that will be used across all subsequent blocks.
362+
This `_liquid` segment only has access to variables passed into the main render call, not to any content blocks.
363+
364+
[source,markdown]
365+
----
366+
<!-- tag::_liquid -->
367+
{%- assign name = data.variables.this_proj_name | default: 'Unknown Project' %}
368+
{%- assign version = data.variables.this_prod_vrsn | default: '0.0.0' %}
369+
<!-- end::_liquid -->
370+
----
371+
357372
[[sync-cast-bootstrap]]
358373
==== Bootstrap example
359374

@@ -362,7 +377,7 @@ This is {{ data.variables.name }} version {{ data.variables.version }}.
362377
Sourcerer::Sync.init(
363378
'templates/AGENTS.markdown',
364379
'AGENTS.md',
365-
data: { 'project' => 'my-gem', 'org' => 'DocOps' }
380+
data: { 'project' => 'my-gem', 'org' => 'ACME Co' }
366381
)
367382
----
368383

@@ -421,10 +436,14 @@ Schema-aware filters (including SGYML-specific classification filters) should be
421436
[[source-skim]]
422437
=== SourceSkim
423438

424-
`Sourcerer::SourceSkim` generates machine-oriented _skims_ of AsciiDoc source documents.
439+
`Sourcerer::SourceSkim` generates machine-oriented _skims_ of AsciiDoc and Markdown source documents.
425440

426-
A skim is a structured, JSON/YAML-ready outline of selected source elements:
441+
A skim is a structured, JSON/YAML-ready outline of selected source elements.
442+
AsciiDoc skims include:
427443
sections, code blocks, definition lists, tables, images, and more.
444+
445+
Markdown skims include only sections and frontmatter, since other semantic elements are not reliably parseable in Markdown's freeform syntax.
446+
428447
Skims are intended to help tooling and agents inspect documentation source without ingesting full file contents.
429448

430449
.Example: Skim a file for sections and code blocks
@@ -441,13 +460,17 @@ skim = Sourcerer::SourceSkim.skim_file('docs/install.adoc', categories: [:code_b
441460
442461
# Skim inline content
443462
skim = Sourcerer::SourceSkim.skim_string(raw_adoc_content)
463+
464+
# Skim Markdown file with flat sections only
465+
skim = Sourcerer::SourceSkim.skim_file('README.md', forms: [:flat])
444466
----
445467

446468
Section shapes::
447469
Pass `forms: [:tree]` (default), `forms: [:flat]`, or both.
448470
Tree shape preserves nesting; flat shape adds `parent_id` and expresses child section IDs as an array.
449471

450472
Categories::
473+
(AsciiDoc skims only.)
451474
Default output includes `attributes_custom`, `definition_lists`, `code_blocks`, `literal_blocks`, `examples`, `sidebars`, `tables`, and `images`.
452475
Opt-in only (excluded by default): `attributes_builtin`, `admonitions`, `quotes`.
453476
Pass `categories:` with an explicit array of symbols to restrict or expand output.
@@ -457,6 +480,7 @@ The skim output schema is at `specs/data/asciidoc-source-skim.schema.json` and a
457480

458481
[[skim-asciidoctor-extension]]
459482
==== Asciidoctor extension
483+
460484
`Sourcerer::SourceSkim::TreeProcessorExtension` integrates SourceSkim into Asciidoctor parsing pipelines.
461485
It stores the result as the `source-skim-result` document attribute and reads `source-skim-forms` and `source-skim-categories` document attributes for per-document configuration.
462486

@@ -620,9 +644,10 @@ Use them as examples or utilities but do not rely on them in production.
620644

621645
Current scripts include: ::
622646

623-
link:https://github.com/DocOps/asciisourcerer/blob/main/scripts/skim_asciidoc.rb[`skim_asciidoc.rb`]:::
624-
For AsciiDoc source inspection.
625-
Generates YAML or JSON versions of `Sourcerer::SourceSkim` output for a given AsciiDoc document or collection of documents.
647+
link:https://github.com/DocOps/asciisourcerer/blob/main/scripts/skim_markup.rb[`skim_markup.rb`]:::
648+
(Formerly `skim_asciidoc.rb`.)
649+
For AsciiDoc/Markdown source inspection.
650+
Generates YAML or JSON versions of `Sourcerer::SourceSkim` output for a given AsciiDoc document, Markdown file, or collection of such.
626651

627652
link:https://github.com/DocOps/asciisourcerer/blob/main/scripts/mark_down_grade.rb[`mark_down_grade.rb`]:::
628653
For AsciiDoc-to-Markdown conversion.
@@ -655,14 +680,14 @@ For each script you wish to use:
655680
+
656681
.Example: writes current GH copy to a local `scripts/` path.
657682
[.prompt]
658-
curl -o scripts/skim_asciidoc.rb https://raw.githubusercontent.com/DocOps/asciisourcerer/refs/heads/main/scripts/skim_asciidoc.rb
683+
curl -o scripts/skim_markup.rb https://raw.githubusercontent.com/DocOps/asciisourcerer/refs/heads/main/scripts/skim_markup.rb
659684
+
660685
Change `-o scripts/` to wherever you wish to save the script locally.
661686

662687
. Run the script.
663688
+
664689
[.prompt]
665-
bundle exec ruby scripts/skim_asciidoc.rb --help
690+
bundle exec ruby scripts/skim_markup.rb --help
666691

667692

668693
[[development]]

lib/sourcerer.rb

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,18 @@
1717
# Requiring `sourcerer` also makes adjacent public constants (for example,
1818
# `Sourcerer::Builder`) available to downstream callers.
1919
module Sourcerer
20+
# File extensions recognised as Markdown source files.
21+
MARKDOWN_EXTS = %w[.md .markdown].freeze
22+
23+
# File extensions recognised as AsciiDoc source files.
24+
ASCIIDOC_EXTS = %w[.adoc .asciidoc .asc .ad].freeze
25+
2026
autoload :AttributesFilter, 'sourcerer/attributes_filter'
21-
autoload :Jekyll, 'sourcerer/jekyll'
22-
autoload :MarkDownGrade, 'sourcerer/mark_down_grade'
23-
autoload :SourceSkim, 'sourcerer/source_skim'
24-
autoload :Sync, 'sourcerer/sync'
27+
autoload :YamlFrontmatter, 'sourcerer/yaml_frontmatter'
28+
autoload :Jekyll, 'sourcerer/jekyll'
29+
autoload :MarkDownGrade, 'sourcerer/mark_down_grade'
30+
autoload :SourceSkim, 'sourcerer/source_skim'
31+
autoload :Sync, 'sourcerer/sync'
2532

2633
DEPRECATED_FACADE_METHODS = {
2734
# DO NOT add new public methods to this surface

lib/sourcerer/asciidoc.rb

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require 'fileutils'
55
require 'yaml'
66
require 'cgi'
7+
require_relative 'yaml_frontmatter'
78

89
module Sourcerer
910
# AsciiDoc-focused primitives for attribute loading, region extraction,
@@ -35,7 +36,7 @@ module Sourcerer
3536
#
3637
# @see https://asciidoctor.org/ Asciidoctor Documentation
3738
module AsciiDoc
38-
YAML_FRONTMATTER_REGEXP = /\A(---\s*\n.*?\n)(---\s*\n?)/m
39+
YAML_FRONTMATTER_REGEXP = Sourcerer::YamlFrontmatter::REGEXP
3940
YAML_FRONT_MATTER_REGEXP = YAML_FRONTMATTER_REGEXP
4041
PAGE_ATTRIBUTE_PREFIX = 'page-'
4142

@@ -327,22 +328,15 @@ def self.extract_page_attributes document_attributes
327328
# @param source_text [String]
328329
# @return [Hash]
329330
def self.extract_yaml_frontmatter source_text
330-
match = source_text.match(YAML_FRONTMATTER_REGEXP)
331-
return {} unless match
332-
333-
frontmatter_payload = match[1].sub(/\A---\s*\n/, '')
334-
parsed = YAML.safe_load(frontmatter_payload, aliases: true)
335-
parsed.is_a?(Hash) ? parsed : {}
336-
rescue Psych::SyntaxError
337-
{}
331+
Sourcerer::YamlFrontmatter.extract(source_text)
338332
end
339333

340334
# Remove leading YAML front matter fence block from AsciiDoc source.
341335
#
342336
# @param source_text [String]
343337
# @return [String]
344338
def self.strip_yaml_frontmatter source_text
345-
source_text.sub(YAML_FRONTMATTER_REGEXP, '')
339+
Sourcerer::YamlFrontmatter.strip(source_text)
346340
end
347341

348342
# Compatibility alias.
@@ -483,5 +477,65 @@ def self.ensure_document_title html_body, doctitle
483477
:normalize_extract_tags,
484478
:collect_tagged_content,
485479
:normalize_mark_down_grade_options
480+
481+
# Utilities for filtering and partitioning Asciidoctor document attributes.
482+
#
483+
# Separates user-defined ("custom") attributes from those injected by
484+
# Asciidoctor at parse time ("built-in").
485+
#
486+
# @example
487+
# custom = Sourcerer::AsciiDoc::AttributesFilter.user_attributes(doc)
488+
# builtin = Sourcerer::AsciiDoc::AttributesFilter.builtin_attributes(doc)
489+
module AttributesFilter
490+
# Attribute keys injected by Asciidoctor at parse time.
491+
BUILTIN_ATTR_KEYS = (Asciidoctor::DEFAULT_ATTRIBUTES.keys + %w[
492+
asciidoctor asciidoctor-version
493+
attribute-missing attribute-undefined
494+
authorcount
495+
docdate docdatetime docdir docfile docfilesuffix docname doctime doctitle doctype docyear
496+
embedded
497+
htmlsyntax
498+
iconsdir
499+
localdate localdatetime localtime localyear
500+
max-include-depth
501+
notitle
502+
outfilesuffix
503+
stylesdir
504+
toc-position
505+
user-home
506+
]).freeze
507+
508+
BUILTIN_ATTR_PATTERNS = [
509+
/^backend(-|$)/,
510+
/^basebackend(-|$)/,
511+
/^doctype-/,
512+
/^filetype(-|$)/,
513+
/^safe-mode-/
514+
].freeze
515+
516+
module_function
517+
518+
# Returns user-defined attributes, excluding Asciidoctor built-ins.
519+
#
520+
# @param doc [Asciidoctor::Document]
521+
# @return [Hash{String => String}]
522+
def user_attributes doc
523+
doc.attributes.reject do |k, _|
524+
BUILTIN_ATTR_KEYS.include?(k) ||
525+
BUILTIN_ATTR_PATTERNS.any? { |pat| pat.match?(k) }
526+
end
527+
end
528+
529+
# Returns built-in Asciidoctor attributes injected at parse time.
530+
#
531+
# @param doc [Asciidoctor::Document]
532+
# @return [Hash{String => String}]
533+
def builtin_attributes doc
534+
doc.attributes.select do |k, _|
535+
BUILTIN_ATTR_KEYS.include?(k) ||
536+
BUILTIN_ATTR_PATTERNS.any? { |pat| pat.match?(k) }
537+
end
538+
end
539+
end
486540
end
487541
end

lib/sourcerer/attributes_filter.rb

Lines changed: 0 additions & 72 deletions
This file was deleted.

0 commit comments

Comments
 (0)