{"id":42212913,"url":"https://github.com/foliant-docs/foliantcontrib.alt_structure","last_synced_at":"2026-01-27T01:06:55.111Z","repository":{"id":57431727,"uuid":"238901951","full_name":"foliant-docs/foliantcontrib.alt_structure","owner":"foliant-docs","description":"Generate alternative chapters structure","archived":false,"fork":false,"pushed_at":"2021-07-20T09:57:37.000Z","size":25,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-28T00:22:52.293Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/foliant-docs.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-02-07T10:59:28.000Z","updated_at":"2021-07-20T09:57:12.000Z","dependencies_parsed_at":"2022-09-02T12:40:17.417Z","dependency_job_id":null,"html_url":"https://github.com/foliant-docs/foliantcontrib.alt_structure","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/foliant-docs/foliantcontrib.alt_structure","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foliant-docs%2Ffoliantcontrib.alt_structure","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foliant-docs%2Ffoliantcontrib.alt_structure/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foliant-docs%2Ffoliantcontrib.alt_structure/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foliant-docs%2Ffoliantcontrib.alt_structure/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/foliant-docs","download_url":"https://codeload.github.com/foliant-docs/foliantcontrib.alt_structure/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foliant-docs%2Ffoliantcontrib.alt_structure/sbom","scorecard":{"id":406054,"data":{"date":"2025-08-11","repo":{"name":"github.com/foliant-docs/foliantcontrib.alt_structure","commit":"1ceec56ff13d0ebb8cb60598aa8be21d9692b314"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/11 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-18T21:17:28.761Z","repository_id":57431727,"created_at":"2025-08-18T21:17:28.761Z","updated_at":"2025-08-18T21:17:28.761Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28794642,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-26T21:49:50.245Z","status":"ssl_error","status_checked_at":"2026-01-26T21:48:29.455Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-27T01:06:54.104Z","updated_at":"2026-01-27T01:06:55.087Z","avatar_url":"https://github.com/foliant-docs.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![](https://img.shields.io/pypi/v/foliantcontrib.alt_structure.svg)](https://pypi.org/project/foliantcontrib.alt_structure/) [![](https://img.shields.io/github/v/tag/foliant-docs/foliantcontrib.alt_structure.svg?label=GitHub)](https://github.com/foliant-docs/foliantcontrib.alt_structure)\n\n# AltStructure Extension\n\nAltStructure is a config extension for Foliant to generate alternative chapter structure based on metadata.\n\nIt adds an `alt_structure` preprocessor and resolves `!alt_structure` YAML tags in the project config.\n\n## Installation\n\n```bash\n$ pip install foliantcontrib.alt_structure\n```\n\n## Configuration\n\n**Config extension**\n\nOptions for AltStructure are specified in the `alt_structure` section at the root of Foliant config file:\n\n```yaml\nalt_structure:\n    structure:\n        topic:\n            entity:\n        additional:\n    add_unmatched_to_root: false\n    registry:\n        auth: Аутентификация и авторизация\n        weather: Погода\n        test_case: Тест кейсы\n        spec: Спецификации\n```\n\n`structure`\n:   *(required)* A mapping tree, representing alternative structure.\n\n`add_unmatched_to_root`\n:   if `true`, all chapters that weren't matched to structure in metadata will be added to root of the chapter tree. If `false` — they will be ignored. Default: `false`\n\n`registry`\n:   A dictionary which defines aliases for chapter tree categories.\n\n**Preprocessor**\n\nPreprocessor has just one option:\n\n```yaml\npreprocessors:\n    - alt_structure:\n        create_subfolders: true\n```\n\n`create_subfolders`\n:   If `true`, preprocessor will create a full copy of the working_dir and add it to the beginning of all filepaths in the generated structure. If `false` — preprocessor doesn't do anything. Default: `true`\n\n## Usage\n\n**Step 1**\n\nAdd `!alt_structure` tag to your chapters in the place where you expect new structure to be generated. It accepts one argument: list of chapters, which will be scanned.\n\n```yaml\nchapters:\n    - basic:  # \u003c-- this is _chapter tree category_\n        - auth/auth.md\n        - index.md\n        - auth/test_auth.md\n        - auth/test_auth_aux.md\n        - weather.md\n        - glossary.md\n        - auth/spec_auth.md\n        - test_weather.md\n    - Alternative: !alt_structure\n        - auth/auth.md\n        - index.md\n        - auth/test_auth.md\n        - auth/test_auth_aux.md\n        - weather.md\n        - glossary.md\n        - auth/spec_auth.md\n        - test_weather.md\n```\n\n\u003e AltStructure extension introduces a lot of new notions, so let's agree on some terms to make sure we are on the same page. _Chapter tree category_ is a mapping with single key which you add to your chapter list to create hierarchy. `basic:` and `Alternative:` are categories in this example.\n\nYou can also utilize YAML anchors and aliases, but in this case, because of language limitation you need to supply alias inside a list. Let's use it to get the same result as the above, but in a more compact way:\n\n```yaml\nchapters:\n    - basic: \u0026basic\n        - auth/auth.md\n        - index.md\n        - auth/test_auth.md\n        - auth/test_auth_aux.md\n        - weather.md\n        - glossary.md\n        - auth/spec_auth.md\n        - test_weather.md\n    - Alternative: !alt_structure [*basic]\n```\n\n**Step 2**\n\nNext you need to define the structure in `structure` parameter of extension config. It is defined by a mapping tree of *node types*. For example:\n\n```yaml\nalt_structure:\n    structure:\n        topic:  # topic is the upmost node type\n            entity:  # nodes with type \"entity\" will be nested in \"topic\"\n        additional:\n            glossaries:\n```\n\nThese names of the node types are arbitrary, you can use any words you like except `root` and `subfolder`.\n\n**Step 3**\n\nOpen your source md-files and edit their *main meta sections*. Main meta section is a section, defined before the first heading in the document (check [metadata documentation](https://foliant-docs.github.io/docs/meta/) for more info). Add a mapping with nodes for this chapter under the key `structure`.\n\nfile auth_spec.md\n```yaml\n---\nstructure:\n    topic: auth  # \u003c-- node type: node name\n    entity: spec\n---\n\n# Specification for authorization\n```\n\nHere `topic` and `entity` are node types, which are part of our structure (step 2). `auth` and `spec` are *node names*. After applying `!alt_structure` tag nodes will be converted into chapter tree categories. Node type defines the level of the category and node name defines the caption of the category.\n\nWe've added two nodes to the `structure` field of chapter metadata: `topic: auth` and `entity: spec`. In the structure that we've defined on step 2 the `topic` goes first and `entity` — second. So after applying the tag, this chapter will appear in config like this:\n\n```yaml\n- auth:\n    - spec:\n        - auth_spec.md\n```\n\nIf we'd stated only `topic` key in metadata, then it would look like this:\n\n```yaml\n- auth:\n    - auth_spec.md\n```\n\n**Step 4**\n\nNow let's fill up registry. We used `spec` and `auth` in our metadata for node names, but these words don't look pretty in the documents. Registry allows us to set verbose captions for node names in config:\n\n```yaml\nalt_structure:\n    structure:\n        - ['topic', 'entity']\n        - 'additional/glossaries'\n    registry:\n        auth: Authentication and Authorization\n        spec: Specifications\n```\n\nWith such registry now our new structure will look like this:\n\n```yaml\n- Authentication and Authorization:\n    - Specifications:\n        - auth_spec.md\n```\n\n### Special node types\n\nIn the step 2 of the user guide above we've mentioned that you may choose any node names in the structure except `root` and `subfolder`. These are special note types and here's how you can use them.\n\n**root**\n\nFor example, if our structure looks like this:\n\n```yaml\nalt_structure:\n    structure:\n        topic:\n            entity:\n```\n\nand our chapter's metadata looks like this:\n\n```yaml\n---\nstructure:\n    foo: bar\n---\n```\n\nThe node `foo: bar` is not part of the structure, so applying the `!alt_structure` tag it will just be ignored (unless `add_unmatched_to_root` is set to `true` in config). But what if you want to add it to the root of your chapter tree?\n\nTo do that — add the `root` node to your metadata:\n\n```yaml\n---\nstructure:\n    foo: bar\n    root: true  # the value of the key `root` is ignored, we use `true` for clarity\n---\n```\n\n**subfolder**\n\nBy defining `subfolder` node in chapter's metadata you can manually add another chapter tree category to any chapter.\n\nFor example:\n\nfile auth_spec.md\n```yaml\n---\nstructure:\n    topic: auth\n    entity: spec\n    subfolder: Main specifications\n---\n```\n\nAfter applying tag the new structure will look like this:\n\n```yaml\n- auth:\n    - spec:\n        - Main specifications:\n            - auth_spec.md\n```\n\n### Using preprocessor\n\nBy default the `!alt_structure` tag only affects the `chapters` section of your foliant.yml. This may lead to situation when the same file is mentioned several times in the `chapters` section. While most backends are fine with that — they will just publish the file two times, [MkDocs](https://foliant-docs.github.io/docs/backends/mkdocs/) does not handle this situation well.\n\nThat's where you will need to add the preprocessor `alt_structure` to your preprocessors list. Preprocessor creates a subfolder in the working_dir and copies the entier working_dir contents into it. Then it inserts the subfolder name into the beginning of all chapters paths in the alternative structure.\n\n\u003e **Important:** It is recommended to add this preprocessor to the end of the preprocessors list.\n\n```yaml\n\npreprocessors:\n    ...\n    alt_structure:\n        create_subfolders: true\n```\n\nNote, that the parameter `create_subfolders` is not necessary, it is `true` by default. But we recommend to state it anyway for clarity.\n\nAfter applying the tag, your new structure will now look like this:\n\n```yaml\n- Authentication and Authorization:\n    - Specifications:\n        - alt1/auth_spec.md\n```\n\nThe contents of the working_dir were copied into a subdir `alt1`, and new structure refers to the files in this subdir.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoliant-docs%2Ffoliantcontrib.alt_structure","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffoliant-docs%2Ffoliantcontrib.alt_structure","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoliant-docs%2Ffoliantcontrib.alt_structure/lists"}