├── static ├── .nojekyll └── img │ ├── favicon.ico │ ├── old │ ├── favicon.ico │ └── logo.svg │ ├── gura-thumbnail.png │ ├── logos │ ├── gura-200.png │ ├── gura-500.png │ └── gura-thumbnail.png │ ├── differences │ ├── gura.png │ ├── json.png │ ├── toml.png │ └── yaml.png │ ├── features │ ├── simple.png │ ├── friendly.png │ └── robustness.png │ └── logos-usage │ ├── blog.png │ ├── development.png │ └── IDE-extension.png ├── docs ├── Developers │ ├── _category_.yml │ ├── introduction.md │ ├── availability.md │ ├── parsing.md │ ├── abnf.md │ └── tokenization.md ├── conventions.md ├── gura.md ├── changelog.md └── spec.md ├── versions.json ├── .vscode └── settings.json ├── CHANGELOG.md ├── src ├── theme │ └── CodeSnippet │ │ ├── styles.module.css │ │ └── index.js ├── components │ ├── HomepageFeatures.module.css │ ├── ResourcesUsage │ │ ├── ResourcesUsage.module.css │ │ └── ResourcesUsage.tsx │ ├── ResourceList │ │ ├── ResourceList.module.css │ │ └── ResourceList.tsx │ ├── HomepageFeatures.tsx │ ├── FeaturesReview │ │ └── FeaturesReview.tsx │ └── Differences │ │ └── Differences.tsx ├── pages │ ├── index.module.css │ ├── resources.tsx │ └── index.tsx ├── prism_themes │ ├── monokai │ │ └── index.js │ └── github │ │ └── index.js └── css │ └── custom.scss ├── babel.config.js ├── versioned_sidebars └── version-1.0.0-sidebars.json ├── tsconfig.json ├── .gitignore ├── sidebars.js ├── versioned_docs └── version-1.0.0 │ ├── conventions.md │ ├── gura.md │ ├── abnf.md │ └── spec.md ├── LICENSE ├── package.json ├── docusaurus.config.js └── README.md /static/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/Developers/_category_.yml: -------------------------------------------------------------------------------- 1 | position: 5 -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | [ 2 | "1.0.0" 3 | ] 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true 3 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.1.0 / 2013-03-17 2 | 3 | * First release. 4 | -------------------------------------------------------------------------------- /src/theme/CodeSnippet/styles.module.css: -------------------------------------------------------------------------------- 1 | .codeSnippet { 2 | font-size: 10pt; 3 | } -------------------------------------------------------------------------------- /static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/favicon.ico -------------------------------------------------------------------------------- /static/img/old/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/old/favicon.ico -------------------------------------------------------------------------------- /static/img/gura-thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/gura-thumbnail.png -------------------------------------------------------------------------------- /static/img/logos/gura-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/logos/gura-200.png -------------------------------------------------------------------------------- /static/img/logos/gura-500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/logos/gura-500.png -------------------------------------------------------------------------------- /static/img/differences/gura.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/differences/gura.png -------------------------------------------------------------------------------- /static/img/differences/json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/differences/json.png -------------------------------------------------------------------------------- /static/img/differences/toml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/differences/toml.png -------------------------------------------------------------------------------- /static/img/differences/yaml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/differences/yaml.png -------------------------------------------------------------------------------- /static/img/features/simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/features/simple.png -------------------------------------------------------------------------------- /static/img/logos-usage/blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/logos-usage/blog.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /static/img/features/friendly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/features/friendly.png -------------------------------------------------------------------------------- /static/img/features/robustness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/features/robustness.png -------------------------------------------------------------------------------- /static/img/logos/gura-thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/logos/gura-thumbnail.png -------------------------------------------------------------------------------- /static/img/logos-usage/development.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/logos-usage/development.png -------------------------------------------------------------------------------- /static/img/logos-usage/IDE-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gura-conf/gura/HEAD/static/img/logos-usage/IDE-extension.png -------------------------------------------------------------------------------- /versioned_sidebars/version-1.0.0-sidebars.json: -------------------------------------------------------------------------------- 1 | { 2 | "version-1.0.0/guraSidebar": [ 3 | { 4 | "type": "autogenerated", 5 | "dirName": "." 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /src/components/HomepageFeatures.module.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable docusaurus/copyright-header */ 2 | 3 | .features { 4 | display: flex; 5 | align-items: center; 6 | padding: 2rem 0; 7 | width: 100%; 8 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/docusaurus/tsconfig.json", 3 | "include": [ 4 | "src/" 5 | ], 6 | "compilerOptions": { 7 | "jsx": "react", 8 | "moduleResolution": "node" 9 | } 10 | } -------------------------------------------------------------------------------- /src/components/ResourcesUsage/ResourcesUsage.module.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable docusaurus/copyright-header */ 2 | 3 | .usage-img { 4 | border-radius: 5px; 5 | } 6 | 7 | @media screen and (max-width: 966px) { 8 | .usage-img { 9 | margin-top: 10%; 10 | } 11 | } -------------------------------------------------------------------------------- /src/components/ResourceList/ResourceList.module.css: -------------------------------------------------------------------------------- 1 | .logo-img { 2 | height: 200px; 3 | width: 200px; 4 | } 5 | 6 | @media screen and (max-width: 966px) { 7 | .logo-img { 8 | float: left; 9 | } 10 | 11 | .download-buttons-div { 12 | display: inline; 13 | vertical-align: text-bottom; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | module.exports = { 13 | // By default, Docusaurus generates a sidebar from the docs folder structure 14 | guraSidebar: [{type: 'autogenerated', dirName: '.'}], 15 | }; 16 | -------------------------------------------------------------------------------- /src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable docusaurus/copyright-header */ 2 | 3 | /** 4 | * CSS files with the .module.css suffix will be treated as CSS modules 5 | * and scoped locally. 6 | */ 7 | 8 | .mainBanner { 9 | padding: 4rem 0; 10 | /* text-align: center; */ 11 | position: relative; 12 | overflow: hidden; 13 | } 14 | 15 | @media screen and (max-width: 966px) { 16 | .mainBanner { 17 | padding: 2rem; 18 | } 19 | } 20 | 21 | .buttons { 22 | display: flex; 23 | align-items: left; 24 | justify-content: left; 25 | } 26 | -------------------------------------------------------------------------------- /versioned_docs/version-1.0.0/conventions.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Conventions 6 | 7 | 8 | ## Filename Extension 9 | 10 | Gura files should use the extension `.ura`. 11 | 12 | 13 | ## File naming convention 14 | 15 | As with keys, file names should have short, all-lowercase names and underscores can be used if it improves readability. 16 | 17 | 18 | ## MIME Type 19 | 20 | When transferring Gura files over the internet, the appropriate MIME type is `application/gura`. 21 | 22 | 23 | ## ABNF Grammar 24 | 25 | A formal description of Gura's syntax is available in the [ABNF section][abnf]. 26 | 27 | 28 | ## License 29 | 30 | Gura is distributed under the terms of the MIT license. 31 | 32 | 33 | [abnf]: abnf.md -------------------------------------------------------------------------------- /docs/conventions.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | description: 'Gura conventions and license' 4 | keywords: ['File name extension', 'Conventions', 'MIME', 'ABNF', 'License'] 5 | --- 6 | 7 | # Conventions 8 | 9 | 10 | ## Filename extension 11 | 12 | Gura files should use the extension `.ura`. 13 | 14 | 15 | ## File naming convention 16 | 17 | As with keys, file names should have short, all-lowercase names and underscores can be used if it improves readability. 18 | 19 | 20 | ## MIME type 21 | 22 | When transferring Gura files over the internet, the appropriate MIME type is `application/gura`. 23 | 24 | 25 | ## ABNF grammar 26 | 27 | A formal description of Gura's syntax is available in the [ABNF section][abnf]. 28 | 29 | 30 | ## License 31 | 32 | Gura is distributed under the terms of the MIT license. 33 | 34 | 35 | [abnf]: Developers/abnf.md 36 | -------------------------------------------------------------------------------- /versioned_docs/version-1.0.0/gura.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | 6 | # Gura 7 | 8 | Gura configuration file. 9 | 10 | By Jware solutions. 11 | 12 | 13 | 14 | 15 | ## Objectives 16 | 17 | Gura aims to be a minimal configuration file format that's easy to read due to its similarity with YAML. The key of the language is that there is one and only one way to do things. That feature make it ease to learn, parse, implement and understand. 18 | 19 | 20 | ## Standard errors 21 | 22 | The Gura specifications define the semantic errors that should be thrown in certain situations to define implementation-agnostic behavior so that you can receive the same type of error regardless of the programming language from which you are using Gura. 23 | 24 | Each type of error will be mentioned in the respective sections. 25 | -------------------------------------------------------------------------------- /src/prism_themes/monokai/index.js: -------------------------------------------------------------------------------- 1 | // Converted automatically using ./tools/themeFromVsCode 2 | var theme = { 3 | "plain": { 4 | "color": "#f8f8f2", 5 | "backgroundColor": "#272822" 6 | }, 7 | "styles": [{ 8 | "types": ["comment"], 9 | "style": { 10 | "color": "rgb(136, 132, 111)" 11 | } 12 | }, { 13 | "types": ["string", "changed"], 14 | "style": { 15 | "color": "rgb(230, 219, 116)" 16 | } 17 | }, { 18 | "types": ["punctuation", "tag", "deleted"], 19 | "style": { 20 | "color": "rgb(249, 38, 114)" 21 | } 22 | }, { 23 | "types": ["number", "builtin"], 24 | "style": { 25 | "color": "rgb(174, 129, 255)" 26 | } 27 | }, { 28 | "types": ["variable"], 29 | "style": { 30 | "color": "rgb(248, 248, 242)" 31 | } 32 | }, { 33 | "types": ["function", "attr-name", "inserted"], 34 | "style": { 35 | "color": "rgb(166, 226, 46)" 36 | } 37 | }] 38 | }; 39 | module.exports = theme; 40 | -------------------------------------------------------------------------------- /docs/gura.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | description: 'Gura documentation introduction' 4 | keywords: ['Gura', 'Config lang', 'Gura documentation'] 5 | --- 6 | 7 | 8 | # Gura 9 | 10 | Gura configuration language. By [JWare solutions][jware-organization]. 11 | 12 | 13 | 14 | 15 | ## Objectives 16 | 17 | Gura aims to be a minimal configuration file format that's easy to read due to its similarity with YAML. The key of the language is that there is one and only one way to do things. That feature make it ease to learn, parse, implement and understand. 18 | 19 | 20 | ## Standard errors 21 | 22 | The Gura specifications define the semantic errors that should be thrown in certain situations to define implementation-agnostic behavior so that you can receive the same type of error regardless of the programming language from which you are using Gura. 23 | 24 | Each type of error will be mentioned in the respective sections. 25 | 26 | 27 | [jware-organization]: https://github.com/jware-solutions/ 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 JWare Solutions 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /docs/Developers/introduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | sidebar_position: 1 4 | --- 5 | 6 | # Developers section 7 | 8 | The following section is intended for those developers who want to implement Gura, if you are implementing a parser, a serialization/deserialization tool, a content generator in Gura format, or any other project that uses this language, this section is for you! 9 | 10 | If you are looking for the language specifications to use in your projects, you can check the [official specifications][specs] or use an [existing implementation][implementations]. 11 | 12 | This section will detail the basic structure that your future implementation should cover, such as the data types, errors that should be thrown in certain situations, conventions, etc. Some resources that may be useful are also provided. 13 | 14 | If you are a designer and you are looking for official resources for your designs, you can check the [Resources section][resources] where the official logos are available for free usage. 15 | 16 | 17 | [specs]: /docs/gura 18 | [implementations]: https://github.com/gura-conf/gura#library-implementations 19 | [resources]: /resources 20 | -------------------------------------------------------------------------------- /src/pages/resources.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Layout from "@theme/Layout"; 3 | import { ResourcesUsage } from '../components/ResourcesUsage/ResourcesUsage' 4 | import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; 5 | import styles from "./index.module.css"; 6 | import { ResourceList } from '../components/ResourceList/ResourceList' 7 | 8 | 9 | export default function ResourcesPage() { 10 | const { siteConfig } = useDocusaurusContext(); 11 | const pageTitle = `${siteConfig.title} Official branding` 12 | 13 | return ( 14 | 15 |
16 |
17 |
18 |
19 |

{pageTitle}

20 |

21 | If you are developing your own tool for Gura management, be it a parser, an IDE extension or just want to mention the language, you are free to use our official logos. 22 |

23 |
24 |
25 | 26 |
27 |
28 |
29 |
30 | 31 |
32 | 33 |
34 |
35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /docs/Developers/availability.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Availability 3 | sidebar_position: 5 4 | --- 5 | 6 | Even if you are developing a parser or a tokenizer. It is strongly recommended that the source code of the tools be made available, as it is easier to access it, report bugs, promote collaboration between the different developers and empower Gura. 7 | 8 | Regarding versioning, if your tool supports different versions of Gura, we recommend making available in the official documentation (either a website or README) a table indicating which versions of the library support which version of Gura. For example: 9 | 10 | 11 | **Compatibility** 12 | 13 | | **Parser version** | **Gura version** | 14 | |--------------------|------------------| 15 | | 1.x | 1.0.0 | 16 | | 2.0.x | 2.0.0 | 17 | | 2.1.x | 2.0.1 | 18 | 19 | 20 | This can also be accompanied by references to [Git branches][git-branches], [Git tags][git-tags], [Github releases][github-releases], or any other way to differentiate versions of your project that can be explicitly linked to a Gura version. 21 | 22 | 23 | [git-branches]: https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell#ch03-git-branching 24 | [git-tags]: https://git-scm.com/book/en/v2/Git-Basics-Tagging 25 | [github-releases]: https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gura-site", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids" 15 | }, 16 | "dependencies": { 17 | "@docusaurus/core": "^2.2.0", 18 | "@docusaurus/preset-classic": "^2.2.0", 19 | "@mdx-js/react": "^1.6.21", 20 | "@svgr/webpack": "^5.5.0", 21 | "docusaurus-plugin-sass": "^0.1.14", 22 | "file-loader": "^6.2.0", 23 | "prism-react-renderer": "^1.2.0", 24 | "react": "^17.0.1", 25 | "react-dom": "^17.0.1", 26 | "sass": "^1.32.12", 27 | "url-loader": "^4.1.1" 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.5%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | }, 41 | "devDependencies": { 42 | "@docusaurus/module-type-aliases": "^2.2.0", 43 | "@tsconfig/docusaurus": "^1.0.2", 44 | "@types/react": "^17.0.5", 45 | "@types/react-helmet": "^6.1.1", 46 | "@types/react-router-dom": "^5.1.7", 47 | "typescript": "^4.2.4" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/prism_themes/github/index.js: -------------------------------------------------------------------------------- 1 | var theme = { 2 | plain: { 3 | color: "#393A34", 4 | backgroundColor: "#f6f8fa" 5 | }, 6 | styles: [ 7 | { 8 | types: ["comment", "prolog", "doctype", "cdata"], 9 | style: { 10 | color: "#999988", 11 | fontStyle: "italic" 12 | } 13 | }, 14 | { 15 | types: ["namespace"], 16 | style: { 17 | opacity: 0.7 18 | } 19 | }, 20 | { 21 | types: ["string", "attr-value"], 22 | style: { 23 | color: "#e3116c" 24 | } 25 | }, 26 | { 27 | types: ["punctuation", "operator"], 28 | style: { 29 | color: "#393A34" 30 | } 31 | }, 32 | { 33 | types: [ 34 | "entity", 35 | "url", 36 | "symbol", 37 | "number", 38 | "boolean", 39 | "variable", 40 | "constant", 41 | "property", 42 | "regex", 43 | "inserted" 44 | ], 45 | style: { 46 | color: "#36acaa" 47 | } 48 | }, 49 | { 50 | types: ["atrule", "keyword", "attr-name", "selector"], 51 | style: { 52 | color: "#00a4db" 53 | } 54 | }, 55 | { 56 | types: ["function", "deleted", "tag"], 57 | style: { 58 | color: "#d73a49" 59 | } 60 | }, 61 | { 62 | types: ["function-variable"], 63 | style: { 64 | color: "#6f42c1" 65 | } 66 | }, 67 | { 68 | types: ["tag", "selector", "keyword"], 69 | style: { 70 | color: "#00009f" 71 | } 72 | } 73 | ] 74 | }; 75 | module.exports = theme; 76 | -------------------------------------------------------------------------------- /src/theme/CodeSnippet/index.js: -------------------------------------------------------------------------------- 1 | import React, {useEffect, useState} from 'react'; 2 | import styles from './styles.module.css'; 3 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 4 | import { useColorMode } from '@docusaurus/theme-common'; 5 | import Highlight, { defaultProps } from "prism-react-renderer"; 6 | import monokai from "@site/src/prism_themes/monokai"; 7 | 8 | function CodeSnippet(props) { 9 | const { 10 | siteConfig: { 11 | themeConfig: {prism = {}}, 12 | }, 13 | } = useDocusaurusContext(); 14 | 15 | const [mounted, setMounted] = useState(false); 16 | // The Prism theme on SSR is always the default theme but the site theme 17 | // can be in a different mode. React hydration doesn't update DOM styles 18 | // that come from SSR. Hence force a re-render after mounting to apply the 19 | // current relevant styles. There will be a flash seen of the original 20 | // styles seen using this current approach but that's probably ok. Fixing 21 | // the flash will require changing the theming approach and is not worth it 22 | // at this point. 23 | useEffect(() => { 24 | setMounted(true); 25 | }, []); 26 | 27 | const isDarkTheme = useColorMode().colorMode === "dark"; 28 | const lightModeTheme = prism.theme || monokai; 29 | const darkModeTheme = prism.darkTheme || lightModeTheme; 30 | const prismTheme = isDarkTheme ? darkModeTheme : lightModeTheme; 31 | 32 | const { 33 | lang = 'yaml', 34 | snippet, 35 | } = props; 36 | 37 | return ( 38 | 39 | {({ className, style, tokens, getLineProps, getTokenProps }) => ( 40 |
41 |           {tokens.map((line, i) => (
42 |             
43 | {line.map((token, key) => ( 44 | 45 | ))} 46 |
47 | ))} 48 |
49 | )} 50 |
51 | ); 52 | } 53 | 54 | export default CodeSnippet; 55 | -------------------------------------------------------------------------------- /docusaurus.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@docusaurus/types').DocusaurusConfig} */ 2 | module.exports = { 3 | title: 'Gura', 4 | tagline: '', 5 | url: 'https://gura.netlify.app/', 6 | baseUrl: '/', 7 | onBrokenLinks: 'throw', 8 | onBrokenMarkdownLinks: 'warn', 9 | favicon: 'img/favicon.ico', 10 | organizationName: 'JWare', 11 | projectName: 'Gura', 12 | themeConfig: { 13 | navbar: { 14 | title: 'Gura', 15 | logo: { 16 | alt: 'Gura Logo', 17 | src: 'img/gura-thumbnail.png', 18 | }, 19 | items: [ 20 | { to: 'docs/gura', label: 'Docs', position: 'left' }, 21 | { to: 'resources', label: 'Resources', position: 'left' }, 22 | { 23 | type: 'docsVersionDropdown', 24 | position: 'right' 25 | }, 26 | { 27 | href: 'https://discord.gg/Qs5AXPQpKd', 28 | position: 'right', 29 | className: 'header-discord-link header-icon-link', 30 | title: 'Discord server', 31 | 'aria-label': 'Discord server', 32 | }, 33 | { 34 | href: 'https://github.com/gura-conf/gura', 35 | position: 'right', 36 | className: 'header-github-link header-icon-link', 37 | title: 'GitHub repository', 38 | 'aria-label': 'GitHub repository', 39 | }, 40 | ], 41 | }, 42 | footer: { 43 | style: 'dark', 44 | copyright: `Copyright © ${new Date().getFullYear()} JWare Solutions`, 45 | }, 46 | }, 47 | presets: [ 48 | [ 49 | '@docusaurus/preset-classic', 50 | { 51 | docs: { 52 | sidebarPath: require.resolve('./sidebars.js'), 53 | /** 54 | * Skip the next release docs when versioning is enabled. 55 | * This will not generate HTML files in the production build for documents 56 | * in `/docs/next` directory, only versioned docs. 57 | * TODO: set to false when finished version 2.0.0 58 | */ 59 | includeCurrentVersion: true 60 | }, 61 | theme: { 62 | customCss: [ 63 | require.resolve('./src/css/custom.scss'), 64 | ] 65 | }, 66 | }, 67 | ], 68 | ], 69 | plugins: ['docusaurus-plugin-sass'], 70 | }; 71 | -------------------------------------------------------------------------------- /src/components/ResourcesUsage/ResourcesUsage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styles from '../HomepageFeatures.module.css'; 3 | import stylesResourcesUsage from './ResourcesUsage.module.css' 4 | 5 | 6 | /** Gura feature structure */ 7 | interface UsageExample { 8 | title: string, 9 | img: string, 10 | description: JSX.Element 11 | } 12 | 13 | const usageExamplesList: UsageExample[] = [ 14 | { 15 | title: 'IDE extension', 16 | img: require('../../../static/img/logos-usage/IDE-extension.png').default, 17 | description: ( 18 | <> 19 | Use the Gura thumbnail to style your extensions! 20 | 21 | ) 22 | }, 23 | { 24 | title: 'Development', 25 | img: require('../../../static/img/logos-usage/development.png').default, 26 | description: ( 27 | <> 28 | You can use the official logo for the design of your tools and websites! 29 | 30 | ) 31 | }, 32 | { 33 | title: 'Anywhere!', 34 | img: require('../../../static/img/logos-usage/blog.png').default, 35 | description: ( 36 | <> 37 | Whether it's your blog, your library, or any project you have in mind, you have Gura's resources at hand! 38 | 39 | ) 40 | } 41 | ]; 42 | 43 | 44 | const ResourcesUsage = () => { 45 | return ( 46 |
47 |
48 |
49 | {usageExamplesList.map((example) => ( 50 |
51 |
52 | {example.title} 53 |
54 |
55 |

{example.title}

56 |

{example.description}

57 |
58 |
59 | ))} 60 |
61 |
62 |
63 | ) 64 | } 65 | 66 | export { ResourcesUsage } -------------------------------------------------------------------------------- /src/components/HomepageFeatures.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './HomepageFeatures.module.css'; 3 | 4 | /** Gura feature structure */ 5 | interface Feature { 6 | img: string, 7 | title: string, 8 | description: JSX.Element 9 | } 10 | 11 | const featureList: Feature[] = [ 12 | { 13 | title: 'Simple', 14 | img: require('../../static/img/features/simple.png').default, 15 | description: ( 16 | <> 17 | Gura is simple, and its "one way of doing things" philosophy minimizes the possibility of error and its implementation complexity. 18 | 19 | ), 20 | }, 21 | { 22 | title: 'Robust', 23 | img: require('../../static/img/features/robustness.png').default, 24 | description: ( 25 | <> 26 | Gura has no implicit mechanisms that lead to bugs, it is strongly typed and bugs are standardized to make it a robust configuration language. 27 | 28 | ), 29 | }, 30 | { 31 | title: 'Friendly', 32 | img: require('../../static/img/features/friendly.png').default, 33 | description: ( 34 | <> 35 | Gura retains the best aspects of well-known languages such as TOML and YAML to make user adoption a smooth and agile process. 36 | 37 | ), 38 | }, 39 | ]; 40 | 41 | /** Renders a Gura's feature section */ 42 | const Feature = (props: Feature) => { 43 | return ( 44 |
45 |
46 | {props.title} 47 |
48 |
49 |

{props.title}

50 |

{props.description}

51 |
52 |
53 | ); 54 | } 55 | 56 | /** 57 | * Renders list of Gura's features 58 | * @returns Component 59 | */ 60 | export default function HomepageFeatures() { 61 | return ( 62 |
63 |
64 |
65 | {featureList.map((feature) => ( 66 | 67 | ))} 68 |
69 |
70 |
71 | ); 72 | } 73 | -------------------------------------------------------------------------------- /docs/changelog.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Changelog 6 | 7 | On this page are listed all the changes introduced in Gura specs (version 2.0.0). 8 | 9 | 10 | ## From 1.0.0 ➞ 2.0.0 11 | 12 | 13 | ### Literal Keys 14 | 15 | Literal Keys were introduced in [Keys section][keys-section] to provide portability with other configuration languages ([related Github discussion][discussion-literal-keys]). 16 | 17 | 18 | ### Variables support all basic types 19 | 20 | [Booleans][boolean-section], `empty` and [null][null-section] values can now also be assigned as the value of a [variable][variables-section]. This change was introduced because it adds value to the language without sacrificing simplicity. 21 | 22 | 23 | ### Added a mechanism to make imports optional 24 | 25 | Now Gura specs state that implementations must provide a way to disable imports. This change avoids errors or security problems on environments without filesystem access or that are sensitive. It has been proposed that such variables be disabled by default in the [Developers documentation][developers-tool-parameters]. Check the [Imports section][import-section] to learn more. 26 | 27 | 28 | ### Added a mechanism to make ENV vars optional 29 | 30 | For security reasons, it is possible to disable environment variables in Gura files in this new version. It has been proposed that such variables be disabled by default in the [Developers documentation][developers-tool-parameters]. Check the [Variables section][variables-section] to learn more. 31 | 32 | 33 | ### Changed behavior with invalid escaped sentences 34 | 35 | Added `InvalidEscapedCharacterError` error in [String section][string-section] when used invalid escape sentences ([related Github discussion][discussion-escape-chars]). 36 | 37 | 38 | ### New *Developer* section 39 | 40 | Added a new [Developers section][developers-section] listing some useful conventions, standards, tools and recommendations for developers working on a new parser, emitter or tokenizer for Gura. 41 | 42 | 43 | [keys-section]: spec#keys 44 | [boolean-section]: spec#boolean 45 | [null-section]: spec#null 46 | [discussion-literal-keys]: https://github.com/gura-conf/gura/discussions/10 47 | [import-section]: spec#imports 48 | [variables-section]: spec#variables 49 | [string-section]: spec#string 50 | [discussion-escape-chars]: https://github.com/gura-conf/gura/discussions/11 51 | [developers-section]: Developers/introduction 52 | [developers-tool-parameters]: Developers/parsing#tool-parameters 53 | -------------------------------------------------------------------------------- /src/components/ResourceList/ResourceList.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import stylesIndex from "../../pages/index.module.css"; 3 | import stylesResource from "./ResourceList.module.css"; 4 | 5 | 6 | /** Link to download a resource */ 7 | type ResourceLink = { 8 | description: string, 9 | link: string 10 | } 11 | 12 | /** Resource */ 13 | interface Resource { 14 | img: string, 15 | title: string, 16 | links: ResourceLink[] 17 | } 18 | 19 | const resourceList: Resource[] = [ 20 | { 21 | title: 'Official logo', 22 | img: require('../../../static/img/logos/gura-200.png').default, 23 | links: [ 24 | { description: '200 x 200', link: '/static/img/logos/gura-200.png' }, 25 | { description: '500 x 500', link: '/static/img/logos/gura-500.png' } 26 | ] 27 | }, 28 | { 29 | title: 'Official thumbnail', 30 | img: require('../../../static/img/logos/gura-thumbnail.png').default, 31 | links: [ 32 | { description: '500 x 500', link: '/static/img/logos/gura-thumbnail.png' }, 33 | ] 34 | }, 35 | ]; 36 | 37 | /** Renders a resource section with download buttons */ 38 | function Resource(props: Resource) { 39 | const lastLinkIdx = props.links.length - 1 40 | return ( 41 |
42 | {props.title} 43 |
44 | {props.links.map((resourceLink, idx) => { 45 | const marginClass = idx < lastLinkIdx ? 'margin-bottom--md' : '' 46 | return ( 47 |
48 |
49 |
50 | 57 | {resourceLink.description} 58 | 59 |
60 |
61 |
62 | ) 63 | })} 64 |
65 |
66 | ); 67 | } 68 | 69 | /** 70 | * Renders list of resources 71 | * @returns Component 72 | */ 73 | const ResourceList = () => ( 74 |
75 |
76 |
77 | {resourceList.map((feature) => ( 78 | 79 | ))} 80 |
81 |
82 |
83 | ) 84 | 85 | export { ResourceList } 86 | -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Head from '@docusaurus/Head'; 3 | import Layout from '@theme/Layout'; 4 | import Link from '@docusaurus/Link'; 5 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 6 | import styles from './index.module.css'; 7 | import HomepageFeatures from '../components/HomepageFeatures'; 8 | import { FeaturesReview} from '../components/FeaturesReview/FeaturesReview' 9 | import { DifferencesSection } from '../components/Differences/Differences'; 10 | import CodeSnippet from '../theme/CodeSnippet'; 11 | 12 | 13 | const HeaderWithCodeSnippet = () => { 14 | const { siteConfig } = useDocusaurusContext(); 15 | 16 | const snippetContent = `# This is a comment in a Gura configuration file. 17 | # Define a variable named \`title\` with string value "Gura Example" 18 | title: "Gura Example" 19 | 20 | # Define an object with fields \`username\` and \`age\` 21 | # with string and integer values, respectively 22 | # Indentation is used to indicate nesting 23 | person: 24 | username: "Stephen" 25 | age: 20 26 | 27 | # Define a list of values 28 | # Line breaks are OK when inside arrays 29 | hosts: [ 30 | "alpha", 31 | "omega" 32 | ] 33 | 34 | # Variables can be defined and referenced to avoid repetition 35 | $foreground: "#FFAH84" 36 | color_scheme: 37 | editor: $foreground 38 | ui: $foreground` 39 | 40 | return ( 41 |
42 |
43 |
44 |
45 |

{siteConfig.title}

46 |

47 | Gura is a file format for configuration files. Gura is as readable as YAML and simple as TOML. Its syntax is clear and powerful, yet familiar for YAML/TOML users. 48 |

49 |
50 |
51 |
52 | 55 | Get started 56 | 57 |
58 |
59 |
60 |
61 | 64 | Find a library 65 | 66 |
67 |
68 |
69 |
70 |
71 | 72 |
73 |
74 |
75 |
76 | ) 77 | } 78 | 79 | export default function Home() { 80 | const title = 'Gura | Configuration language' 81 | return ( 82 | 85 | 86 | 87 | {title} 88 | 92 | 96 | 97 | 98 | 99 | 100 |
101 | 102 | 103 | 104 | 105 | 106 |
107 |
108 | ); 109 | } 110 | -------------------------------------------------------------------------------- /src/components/FeaturesReview/FeaturesReview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Tabs from '@theme/Tabs'; 3 | import TabItem from '@theme/TabItem'; 4 | import CodeSnippet from "../../theme/CodeSnippet"; 5 | import styles from '../../pages/index.module.css'; 6 | import Link from '@docusaurus/Link'; 7 | 8 | /** Code Snippet to show some Gura features */ 9 | interface Snippet { 10 | /** Label to show in pills/tabs */ 11 | label: string, 12 | /** Link to the spec section where the concept is further explained */ 13 | further: string, 14 | /** Snippet content */ 15 | content: string 16 | } 17 | 18 | const snippets: Snippet[] = [ 19 | { 20 | label: 'Strings', 21 | further: '/docs/spec#string', 22 | content: `basic: "I'm a string. \"You can quote me\". Name\\tJos\\u00E9\\nLocation\\tSF." 23 | 24 | multiline_basic: """ 25 | The quick brown \\ 26 | fox jumps over \\ 27 | the lazy dog. 28 | """ 29 | 30 | literal: 'C:\\Users\\nodejs\\templates' 31 | 32 | multiline_literal: ''' 33 | The first newline is 34 | trimmed in raw strings. 35 | All other whitespace 36 | is preserved. 37 | '''` 38 | }, 39 | { 40 | label: 'Numbers', 41 | further: '/docs/spec#integer', 42 | content: `# Integers 43 | int1: +99 44 | int2: 1_000 # Separator! 45 | 46 | # Different formats 47 | hex: 0xDEADBEEF # Hexadecimal 48 | oct: 0o01234567 # Octal 49 | bin: 0b11010110 # Binary 50 | 51 | # Floats 52 | flt1: +1.0 53 | flt2: 3.1415 54 | 55 | # Infinity 56 | sf1: inf # Positive infinity 57 | sf2: +inf # Positive infinity 58 | sf3: -inf # Negative infinity 59 | 60 | # Not a number 61 | sf4: nan # Actual sNaN/qNaN encoding is implementation-specific 62 | sf5: +nan # Same as \`nan\` 63 | sf6: -nan # Valid, actual encoding is implementation-specific`, 64 | }, 65 | { 66 | label: 'Objects', 67 | further: '/docs/spec#object', 68 | content: `services: 69 | nginx: 70 | host: "127.0.0.1" 71 | port: 80 72 | 73 | apache: 74 | virtual_host: "10.10.10.4" 75 | port: 81` 76 | }, 77 | { 78 | label: 'Arrays', 79 | further: '/docs/spec#array', 80 | content: `numbers: [ 0.1, 0.2, 0.5, 1, 2, 5 ] 81 | 82 | # Nested and mixed 83 | numbers_and_strings: [ [ 1, 2 ], ["a", "b", "c"] ] 84 | 85 | # Array of objects 86 | tango_singers: [ 87 | user1: 88 | name: "Carlos" 89 | surname: "Gardel" 90 | year_of_birth: 1890, 91 | 92 | user2: 93 | name: "Aníbal" 94 | surname: "Troilo" 95 | year_of_birth: 1914 96 | ]` 97 | }, 98 | { 99 | label: 'Booleans', 100 | further: '/docs/spec#boolean', 101 | content: `# Just simple bool values. No magic, only one way 102 | is_true: true 103 | is_false: false` 104 | }, 105 | { 106 | label: 'Variables', 107 | further: '/docs/spec#variables', 108 | content: `$my_host: "127.0.0.1" 109 | nginx: 110 | host: $my_host 111 | port: 8080` 112 | }, 113 | ]; 114 | 115 | 116 | const FeaturesReview = () => { 117 | return ( 118 |
119 |
120 |
121 |
122 | {snippets && snippets.length && ( 123 |
124 | ( 125 | { label: snippet.label, value: snippet.label } 126 | ))}> 127 | {snippets.map((props, idx) => ( 128 | 129 | 130 | 132 | Read more about {props.label.toLowerCase()} 133 | 134 | 135 | ))} 136 | 137 |
138 | )} 139 |
140 | 141 |
142 |

Gura is simple and elegant

143 |

144 | Gura was born from the need to have a configuration language that is human readable without falling into the unnecessary complexity of popular formats such as YAML. 145 |

146 | 148 | Read more in the full specs! 149 | 150 |
151 |
152 |
153 |
154 | ) 155 | } 156 | 157 | export { FeaturesReview } -------------------------------------------------------------------------------- /static/img/old/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Differences/Differences.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import useBaseUrl from '@docusaurus/useBaseUrl'; 3 | import styles from '../../pages/index.module.css'; 4 | 5 | 6 | /** Config language difference section */ 7 | interface DifferenceElem { 8 | /** Title of the section */ 9 | title: string, 10 | /** Image of the language with which the comparison is being made */ 11 | imageUrl: string, 12 | /** HTML/string content of the section */ 13 | description: JSX.Element 14 | } 15 | 16 | const differences: DifferenceElem[] = [ 17 | { 18 | title: 'Differences with YAML', 19 | imageUrl: 'img/differences/yaml.png', 20 | description: ( 21 | <> 22 |

23 | YAML offered a readable alternative to JSON or INI for a configuration file. While TOML was great for basic files because of its simplicity, YAML provided a readable solution when the complexity of the file grew. However, as the NOYAML manifesto argues, we should stop supporting that format. The reason? YAML is unnecessarily complex. We highlight main issues with YAML that Gura tries to solve. 24 | 25 |

34 |

35 | 36 | ), 37 | }, 38 | { 39 | title: 'Differences with JSON', 40 | imageUrl: 'img/differences/json.png', 41 | description: ( 42 | <> 43 |

44 | It's easy, JSON is and will be the fastest serialization language available. Gura is not meant for fast processing and/or machine-to-machine communication. When a readable, simple, and maintainable language is needed Gura becomes an excellent alternative. 45 |

46 | 47 | ), 48 | }, 49 | { 50 | title: 'Differences with TOML', 51 | imageUrl: 'img/differences/toml.png', 52 | description: ( 53 | <> 54 |

55 | The idea of Gura is not to replace TOML but to complement it when the complexity of the project warrants it. The use of TOML for files such as cargo.toml in the Rust programming language is an excellent example of matching the complexity of the language to that of the domain. However, when the level of nesting increases, TOML is very cumbersome since you must resort to repeating all the parent levels (using Dotted keys) every time you want to define a nested value. 56 | 57 | Furthermore, even TOML falls in some cases into the same complexity as YAML, with features such as: 58 | 59 |

64 |

65 | 66 | ), 67 | }, 68 | { 69 | title: 'Gura ⭐', 70 | imageUrl: 'img/differences/gura.png', 71 | description: ( 72 | <> 73 |

74 | Gura combines the readability of YAML and a reduced version of its syntax with the (even more simplified) simplicity of TOML. It also brings in some features and characteristics exclusive to this language: 75 | 76 |

87 |

88 | 89 | ), 90 | }, 91 | ]; 92 | 93 | interface LanguageComparisonProps { 94 | difference: DifferenceElem 95 | } 96 | 97 | 98 | /** Renders a language comparison section */ 99 | function LanguageComparison(props: LanguageComparisonProps) { 100 | const { imageUrl, title, description } = props.difference 101 | const imgUrl = useBaseUrl(imageUrl); 102 | return ( 103 |
104 | {imgUrl && ( 105 |
106 | {title} 107 |
108 | )} 109 |

{title}

110 |

{description}

111 |
112 | ); 113 | } 114 | 115 | 116 | /** A comparison section with other config languages */ 117 | export const DifferencesSection = () => ( 118 |
119 |
120 |
121 | {differences.map((difference, idx) => ( 122 | 123 | ))} 124 |
125 |
126 |
127 | ) 128 | -------------------------------------------------------------------------------- /docs/Developers/parsing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Serialization/Deserialization 3 | sidebar_position: 2 4 | description: 'Serialization and deserialization process specifications for Gura parsers development' 5 | keywords: ['Serialization', 'Deserialization', 'Parsers'] 6 | --- 7 | 8 | # Serialization/Deserialization 9 | 10 | This page defines the basic concepts for the implementation of a parser that serializes/deserializes text in Gura format. In honor of the simplicity of the language, we will try to make this documentation as easy as possible. 11 | 12 | 13 | ## Basic types 14 | 15 | All implementations that parse or output text in Gura format must contemplate the following data types to comply with the language specifications: 16 | 17 | - **Null**: defines a unit value. Different programming languages have different ways of representing this value, for example, in Java, Javascript or PHP it is defined with the type null, in Python it is None, in Ruby it is nil, Option in Rust, and so on. Use the corresponding value depending on which language you are implementing your parser in. [Reference][null-reference]. 18 | - **Bool**: sets the boolean values that in Gura are defined through the keywords `false` and `true`. [Reference][bool-reference]. 19 | - **String**: defines text strings. Regardless of whether they are basic, literal, and/or multiline strings. [Reference][string-reference]. 20 | - **Integer**: defines signed integers. [Reference][integer-reference]. 21 | - **Float**: defines signed floating-point number. [Reference][float-reference]. 22 | - **Array**: defines an ordered collection of Gura elements. [Reference][array-reference]. 23 | - **Object**: defines an ordered structure containing keys that uniquely reference a Gura element. Examples of this type of structure in programming languages are objects in Javascript, a dictionary in Python, a HashMap in Java or Rust, a map in C++, etc. Where the key is a String, and the value is a Gura element that is part of this basic data list. [Reference][object-reference]. 24 | 25 | It is vitally important to understand that the implementation of a parser is a complex task and **will probably involve the use of more complex data structures than the one just mentioned**. 26 | 27 | These structures should be considered internal and act as utilities to perform certain tasks. For example, the official parsers of Python, Javascript, and Rust (which can be found in the [list of implementations][implementations]) have internal structures to map the indentation, import, variables, among other structures that are only of interest to developers but are not part of the specifications that apply to the end-user. These structures can be freely defined by the tool manager(s) and are not subject to any standard by the Gura team. 28 | 29 | 30 | ## Standard errors 31 | 32 | All implementations must consider the following errors (all of them are duly entered in the corresponding sections on the [Specs page][specs-page]) during the parsing of Gura text to a representation in the programming language used, to comply with the language specifications: 33 | 34 | - **ParseError**: Gura syntax is invalid. 35 | - **VariableNotDefinedError**: a variable is not defined, or ENV vars are disabled (see [Tool parameters section](#tool-parameters)) and a local variable is not found (maybe it is an ENV var, but no check should be made). 36 | - **InvalidIndentationError**: indentation is invalid. 37 | - **DuplicatedVariableError**: a variable is defined more than once. 38 | - **DuplicatedKeyError**: a key is defined more than once. 39 | - **InvalidEscapedCharacterError**: an escape sequences not listed in [String section][string-reference] is used. 40 | - **FileNotFoundError**: an imported file does not exist. 41 | - **DuplicatedImportError**: a file is imported more than once. 42 | - **ImportDisabledError**: an `import` sentence is found in Gura file with the import setting disabled (see [Tool parameters section](#tool-parameters)). 43 | 44 | For all cases, **it is recommended that the developing tool provides the line** (*1-Based* indexing, like most IDEs or compilers) **and the global position of the text** (*0-Based* indexing, like most IDEs or compilers) where the error occurred. A series of tests (an explanation of this repository is provided below) are provided [here][error-reporting-tests] to check the correct error reporting. 45 | 46 | As mentioned above in the *Basic types* section, it could be possible that some internal errors may be used during parsing. However, it is reminded that such errors are not part of the formal language specifications and should not be accessible by end-users through the tool API. 47 | 48 | 49 | ## Tool parameters 50 | 51 | The parameters to be used during serialization or deserialization functions are up to the developer. However, **two parameters are mandatory for all implementations seeking to comply with Gura version 2**: 52 | 53 | - **Disable imports during serialization**: a mechanism must be provided to disable `import` statements in Gura documents (check the [Imports section][import-reference] to learn more). In case this mechanism is disabled, and the document contains an `import` sentence, an `ImportDisabledError` error must be thrown. **This option should be disabled by default**. 54 | - **Disable environment variables serialization**: a mechanism must be provided to disable the use of environment variables (check the [Variables section][variables-reference] to learn more) and only consider variables local to the Gura document (including, if any, imported documents). In case this mechanism is disabled, and a local variable is not found a `VariableNotDefinedError` error must be thrown. **This option should be disabled by default**. 55 | 56 | Both options ensure security in sensitive environments by preventing access to important system information. 57 | 58 | 59 | ## Testing 60 | 61 | A repository containing several tests for validating files with valid Gura format, and all the errors listed above, is made available to developers [here][testing-repository]. 62 | 63 | We encourage all developers to use the tests provided to corroborate the correct functioning of their tools. And to add some tests they consider important during their development (they could be useful for other Gura projects). 64 | 65 | 66 | [specs-page]: /docs/spec 67 | [null-reference]: /docs/spec#null 68 | [bool-reference]: /docs/spec#boolean 69 | [string-reference]: /docs/spec#string 70 | [integer-reference]: /docs/spec#integer 71 | [float-reference]: /docs/spec#float 72 | [array-reference]: /docs/spec#array 73 | [object-reference]: /docs/spec#object 74 | [implementations]: https://github.com/gura-conf/gura#library-implementations 75 | [error-reporting-tests]: https://github.com/gura-conf/testing/tree/main/error_reporting 76 | [testing-repository]: https://github.com/gura-conf/testing 77 | [import-reference]: /docs/spec#imports 78 | [variables-reference]: /docs/spec#variables 79 | -------------------------------------------------------------------------------- /versioned_docs/version-1.0.0/abnf.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | --- 4 | 5 | # ABNF grammar 6 | 7 | This document describes Gura's syntax, using the ABNF format (defined in RFC 5234 -- https://www.ietf.org/rfc/rfc5234.txt). 8 | 9 | All valid Gura documents will match this description, however certain invalid documents would need to be rejected as per the semantics described in the supporting text description. 10 | 11 | It is possible to try this grammar interactively, using [instaparse](http://instaparse.mojombo.com/). To do so, in the lower right, click on Options and change `:input-format` to `:abnf`. Then paste this entire ABNF document into the grammar entry box (above the options). Then you can type or paste a sample Gura document into the beige box on the left. 12 | 13 | ```abnf 14 | ;; Overall Structure 15 | gura = expression *( newline expression ) 16 | 17 | expression = ws [ comment ] 18 | expression =/ ws variable-definition ws [ comment ] 19 | expression =/ import ws [ comment ] 20 | expression =/ object 21 | 22 | ;; Variables 23 | dollar-sign = %x24 ; $ 24 | var-val = string / float / integer / other-variable 25 | keyval-var = unquoted-key keyval-sep var-val 26 | variable-definition = dollar-sign keyval-var ws [ comment ] 27 | other-variable = ws dollar-sign unquoted-key ws [ comment] 28 | 29 | ;; Imports 30 | import-keyword = %x69 %x6D %x70 %x6F %x72 %x74 ; "import" 31 | import = import-keyword wschar basic-string 32 | 33 | ;; Objects 34 | object = ws unquoted-key keyval-sep ws [comment] newline object 35 | object =/ keyval-with-spaces *( newline object ) 36 | 37 | 38 | ;; Whitespace 39 | ws = *wschar 40 | wschar = %x20 ; Space 41 | wschar =/ %x09 ; Horizontal tab 42 | 43 | 44 | ;; Newline 45 | newline = %x0A ; LF 46 | newline =/ %x0D.0A ; CRLF 47 | 48 | 49 | ;; Comment 50 | comment-start-symbol = %x23 ; # 51 | non-ascii = %x80-D7FF / %xE000-10FFFF 52 | non-eol = %x09 / %x20-7F / non-ascii 53 | comment = comment-start-symbol *non-eol 54 | 55 | 56 | ;; Key-Value pairs 57 | keyval-with-spaces = ws keyval ws [ comment ] 58 | keyval = unquoted-key keyval-sep val 59 | unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _ 60 | keyval-sep = ws %x3A ws ; ':' Colon 61 | 62 | 63 | ;; Values 64 | val = null / string / boolean / array / float / integer / other-variable / empty 65 | 66 | 67 | ;; Null 68 | null = %x6E.75.6C.6C ; null 69 | 70 | 71 | ;; Empty 72 | empty = %x65.6D.70.74.79 ; empty 73 | 74 | 75 | ;; String 76 | string = ml-basic-string / basic-string / ml-literal-string / literal-string 77 | 78 | 79 | ;; Basic String 80 | basic-string = quotation-mark *basic-char quotation-mark 81 | 82 | quotation-mark = %x22 ; " 83 | 84 | basic-char = basic-unescaped / escaped 85 | basic-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii 86 | escaped = escape escape-seq-char 87 | 88 | escape = %x5C ; \ 89 | escape-seq-char = %x22 ; " quotation mark U+0022 90 | escape-seq-char =/ %x5C ; \ reverse solidus U+005C 91 | escape-seq-char =/ %x62 ; b backspace U+0008 92 | escape-seq-char =/ %x66 ; f form feed U+000C 93 | escape-seq-char =/ %x6E ; n line feed U+000A 94 | escape-seq-char =/ %x72 ; r carriage return U+000D 95 | escape-seq-char =/ %x74 ; t tab U+0009 96 | escape-seq-char =/ %x75 4HEXDIG ; uXXXX U+XXXX 97 | escape-seq-char =/ %x55 8HEXDIG ; UXXXXXXXX U+XXXXXXXX 98 | 99 | 100 | ;; Multiline Basic String 101 | ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body 102 | ml-basic-string-delim 103 | ml-basic-string-delim = 3quotation-mark 104 | ml-basic-body = *mlb-content *( mlb-quotes 1*mlb-content ) [ mlb-quotes ] 105 | 106 | mlb-content = mlb-char / newline / mlb-escaped-nl 107 | mlb-char = mlb-unescaped / escaped 108 | mlb-quotes = 1*2quotation-mark 109 | mlb-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii 110 | mlb-escaped-nl = escape ws newline *( wschar / newline ) 111 | 112 | 113 | ;; Literal String 114 | literal-string = apostrophe *literal-char apostrophe 115 | apostrophe = %x27 ; ' apostrophe 116 | literal-char = %x09 / %x20-26 / %x28-7E / non-ascii 117 | 118 | 119 | ;; Multiline Literal String 120 | ml-literal-string = ml-literal-string-delim [ newline ] ml-literal-body 121 | ml-literal-string-delim 122 | ml-literal-string-delim = 3apostrophe 123 | ml-literal-body = *mll-content *( mll-quotes 1*mll-content ) [ mll-quotes ] 124 | 125 | mll-content = mll-char / newline 126 | mll-char = %x09 / %x20-26 / %x28-7E / non-ascii 127 | mll-quotes = 1*2apostrophe 128 | 129 | 130 | ;; Integer 131 | integer = dec-int / hex-int / oct-int / bin-int 132 | 133 | minus = %x2D ; - 134 | plus = %x2B ; + 135 | underscore = %x5F ; _ 136 | digit1-9 = %x31-39 ; 1-9 137 | digit0-7 = %x30-37 ; 0-7 138 | digit0-1 = %x30-31 ; 0-1 139 | 140 | hex-prefix = %x30.78 ; 0x 141 | oct-prefix = %x30.6F ; 0o 142 | bin-prefix = %x30.62 ; 0b 143 | 144 | dec-int = [ minus / plus ] unsigned-dec-int 145 | unsigned-dec-int = DIGIT / digit1-9 1*( DIGIT / underscore DIGIT ) 146 | 147 | hex-int = hex-prefix HEXDIG *( HEXDIG / underscore HEXDIG ) 148 | oct-int = oct-prefix digit0-7 *( digit0-7 / underscore digit0-7 ) 149 | bin-int = bin-prefix digit0-1 *( digit0-1 / underscore digit0-1 ) 150 | 151 | 152 | ;; Float 153 | float = float-int-part ( exp / frac [ exp ] ) 154 | float =/ special-float 155 | 156 | float-int-part = dec-int 157 | frac = decimal-point zero-prefixable-int 158 | decimal-point = %x2E ; . 159 | zero-prefixable-int = DIGIT *( DIGIT / underscore DIGIT ) 160 | 161 | exp = "e" float-exp-part 162 | float-exp-part = [ minus / plus ] zero-prefixable-int 163 | 164 | special-float = [ minus / plus ] ( inf / nan ) 165 | inf = %x69.6E.66 ; inf 166 | nan = %x6E.61.6E ; nan 167 | 168 | 169 | ;; Boolean 170 | boolean = true / false 171 | 172 | true = %x74.72.75.65 ; true 173 | false = %x66.61.6C.73.65 ; false 174 | 175 | 176 | ;; Array 177 | array = array-open [ array-values ] ws-comment-newline array-close 178 | 179 | array-open = %x5B ; [ 180 | array-close = %x5D ; ] 181 | 182 | array-values = ws-comment-newline val-object ws-comment-newline array-sep array-values 183 | array-values =/ ws-comment-newline val-object ws-comment-newline [ array-sep ] 184 | 185 | val-object = ( val / object ) 186 | 187 | array-sep = %x2C ; , Comma 188 | 189 | ws-comment-newline = *( wschar / [ comment ] newline ) 190 | 191 | 192 | ;; Built-in ABNF terms, reproduced here for clarity 193 | ALPHA = %x41-5A / %x61-7A ; A-Z / a-z 194 | DIGIT = %x30-39 ; 0-9 195 | HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" 196 | ``` -------------------------------------------------------------------------------- /docs/Developers/abnf.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | description: 'Gura ABNF grammar' 4 | --- 5 | 6 | # ABNF grammar 7 | 8 | This document describes Gura's syntax, using the ABNF format (defined in [RFC 5234][rfc-523]). 9 | 10 | All valid Gura documents will match this description, however certain invalid documents would need to be rejected as per the semantics described in the supporting text description. 11 | 12 | It is possible to try this grammar interactively, using [instaparse](http://instaparse.mojombo.com/). To do so, in the lower right, click on Options and change `:input-format` to `:abnf`. Then paste this entire ABNF document into the grammar entry box (above the options). Then you can type or paste a sample Gura document into the beige box on the left. 13 | 14 | ```abnf 15 | ;; Overall Structure 16 | gura = expression *( newline expression ) 17 | 18 | expression = ws [ comment ] 19 | expression =/ ws variable-definition ws [ comment ] 20 | expression =/ import ws [ comment ] 21 | expression =/ object 22 | 23 | ;; Variables 24 | dollar-sign = %x24 ; $ 25 | var-val = string / float / integer / other-variable 26 | keyval-var = unquoted-key keyval-sep var-val 27 | variable-definition = dollar-sign keyval-var ws [ comment ] 28 | other-variable = ws dollar-sign unquoted-key ws [ comment] 29 | 30 | ;; Imports 31 | import-keyword = %x69 %x6D %x70 %x6F %x72 %x74 ; "import" 32 | import = import-keyword wschar basic-string 33 | 34 | ;; Objects 35 | object = ws unquoted-key keyval-sep ws [comment] newline object 36 | object =/ keyval-with-spaces *( newline object ) 37 | 38 | 39 | ;; Whitespace 40 | ws = *wschar 41 | wschar = %x20 ; Space 42 | wschar =/ %x09 ; Horizontal tab 43 | 44 | 45 | ;; Newline 46 | newline = %x0A ; LF 47 | newline =/ %x0D.0A ; CRLF 48 | 49 | 50 | ;; Comment 51 | comment-start-symbol = %x23 ; # 52 | non-ascii = %x80-D7FF / %xE000-10FFFF 53 | non-eol = %x09 / %x20-7F / non-ascii 54 | comment = comment-start-symbol *non-eol 55 | 56 | 57 | ;; Key-Value pairs 58 | keyval-with-spaces = ws keyval ws [ comment ] 59 | keyval = unquoted-key keyval-sep val 60 | unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _ 61 | keyval-sep = ws %x3A ws ; ':' Colon 62 | 63 | 64 | ;; Values 65 | val = null / string / boolean / array / float / integer / other-variable / empty 66 | 67 | 68 | ;; Null 69 | null = %x6E.75.6C.6C ; null 70 | 71 | 72 | ;; Empty 73 | empty = %x65.6D.70.74.79 ; empty 74 | 75 | 76 | ;; String 77 | string = ml-basic-string / basic-string / ml-literal-string / literal-string 78 | 79 | 80 | ;; Basic String 81 | basic-string = quotation-mark *basic-char quotation-mark 82 | 83 | quotation-mark = %x22 ; " 84 | 85 | basic-char = basic-unescaped / escaped 86 | basic-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii 87 | escaped = escape escape-seq-char 88 | 89 | escape = %x5C ; \ 90 | escape-seq-char = %x22 ; " quotation mark U+0022 91 | escape-seq-char =/ %x5C ; \ reverse solidus U+005C 92 | escape-seq-char =/ %x62 ; b backspace U+0008 93 | escape-seq-char =/ %x66 ; f form feed U+000C 94 | escape-seq-char =/ %x6E ; n line feed U+000A 95 | escape-seq-char =/ %x72 ; r carriage return U+000D 96 | escape-seq-char =/ %x74 ; t tab U+0009 97 | escape-seq-char =/ %x75 4HEXDIG ; uXXXX U+XXXX 98 | escape-seq-char =/ %x55 8HEXDIG ; UXXXXXXXX U+XXXXXXXX 99 | 100 | 101 | ;; Multiline Basic String 102 | ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body 103 | ml-basic-string-delim 104 | ml-basic-string-delim = 3quotation-mark 105 | ml-basic-body = *mlb-content *( mlb-quotes 1*mlb-content ) [ mlb-quotes ] 106 | 107 | mlb-content = mlb-char / newline / mlb-escaped-nl 108 | mlb-char = mlb-unescaped / escaped 109 | mlb-quotes = 1*2quotation-mark 110 | mlb-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii 111 | mlb-escaped-nl = escape ws newline *( wschar / newline ) 112 | 113 | 114 | ;; Literal String 115 | literal-string = apostrophe *literal-char apostrophe 116 | apostrophe = %x27 ; ' apostrophe 117 | literal-char = %x09 / %x20-26 / %x28-7E / non-ascii 118 | 119 | 120 | ;; Multiline Literal String 121 | ml-literal-string = ml-literal-string-delim [ newline ] ml-literal-body 122 | ml-literal-string-delim 123 | ml-literal-string-delim = 3apostrophe 124 | ml-literal-body = *mll-content *( mll-quotes 1*mll-content ) [ mll-quotes ] 125 | 126 | mll-content = mll-char / newline 127 | mll-char = %x09 / %x20-26 / %x28-7E / non-ascii 128 | mll-quotes = 1*2apostrophe 129 | 130 | 131 | ;; Integer 132 | integer = dec-int / hex-int / oct-int / bin-int 133 | 134 | minus = %x2D ; - 135 | plus = %x2B ; + 136 | underscore = %x5F ; _ 137 | digit1-9 = %x31-39 ; 1-9 138 | digit0-7 = %x30-37 ; 0-7 139 | digit0-1 = %x30-31 ; 0-1 140 | 141 | hex-prefix = %x30.78 ; 0x 142 | oct-prefix = %x30.6F ; 0o 143 | bin-prefix = %x30.62 ; 0b 144 | 145 | dec-int = [ minus / plus ] unsigned-dec-int 146 | unsigned-dec-int = DIGIT / digit1-9 1*( DIGIT / underscore DIGIT ) 147 | 148 | hex-int = hex-prefix HEXDIG *( HEXDIG / underscore HEXDIG ) 149 | oct-int = oct-prefix digit0-7 *( digit0-7 / underscore digit0-7 ) 150 | bin-int = bin-prefix digit0-1 *( digit0-1 / underscore digit0-1 ) 151 | 152 | 153 | ;; Float 154 | float = float-int-part ( exp / frac [ exp ] ) 155 | float =/ special-float 156 | 157 | float-int-part = dec-int 158 | frac = decimal-point zero-prefixable-int 159 | decimal-point = %x2E ; . 160 | zero-prefixable-int = DIGIT *( DIGIT / underscore DIGIT ) 161 | 162 | exp = "e" float-exp-part 163 | float-exp-part = [ minus / plus ] zero-prefixable-int 164 | 165 | special-float = [ minus / plus ] ( inf / nan ) 166 | inf = %x69.6E.66 ; inf 167 | nan = %x6E.61.6E ; nan 168 | 169 | 170 | ;; Boolean 171 | boolean = true / false 172 | 173 | true = %x74.72.75.65 ; true 174 | false = %x66.61.6C.73.65 ; false 175 | 176 | 177 | ;; Array 178 | array = array-open [ array-values ] ws-comment-newline array-close 179 | 180 | array-open = %x5B ; [ 181 | array-close = %x5D ; ] 182 | 183 | array-values = ws-comment-newline val-object ws-comment-newline array-sep array-values 184 | array-values =/ ws-comment-newline val-object ws-comment-newline [ array-sep ] 185 | 186 | val-object = ( val / object ) 187 | 188 | array-sep = %x2C ; , Comma 189 | 190 | ws-comment-newline = *( wschar / [ comment ] newline ) 191 | 192 | 193 | ;; Built-in ABNF terms, reproduced here for clarity 194 | ALPHA = %x41-5A / %x61-7A ; A-Z / a-z 195 | DIGIT = %x30-39 ; 0-9 196 | HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" 197 | ``` 198 | 199 | 200 | [rfc-523]: https://www.ietf.org/rfc/rfc5234.txt 201 | -------------------------------------------------------------------------------- /src/css/custom.scss: -------------------------------------------------------------------------------- 1 | /* stylelint-disable docusaurus/copyright-header */ 2 | /** 3 | * Any CSS included here will be global. The classic template 4 | * bundles Infima by default. Infima is a CSS framework designed to 5 | * work well for content-centric websites. 6 | */ 7 | 8 | /* You can override the default Infima variables here. */ 9 | :root { 10 | --ifm-color-primary: #ff914d; 11 | --ifm-color-primary-dark: #ff7c2c; 12 | --ifm-color-primary-darker: #ff721b; 13 | --ifm-color-primary-darkest: #e85900; 14 | --ifm-color-primary-light: #ffa66e; 15 | --ifm-color-primary-lighter: #ffb07f; 16 | --ifm-color-primary-lightest: #ffcfb1; 17 | --ifm-code-font-size: 95%; 18 | } 19 | 20 | .header-github-link { 21 | padding-right: 16px !important; 22 | padding-left: 16px !important; 23 | 24 | &:before { 25 | content: ''; 26 | width: 24px; 27 | height: 24px; 28 | display: flex; 29 | background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") 30 | no-repeat; 31 | } 32 | 33 | &:hover { 34 | opacity: 0.6; 35 | } 36 | } 37 | 38 | .header-discord-link { 39 | padding-right: 16px !important; 40 | padding-left: 16px !important; 41 | 42 | &:before { 43 | content: ''; 44 | width: 24px; 45 | height: 24px; 46 | display: flex; 47 | background: url("data:image/svg+xml;charset=utf8,%3Csvg width='71' height='55' viewBox='0 0 71 55' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg clip-path='url(%23clip0)'%3E%3Cpath d='M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z' fill='%2323272A'/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id='clip0'%3E%3Crect width='71' height='55' fill='white'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E") 48 | no-repeat; 49 | background-size: 100% 100%; 50 | } 51 | 52 | &:hover { 53 | opacity: 0.6; 54 | } 55 | } 56 | 57 | .darker-row { 58 | background-color: #f7f7f7ba; 59 | } 60 | 61 | 62 | /* For dark theme */ 63 | html[data-theme='dark'] { 64 | .header-github-link:before { 65 | background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") 66 | no-repeat; 67 | } 68 | 69 | .header-discord-link:before { 70 | background: url("data:image/svg+xml;charset=utf8,%3Csvg width='71' height='55' viewBox='0 0 71 55' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg clip-path='url(%23clip0)'%3E%3Cpath d='M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z' fill='%23ffffff'/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id='clip0'%3E%3Crect width='71' height='55' fill='white'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E") 71 | no-repeat; 72 | background-size: 100% 100%; 73 | } 74 | 75 | .darker-row { 76 | background-color: #1e2028; 77 | } 78 | 79 | /* Disables different color for hero section */ 80 | .hero { 81 | background-color: inherit; 82 | } 83 | } 84 | 85 | .difference-image { 86 | width: 25%; 87 | } 88 | 89 | .padded-section { 90 | padding-top: 2%; 91 | padding-bottom: 2%; 92 | } 93 | 94 | @media (max-width: 996px) { 95 | #main-snippet-col { 96 | margin-top: 5%; 97 | } 98 | 99 | #find-library-col { 100 | padding-left: 0px; 101 | margin-top: 2%; 102 | } 103 | } -------------------------------------------------------------------------------- /docs/Developers/tokenization.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | description: 'Tokenization process specifications for Gura tokenizers development' 4 | keywords: ['Tokenization', 'Tokenizers', 'Edition', 'Gura manipulation'] 5 | --- 6 | 7 | # Tokenization 8 | 9 | 10 | ## Introduction 11 | 12 | One of the advantages of Gura is the standardization of all its parts. It was already explained in previous sections which data types and which errors must be supported to comply with the language specifications. 13 | 14 | However, it still remains to define a standardized schema that decomposes all parts of a document written in the Gura format. The process of extracting these parts from a document is called [tokenization][tokenization-wiki]. 15 | 16 | Establishing the basic structures of the language allows the development of Gura text generation tools that are useful, for example, for editing a document automatically. Without these definitions, tools that allow modifying a document must make their own interpretations since the language has no first-class notion of how comments, indentation, line breaks, etc. can be parsed; which leads to unwanted deletion of some parts of the document if the developer did not take them into account. 17 | 18 | This document will specify all the structures to be considered in a document written in the Gura format. This list of components is conformed by the basic types supported by Gura that, for the sake of simplicity, will only be listed and not explained (you can check the [*Basic types* section][parsing-section] to obtain information for each one). 19 | 20 | - **Null** 21 | - **Bool** 22 | - **String** 23 | - **Integer** 24 | - **Float** 25 | - **Array** 26 | - **Object** 27 | 28 | 29 | ## Tokenization structures 30 | 31 | But remember that the tokenization process must also include other technical aspects that are not part of the serialization/deserialization process. Instead, it must include components of the tokenized document that allow its manipulation while respecting the original structure. To do so, the following structs are introduced: 32 | 33 | - **Comment**: defines a comment. This, by definition, starts with the character `#` (U+0023) and all characters up to the end of the line are considered part of the comment. [Reference][comment-reference]. 34 | - **Variables**: indicates the definition of a variable with its name and value. [Reference][variables-reference]. 35 | - **Import**: defines the import sentence, should only indicate the file being imported, without verifying that it exists or is a valid Gura file, since these considerations are part of the parsing process. [Reference][imports-reference]. 36 | - **Space**: defines the use of space/s, either tabs (U+0009) or spaces (U+0020), which are useful when comments are found within the same line as another structure. The structure must contain the number of occurrences and must distinguish between tabs and spaces. 37 | - **Line** break: refers to the occurrence of LF (U+000A) or CRLF (U+000D U+000A). 38 | - **Trailing comma**: defines the presence of a comma in the last element of an array. 39 | 40 | Note that some structures do not need to be considered. Such as the indentation, which is always 4 for each internal level within an object. If an object contains one element, the indentation is 4 blanks (U+0020). If inside that object, there is another object with a key/value, the latter will be preceded by 8 blanks, and so on. In the case of commas, the same thing happens: commas are mandatory within an array to separate elements, so knowing the different structs that compose an array is enough to know how many commas must be considered. Trailing commas only need to be taken into account since they are optional and should be respected during the tokenization process in case the original document contains them. 41 | 42 | It is also important to clarify that **the order of the parsed elements must be preserved** to avoid breaking the original structure during the manipulation of a Gura document. 43 | 44 | 45 | ## Examples 46 | 47 | Consider the following Gura document: 48 | 49 | ```yaml 50 | # A comment 51 | name: "Gura config lang" 52 | 53 | properties: 54 | robust: true 55 | random_ar: [ 56 | "Simple ", 57 | 58 | 'easy', 59 | 4 60 | ] 61 | 62 | # Another comment 63 | inline_array: [1, 2.4, null,] 64 | ``` 65 | 66 | The tokenizer should generate the following structure: 67 | 68 | ``` 69 | Array([ 70 | Comment(" A comment"), 71 | Object({ 72 | "name": String("Gura config lang") 73 | }), 74 | BreakLine(), 75 | Object({ 76 | "properties": Object({ 77 | "robust": Bool(true), 78 | "random_ar": Array( 79 | [ 80 | String("Simple "), 81 | BreakLine(), 82 | String("easy"), 83 | Integer(4) 84 | ] 85 | ) 86 | }) 87 | }), 88 | BreakLine(), 89 | Comment(" Another comment"), 90 | Object({ 91 | "inline_array": Array([ 92 | Integer(1), 93 | Float(2.4), 94 | Null, 95 | TrailingComma() 96 | ]) 97 | }) 98 | ]) 99 | ``` 100 | 101 | Another example to consider could be the following, where variables and import statements are used: 102 | 103 | ```yaml 104 | import "some-file.ura" #Some import. This comment doesn't have trailing left space! 105 | 106 | # Comment with a Tab at beginning of the line 107 | $a_variable: "Some value" 108 | 109 | key: $a_variable 110 | ``` 111 | 112 | It should produce the following result during tokenization: 113 | 114 | ``` 115 | Array([ 116 | Import("some-file.ura"), 117 | Space(2), 118 | Comment("Some import. This comment doesn't have trailing left space!"), 119 | BreakLine(), 120 | Tab(1), 121 | Comment(" Comment with a Tab at beginning of the line"), 122 | Variable("a_variable"), 123 | Object({ 124 | "key": Variable("a_variable") 125 | }) 126 | ]) 127 | ``` 128 | 129 | 130 | ### About spaces in arrays 131 | 132 | Note that, in the previous example, line breaks are only explicitly specified when arrays explicitly span multiple lines. In case of `inline_array`, it does not contain any `BreakLine` elements, but the array named `random_ar` does. Although the presence of objects in an array necessarily involves line breaks, to keep rules the simplest as possible, we choose to maintain redundancy and explicitly preserve the line break during tokenization. 133 | 134 | To summarize, whenever line breaks appear **within an array**, they must be considered in the tokenization result. Consider the following example: 135 | 136 | ```yaml 137 | array_objects: [ 138 | person_1: 139 | name: 'Elvis', 140 | person_2: 141 | name: 'Jack', 142 | ] 143 | ``` 144 | 145 | The result of the tokenization would be: 146 | 147 | ``` 148 | Array([ 149 | Array([ 150 | BreakLine(), 151 | Object({ 152 | "person_1": Object({ 153 | "name": String("Elvis") 154 | }) 155 | }), 156 | BreakLine(), 157 | Object({ 158 | "person_2": Object({ 159 | "name": String("Jack") 160 | }) 161 | }), 162 | BreakLine() 163 | ]) 164 | ]) 165 | ``` 166 | 167 | Even the final line break is considered since Gura would allow closing the array where the user wants it. 168 | 169 | 170 | ## Important considerations 171 | 172 | There are some important considerations: 173 | - Unlike serialization/deserialization process, the initial structure cannot be an object since tokenization also considers elements that are not key/value pairs. That is why it consists of an array. 174 | - With the exception of line breaks within an array as [explained above](#about-spaces-in-arrays), only explicitly empty lines are considered as `BreakLine`, it should not be clarified after each element since the Gura definition does not allow the declaration of multiple key/value elements on the same line. 175 | - Trailing spaces at the beginning and end of both comments and strings must be considered. 176 | - Blanks on empty lines, whether tabs (U+0009) or spaces (U+0020), can be discarded as they do not contribute anything to the Gura structure. 177 | - The definition of a variable does not need to contain the `$` character since it is part of the formal definition of a variable. 178 | - The value of the variable does not need to be computed since the evaluation is done during the parsing process. 179 | - In order not to increase the complexity of the tokenization procedure, the standard space between the `:` and the value of a key/value pair is always 1, you may choose to keep a record with the `Space` structure if you wish, but it is not necessary. 180 | 181 | 182 | [parsing-section]: /docs/next/Developers/parsing#basic-types 183 | [comment-reference]: /docs/spec#comment 184 | [variables-reference]: /docs/spec#variables 185 | [imports-reference]: /docs/spec#imports 186 | [tokenization-wiki]: https://en.wikipedia.org/wiki/Lexical_analysis 187 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Gura logo 2 | 3 | # Gura 4 | 5 | [![Netlify Status](https://api.netlify.com/api/v1/badges/599a9cad-5a04-4e87-9f7b-1457004eabfb/deploy-status)](https://app.netlify.com/sites/gura/deploys) 6 | 7 | Gura is a file format for *configuration files*. Gura is as **flexible as YAML** and **simple and readable like TOML**. Its syntax is clear and powerful, yet familiar for YAML/TOML users: 8 | 9 | > This repository contains the source code of the Gura specification. 10 | > You can find the released versions at https://gura.netlify.app/. 11 | 12 | ```yaml 13 | # This is a comment in a Gura configuration file. 14 | # Define a variable named `title` with string value "Gura Example" 15 | title: "Gura Example" 16 | 17 | # Define an object with fields `username` and `age` 18 | # with string and integer values, respectively 19 | # Indentation is used to indicate nesting 20 | person: 21 | username: "Stephen" 22 | age: 20 23 | 24 | # Define a list of values 25 | # Line breaks are OK when inside arrays 26 | hosts: [ 27 | "alpha", 28 | "omega" 29 | ] 30 | 31 | # Variables can be defined and referenced to avoid repetition 32 | $foreground: "#FFAH84" 33 | color_scheme: 34 | editor: $foreground 35 | ui: $foreground 36 | 37 | ``` 38 | The file extension for Gura is `ura`. We recommend the filename `config.ura` for main configuration files. 39 | 40 | To learn more about Gura, you can read the [Official Gura Documentation][specs]. 41 | 42 | Currently, Gura has, among many others, a [Python implementation][gura-python-parser] you can install with `pip install gura` and start using today. 43 | 44 | ```python 45 | import gura 46 | 47 | gura_string = """ 48 | title: "Gura Example" 49 | 50 | person: 51 | username: "Stephen" 52 | age: 20 53 | 54 | hosts: [ 55 | "alpha", 56 | "omega" 57 | ] 58 | """ 59 | 60 | # Transforms in dictionary 61 | parsed_gura = gura.loads(gura_string) 62 | 63 | # Access a specific field 64 | print(f"Title -> {parsed_gura['title']}") 65 | 66 | # Access object data 67 | person = parsed_gura['person'] 68 | print(f"My username is {person['username']}") 69 | 70 | # Iterate over structure 71 | for host in parsed_gura['hosts']: 72 | print(f'Host -> {host}') 73 | ``` 74 | 75 | [Javascript/Typescript][gura-js-parser] parser is also available! Check the [complete implementation list](#library-implementations) to see available libraries. Other programming languages implementations are being currently developed and will be available shortly. 76 | 77 | 78 | ## Index 79 | 80 | - [Implementations](#library-implementations) 81 | - [IDE support](#ide-support) 82 | - [Contributing](#contributing) 83 | - [Acknowledgements](#acknowledgements) 84 | - [Rationale](#rationale) 85 | - [Licence](#licence) 86 | 87 | 88 | ## Library implementations 89 | 90 | Below is the list of implementations available for Gura. If you have an implementation of your own that you want to make known simply create a new issue and it will be added here. 91 | 92 | - Dart: [gura-dart-parser][gura-dart-parser] 93 | - Javascript/Typescript: [gura-js-parser (official)][gura-js-parser] 94 | - Python: [gura-python-parser (official)][gura-python-parser] 95 | - Rust: [gura-rs-parser (official)][gura-rs-parser] 96 | - V: [vgura (official)][vgura] 97 | 98 | 99 | ## IDE support 100 | 101 | Below is the list of IDEs plugins available for Gura. If you have developed a plugin or IDE integration that you want to make known simply create a new issue and it will be added here. 102 | 103 | - VS Code: [Gura Syntax Highlighting][vs-code-plugin] 104 | 105 | 106 | ## Contributing 107 | 108 | All help is more than welcome. You can: 109 | 110 | - Join to our [community in Discord][discord-server]! 111 | - Write an RFC via our [GitHub Discussions][discussions] if you feel there is a bug in Gura or a missing feature. 112 | - Contribute to some of the implementations, or write your own in the programming language of your choice! In the latter case don't forget to make an issue letting us know that your implementation is available so we can add it to the [Implementations](#implementations) list. 113 | 114 | If you want to contribute with this website: it is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. 115 | 116 | ### Installation 117 | 118 | ```console 119 | yarn install 120 | ``` 121 | 122 | ### Local Development 123 | 124 | ```console 125 | yarn start 126 | ``` 127 | 128 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 129 | 130 | ### Build 131 | 132 | ```console 133 | yarn build 134 | ``` 135 | 136 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 137 | 138 | 139 | ## Rationale 140 | 141 | Gura was born from the need to have a configuration language that is human readable without falling into the unnecessary complexity of popular formats such as YAML. The following is an overview of the issues with such formats, which motivated the creation of this new configuration language. 142 | 143 | 144 | ### Differences with YAML 145 | 146 | YAML offered a readable alternative to JSON or INI for a configuration file. While TOML was great for basic files because of its simplicity, YAML provided a readable solution when the complexity of the file grew. However, as [the NOYAML manifesto][blog] argues, we should stop supporting that format. The reason? [YAML is unnecessarily complex][reddit-post]. We highlight main issues with YAML that Gura tries to solve. 147 | 148 | - Multiple different ways to define a list and the elements inside it 149 | - 4 (!) ways to define a boolean 150 | - Boolean automatically inferred from strings ([workarounds][boolean-workaround]) 151 | - Unnecessary unquoted strings that lead to float type inference problems 152 | - Serious security issues. [Safe YAML][safe-yaml] attempts to address those, but only those. 153 | - [Increadibly long YAML specs][yaml-specs] for what is supposed to be a simple configuration language? 154 | - Special data types such as *Date* or *Datetime* are defined in the spec, but the definition of their semantics is relegated to each specific implementation. 155 | 156 | All the previous points lead to a difficult implementation in any programming language, it is enough to see the repositories of the different languages to realize that carrying out a YAML parser is a complicated task. 157 | 158 | 159 | ### Differences with TOML 160 | 161 | The idea of Gura is not to replace TOML, but to complement it when the complexity of the project warrants it. The use of TOML for files such as `cargo.toml` in the Rust programming language is an excellent example of matching the complexity of the language to that of the domain. However, when the level of nesting increases, TOML is very cumbersome since you must resort to repeating all the parent levels (using [Dotted keys][dotted-keys]) every time you want to define a nested value. 162 | 163 | Furthermore, even TOML falls in some cases into the same complexity as YAML, with features such as: 164 | 165 | - Multiple ways to specify keys 166 | - Empty keys 167 | - Special data types 168 | 169 | 170 | ### Differences with JSON 171 | 172 | JSON is and will be the fastest serialization language available. Gura is not meant for fast processing and/or machine-to-machine communication. When a readable, simple and maintainable language is needed Gura becomes an excellent alternative. 173 | 174 | 175 | ### Gura 176 | 177 | Gura combines the readability of YAML and a reduced version of its syntax with the (even more simplified) simplicity of TOML. It also brings in some features and characteristics exclusive to this language: 178 | 179 | - 📦 Variables: Gura allows you to define variables of any type, even using environment variables, both as a flat value and as values inside a string. So you can compact and reuse the values you require. 180 | - 📑 Imports: Gura defines a way to import different Gura files within the same file in order to modularize the configuration. 181 | - 🚫 Standard errors: Gura defines the *semantic* errors that should be thrown in certain situations. This way you get an implementation-agnostic definition and the developer can get the same type of error regardless of the programming language he/she is using. 182 | - 🥧 Gura is short and simple to learn and use, since it follows the `only one way to do it` Python maxim. 183 | - 🌈 Writing a parser or wrapper for Gura in a new language should be a short and simple as well. 184 | 185 | 186 | Gura does not seek to replace the behavior that any programming language already offers in a much flexible and robust way. Therefore, it is limited to explicit static definitions that make it easier to understand both the language and the configuration files. 187 | 188 | Gura **will always be focused on simplicity**. Therefore, we are reluctant to support more complex structures. If you are looking for a way to execute code like loops, conditions, functions and so on in a config file, we recommend [Dhall][dhall]. 189 | 190 | 191 | ## Acknowledgements 192 | 193 | I want to give my sincere thanks to [Facundo Quiroga][quiroga] and [Ulises Jeremias Cornejo Fandos][cornejo-fandos] for their guidance and valuable opinions during the design and implementation of Gura. 194 | 195 | 196 | ## License 197 | 198 | Gura is distributed under the terms of the MIT license. 199 | 200 | 201 | [blog]: https://noyaml.com/ 202 | [specs]: https://gura.netlify.app/docs/gura 203 | [boolean-workaround]: https://stackoverflow.com/questions/53648244/specifying-the-string-value-yes-in-a-yaml-property 204 | [safe-yaml]: https://pyyaml.docsforge.com/master/api/yaml/safe_load/ 205 | [yaml-specs]: https://yaml.org/spec/1.2/spec.html 206 | [reddit-post]: https://www.reddit.com/r/programming/comments/iqwbek/stop_adding_support_for_yaml_in_your_products/ 207 | [dotted-keys]: https://toml.io/en/v1.0.0#table 208 | [dhall]: https://dhall-lang.org/# 209 | [gura-dart-parser]: https://github.com/zajrik/gura-dart-parser 210 | [gura-js-parser]: https://github.com/gura-conf/gura-js-parser 211 | [gura-python-parser]: https://github.com/gura-conf/gura-python-parser 212 | [gura-rs-parser]: https://github.com/gura-conf/gura-rs-parser 213 | [vgura]: https://github.com/gura-conf/vgura 214 | [discussions]: https://github.com/gura-conf/gura/discussions/categories/ideas-rfc 215 | [quiroga]: https://github.com/facundoq 216 | [cornejo-fandos]: https://github.com/ulises-jeremias 217 | [discord-server]: https://discord.gg/Qs5AXPQpKd 218 | [vs-code-plugin]: https://marketplace.visualstudio.com/items?itemName=zajrik.gura-syntax-highlight 219 | -------------------------------------------------------------------------------- /versioned_docs/version-1.0.0/spec.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Specs 6 | 7 | * Gura is case-sensitive. 8 | * A Gura file must be a valid UTF-8 encoded Unicode document. 9 | * Whitespace means tab (U+0009) or space (U+0020). 10 | * Newline means LF (U+000A) or CRLF (U+000D U+000A). 11 | 12 | 13 | ## Comment 14 | 15 | A hash symbol marks the rest of the line as a comment, except when inside a 16 | string. 17 | 18 | ```yaml 19 | # This is a full-line comment 20 | key: "value" # This is a comment at the end of a line 21 | another: "# This is not a comment" 22 | ``` 23 | 24 | Control characters other than tab (U+0000 to U+0008, U+000A to U+001F, U+007F) are not permitted in comments. 25 | 26 | 27 | ## Key/Value Pair 28 | 29 | The primary building block of a Gura document is the key/value pair. 30 | 31 | Keys are on the left of the colon and values are on the right. Whitespace is ignored around key names and values. The key, colon, and value must be on the same line (though some values can be broken over multiple lines). 32 | 33 | ```yaml 34 | key: "value" 35 | ``` 36 | 37 | Values must have one of the following types. 38 | 39 | - [Null](#null) 40 | - [String](#string) 41 | - [Integer](#integer) 42 | - [Float](#float) 43 | - [Boolean](#boolean) 44 | - [Object](#object) 45 | - [Array](#array) 46 | 47 | Unspecified values are invalid. 48 | 49 | ```yaml 50 | key: # INVALID 51 | ``` 52 | 53 | There must be a newline (or EOF) after a key/value pair. 54 | 55 | ``` 56 | first: "Carlitos" last: "Gardel" # INVALID 57 | ``` 58 | 59 | 60 | ## Keys 61 | 62 | In Gura there is only one way to define keys. A key may only contain ASCII letters and underscores (`A-Za-z0-9_`). Dashes are not allowed to keep a simple and consistent key naming convention. Note that keys are allowed to be composed of only ASCII digits, e.g. `1234`, but are always interpreted as strings. 63 | 64 | ```yaml 65 | key: "value" 66 | some_key: "value" 67 | some-key: "value" # INVALID 68 | 1234: "value" 69 | ``` 70 | 71 | A key must be non-empty. 72 | 73 | ```yaml 74 | : "no key name" # INVALID 75 | ``` 76 | 77 | Defining a key multiple times is invalid and must raise a `DuplicatedKeyError` error. 78 | 79 | ```yaml 80 | # DO NOT DO THIS 81 | name: "Carlos" 82 | name: "Anibal" 83 | ``` 84 | 85 | 86 | ## Null 87 | 88 | The absence of a value can be represented by the `null` value: 89 | 90 | ```yaml 91 | none_value: null 92 | ``` 93 | 94 | 95 | ## String 96 | 97 | There are four ways to express strings: basic, multi-line basic, literal, and multi-line literal. All strings must contain only valid UTF-8 characters. 98 | 99 | Unlike YAML, unquoted strings are not allowed. 100 | 101 | **Basic strings** are surrounded by quotation marks (`"`). Any Unicode character may be used except those that must be escaped: quotation mark, backslash, and the control characters other than tab (U+0000 to U+0008, U+000A to U+001F, U+007F). 102 | 103 | ```yaml 104 | str: "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF." 105 | ``` 106 | 107 | For convenience, some popular characters have a compact escape sequence. 108 | 109 | ``` 110 | \b - backspace (U+0008) 111 | \t - tab (U+0009) 112 | \n - linefeed (U+000A) 113 | \f - form feed (U+000C) 114 | \r - carriage return (U+000D) 115 | \" - quote (U+0022) 116 | \\ - backslash (U+005C) 117 | \$ - dollar sign (variables) (U+0024) 118 | \uXXXX - unicode (U+XXXX) 119 | \UXXXXXXXX - unicode (U+XXXXXXXX) 120 | ``` 121 | 122 | Any Unicode character may be escaped with the `\uXXXX` or `\UXXXXXXXX` forms. The escape codes must be valid Unicode [scalar values](https://unicode.org/glossary/#unicode_scalar_value). 123 | 124 | All other escape sequences not listed above will be interpreted as literal. 125 | 126 | Sometimes you need to express passages of text (e.g. translation files) or would like to break up a very long string into multiple lines. Gura makes this easy. 127 | 128 | **Multi-line basic strings** are surrounded by three quotation marks on each side and allow newlines. A newline immediately following the opening delimiter will be trimmed. All other whitespace and newline characters remain intact. 129 | 130 | ```yaml 131 | str1: """ 132 | Roses are red 133 | Violets are blue""" 134 | ``` 135 | 136 | Gura parsers should feel free to normalize newline to whatever makes sense for their platform. 137 | 138 | ```yaml 139 | # On a Unix system, the above multi-line string will most likely be the same as: 140 | str2: "Roses are red\nViolets are blue" 141 | 142 | # On a Windows system, it will most likely be equivalent to: 143 | str3: "Roses are red\r\nViolets are blue" 144 | ``` 145 | 146 | For writing long strings without introducing extraneous whitespace, use a "line ending backslash". When the last non-whitespace character on a line is an unescaped `\`, it will be trimmed along with all whitespace (including newlines) up to the next non-whitespace character or closing delimiter. All of the escape sequences that are valid for basic strings are also valid for multi-line basic strings. 147 | 148 | ```yaml 149 | # The following strings are byte-for-byte equivalent: 150 | str1: "The quick brown fox jumps over the lazy dog." 151 | 152 | str2: """ 153 | The quick brown \ 154 | 155 | 156 | fox jumps over \ 157 | the lazy dog.""" 158 | 159 | str3: """\ 160 | The quick brown \ 161 | fox jumps over \ 162 | the lazy dog.\ 163 | """ 164 | ``` 165 | 166 | Any Unicode character may be used except those that must be escaped: backslash and the control characters other than tab, line feed, and carriage return (U+0000 to U+0008, U+000B, U+000C, U+000E to U+001F, U+007F). 167 | 168 | You can write a quotation mark, or two adjacent quotation marks, anywhere inside a multi-line basic string. They can also be written just inside the delimiters. 169 | 170 | ```yaml 171 | str4: """Here are two quotation marks: "". Simple enough.""" 172 | # str5: """Here are three quotation marks: """.""" # INVALID 173 | str5: """Here are three quotation marks: ""\".""" 174 | str6: """Here are fifteen quotation marks: ""\"""\"""\"""\"""\".""" 175 | ``` 176 | 177 | Unlike TOML, it is invalid to use three quotation marks inside a multi-line string: 178 | 179 | ```yaml 180 | # "This," she said, "is just a pointless statement." 181 | str7: """"This," she said, "is just a pointless statement."""" # INVALID 182 | ``` 183 | 184 | If you're a frequent specifier of Windows paths or regular expressions, then having to escape backslashes quickly becomes tedious and error-prone. To help, Gura supports literal strings which do not allow escaping at all. 185 | 186 | **Literal strings** are surrounded by single quotes. Like basic strings, they must appear on a single line: 187 | 188 | ```yaml 189 | # What you see is what you get. 190 | winpath: 'C:\Users\nodejs\templates' 191 | winpath2: '\\ServerX\admin$\system32\' 192 | quoted: 'John "Dog lover" Wick' 193 | regex: '<\i\c*\s*>' 194 | ``` 195 | 196 | Since there is no escaping, there is no way to write a single quote inside a literal string enclosed by single quotes. Luckily, Gura supports a multi-line version of literal strings that solves this problem. 197 | 198 | **Multi-line literal strings** are surrounded by three single quotes on each side and allow newlines. Like literal strings, there is no escaping whatsoever. A newline immediately following the opening delimiter will be trimmed. All other content between the delimiters is interpreted as-is without modification. 199 | 200 | ```yaml 201 | regex2: '''I [dw]on't need \d{2} apples''' 202 | lines: ''' 203 | The first newline is 204 | trimmed in raw strings. 205 | All other whitespace 206 | is preserved. 207 | ''' 208 | ``` 209 | 210 | You can write 1 or 2 single quotes anywhere within a multi-line literal string, but sequences of three or more single quotes are not permitted. 211 | 212 | ```yaml 213 | quot15: '''Here are fifteen quotation marks: """""""""""""""''' 214 | 215 | # apos15: '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID 216 | apos15: "Here are fifteen apostrophes: '''''''''''''''" 217 | 218 | # 'That,' she said, 'is still pointless.' 219 | str: ''''That,' she said, 'is still pointless.'''' 220 | ``` 221 | 222 | Control characters other than tab are not permitted in a literal string. Thus, for binary data, it is recommended that you use Base64 or another suitable ASCII or UTF-8 encoding. The handling of that encoding will be application-specific. 223 | 224 | 225 | ## Integer 226 | 227 | Integers are whole numbers. Positive numbers may be prefixed with a plus sign. Negative numbers are prefixed with a minus sign. 228 | 229 | ```yaml 230 | int1: +99 231 | int2: 42 232 | int3: 0 233 | int4: -17 234 | ``` 235 | 236 | For large numbers, you may use underscores between digits to enhance readability. Each underscore must be surrounded by at least one digit on each side. 237 | 238 | ```yaml 239 | int5: 1_000 240 | int6: 5_349_221 241 | int7: 53_49_221 # Indian number system grouping 242 | ``` 243 | 244 | Leading zeros are not allowed. Integer values `-0` and `+0` are valid and identical to an unprefixed zero. Non-negative integer values may also be expressed in hexadecimal, octal, or binary. In these formats, leading `+` is not allowed and leading zeros are allowed (after the prefix). Hex values are case-insensitive. Underscores are allowed between digits (but not between the prefix and the value). 245 | 246 | ```yaml 247 | # Hexadecimal with prefix `0x` 248 | hex1: 0xDEADBEEF 249 | hex2: 0xdeadbeef 250 | hex3: 0xdead_beef 251 | 252 | # Octal with prefix `0o` 253 | oct1: 0o01234567 254 | oct2: 0o755 # useful for Unix file permissions 255 | 256 | # Binary with prefix `0b` 257 | bin1: 0b11010110 258 | ``` 259 | 260 | Arbitrary 64-bit signed integers (from −2^63 to 2^63−1) should be accepted and handled losslessly. If an integer cannot be represented losslessly, an error must be thrown. 261 | 262 | 263 | ## Float 264 | 265 | Floats should be implemented as IEEE 754 binary64 values. 266 | 267 | A float consists of an integer part (which follows the same rules as decimal integer values) followed by a fractional part and/or an exponent part. If both a fractional part and exponent part are present, the fractional part must precede the exponent part. 268 | 269 | ```yaml 270 | # Fractional 271 | flt1: +1.0 272 | flt2: 3.1415 273 | flt3: -0.01 274 | 275 | # Exponent 276 | flt4: 5e+22 277 | flt5: 1e06 278 | flt6: -2E-2 279 | 280 | # Both 281 | flt7: 6.626e-34 282 | ``` 283 | 284 | A fractional part is a decimal point followed by one or more digits. 285 | 286 | An exponent part is an E (upper or lower case) followed by an integer part (which follows the same rules as decimal integer values but may include leading zeros). 287 | 288 | The decimal point, if used, must be surrounded by at least one digit on each side. 289 | 290 | ```yaml 291 | # INVALID FLOATS 292 | invalid_float_1: .7 293 | invalid_float_2: 7. 294 | invalid_float_3: 3.e+20 295 | ``` 296 | 297 | Similar to integers, you may use underscores to enhance readability. 298 | 299 | ```yaml 300 | flt8: 224_617.445_991_228 301 | ``` 302 | 303 | Float values `-0.0` and `+0.0` are valid and should map according to IEEE 754. 304 | 305 | Special float values can also be expressed. They are always lowercase. 306 | 307 | ```yaml 308 | # Infinity 309 | sf1: inf # Positive infinity 310 | sf2: +inf # Positive infinity 311 | sf3: -inf # Negative infinity 312 | 313 | # Not a number 314 | sf4: nan # Actual sNaN/qNaN encoding is implementation-specific 315 | sf5: +nan # Same as `nan` 316 | sf6: -nan # Valid, actual encoding is implementation-specific 317 | ``` 318 | 319 | 320 | ## Boolean 321 | 322 | Booleans are just the tokens you're used to. Always lowercase. 323 | 324 | ```yaml 325 | bool1: true 326 | bool2: false 327 | ``` 328 | 329 | 330 | ## Object 331 | 332 | Like YAML, objects have a header (key), a colon and underneath each of their attributes, which must begin in an indented block. This indentation must be respected throughout the entire Gura file and each indentation level must be represented by 4 (four) spaces (U+0020). Unlike YAML, tabs (U+0009) are not allowed to define indentation blocks in order to standardize language formatting and provide users with a convenient way to maintain documents. 333 | 334 | 335 | ```yaml 336 | services: 337 | nginx: 338 | host: "127.0.0.1" 339 | port: 80 340 | 341 | apache: 342 | virtual_host: "10.10.10.4" 343 | port: 81 344 | ``` 345 | 346 | The equivalent JSON would be: 347 | 348 | ```json 349 | { 350 | "services": { 351 | "nginx": { 352 | "host": "127.0.0.1", 353 | "port": 80 354 | }, 355 | "apache": { 356 | "virtual_host": "10.10.10.4", 357 | "port": 81 358 | } 359 | } 360 | } 361 | ``` 362 | 363 | **Some considerations about the indentation** 364 | 365 | A space (U+0020) or a tab (U+0009) can be used on useless lines like comments o empty lines (lines composed of whitespaces and new lines) but only. In case a tab is found as an indentation character, an `InvalidIndentationError` must be raised. 366 | 367 | Also, as mentioned previously, the indentation levels must be divisible by 4, otherwise an `InvalidIndentationError` error must be raised: 368 | 369 | ```yaml 370 | # INVALID as second level has block of 8 spaces as indentation 371 | services: 372 | nginx: 373 | host: "127.0.0.1" 374 | port: 80 375 | 376 | # INVALID as 2 spaces are used as indentation block 377 | user: 378 | name: "Gura" 379 | ``` 380 | 381 | Finally, as empty values are not allowed, the following case considers any value below `name` as an internal block. As the indentation length between parent and child blocks is the same an `InvalidIndentationError` exception will be thrown: 382 | 383 | ```yaml 384 | user: 385 | name: # INVALID 386 | surname: "Troilo" 387 | ``` 388 | 389 | **Empty objects** 390 | 391 | While the idea is that the configuration of a system is valid, complete, and static information, there may be situations where the information is empty. Assume the following case in JSON: 392 | 393 | ```json 394 | { 395 | "empty_object": {} 396 | } 397 | ``` 398 | 399 | To maintain compatibility with existing languages with support for empty objects such as JSON or YAML, Gura provides the `empty` keyword to cover these scenarios. The above example could be represented in Gura as follows: 400 | 401 | ```yaml 402 | empty_object: empty 403 | ``` 404 | 405 | In this way, an explicit and clear syntax is provided to cover these rare cases, without losing the portability of the configuration to and from other languages. 406 | 407 | 408 | ## Array 409 | 410 | Arrays are square brackets with values inside. Whitespace is ignored. Elements are separated by commas. Arrays can contain values of the same data types as allowed in key/value pairs. Values of different types may be mixed. 411 | 412 | ```yaml 413 | integers: [ 1, 2, 3 ] 414 | colors: [ "red", "yellow", "green" ] 415 | nested_arrays_of_ints: [ [ 1, 2 ], [3, 4, 5] ] 416 | nested_mixed_array: [ [ 1, 2 ], ["a", "b", "c"] ] 417 | 418 | # Mixed-type arrays are allowed 419 | numbers: [ 0.1, 0.2, 0.5, 1, 2, 5 ] 420 | tango_singers: [ 421 | user1: 422 | name: "Carlos" 423 | surname: "Gardel" 424 | year_of_birth: 1890, 425 | 426 | user2: 427 | name: "Aníbal" 428 | surname: "Troilo" 429 | year_of_birth: 1914 430 | ] 431 | ``` 432 | 433 | Arrays can span multiple lines. A terminating comma (also called a trailing comma) is permitted after the last value of the array. Any number of newlines and comments may precede values, commas, and the closing bracket. Indentation between array values and commas is treated as whitespace and ignored. 434 | 435 | ```yaml 436 | integers2: [ 437 | 1, 2, 3 438 | ] 439 | 440 | integers3: [ 441 | 1, 442 | 2, # This is ok 443 | ] 444 | ``` 445 | 446 | Since the comma is the only valid element separator for an array, it is recommended to add a line between elements that are objects or multiple key/values to improve legibility: 447 | 448 | ```yaml 449 | # It is valid but a little hard to read 450 | singers: [ 451 | name: "Andrea" 452 | surname: "Bocelli" 453 | gender: "Opera", 454 | name: "Jimi" 455 | surname: "Hendrix" 456 | gender: "Rock" 457 | ] 458 | 459 | # Much better! 460 | singers: [ 461 | name: "Andrea" 462 | surname: "Bocelli" 463 | gender: "Opera", 464 | 465 | name: "Jimi" 466 | surname: "Hendrix" 467 | gender: "Rock" 468 | ] 469 | ``` 470 | 471 | 472 | ## Variables 473 | 474 | You can define variables. They start with a `$` sign, a name and a colon. A variable name has to respect the same regex as keys and only strings, numbers or other variable are allowed as values. If any of another kind of value type is used a parsing error must be raised. 475 | 476 | ```yaml 477 | $my_string_var: "127.0.0.1" 478 | $my_integer_var: 8080 479 | 480 | nginx: 481 | host: $my_string_var 482 | port: $my_integer_var 483 | 484 | $invalid_var: null # INVALID null is not allowed as variable value 485 | $invalid_var2: true # INVALID booleans are not allowed as variable value 486 | $invalid_var3: [ 1, 2, 3 ] # INVALID complex types such as arrays or objects are not allowed as variable value 487 | ``` 488 | 489 | Variables can not be used as key. 490 | 491 | ```yaml 492 | $hostkey: "host" 493 | nginx: 494 | $hostkey : 4 # INVALID 495 | ``` 496 | 497 | Variables must be specified before they are used, in source code order. Redefining variables must raise a `DuplicatedVariableError` error, even when defined in different files (see [imports](#imports)). 498 | 499 | Variables can be used in *Basic strings* and *Multi-line basic strings*: 500 | 501 | ```yaml 502 | $name: "Gura" 503 | key: "$name is cool" 504 | key_2: """Config languages using variables: 505 | - $name""" 506 | ``` 507 | 508 | Environment variables can be accessed using `$` sign too. 509 | 510 | ```yaml 511 | service: 512 | postgres: 513 | environment: 514 | user: $DB_USER 515 | password: $DB_PASS 516 | 517 | # You can store its value in a variable too 518 | $my_path: $PATH 519 | 520 | # You can replace environment variables like normal ones. After all, environment variables are normal variables defined before parsing. 521 | $PATH: "Another value" 522 | ``` 523 | 524 | When a variable is used Gura looks for the definition in the current file and the imported ones. If it is not defined, checks for available environment variables, if it is not, it must raise a `VariableNotDefinedError` error. 525 | 526 | To use `$` in string just use literal or escape them: 527 | 528 | 529 | ```yaml 530 | basic: "I won \$500 dollars!" 531 | basic_multiline: """I won \$500 dollars!""" 532 | literal: 'I won $500 dollars!' 533 | literal_multiline: '''I won $500 dollars!''' 534 | ``` 535 | 536 | 537 | ## Imports 538 | 539 | You can import one or more Gura files using an `import` statement. The effect of importing a file is the same as replacing the import by the file's contents. Therefore, all the keys and variables defined on them will be available in the file which is importing. 540 | 541 | Imports must occur at the beginning of the file and there must be no blanks in front of the `import` statement. Must be only one whitespace between the `import` and file name. The file name must be between single quotation marks (") and there won't be special character escaping. Importing a non-existing file must raise a `FileNotFoundError` error. 542 | 543 | ```yaml 544 | import "another_file.ura" # Good 545 | import "another_file.ura" # INVALID: there are blanks before import 546 | import "another_file.ura" # INVALID: there are more than one whitespace between import and file name 547 | 548 | some_key: "Some value" 549 | 550 | import "another_file.ura" # INVALID: is not at the beginning of the file 551 | ``` 552 | 553 | 554 | 555 | A file can only be imported once. Re-importing a file must raise a `DuplicatedImportError` error. 556 | 557 | 558 | **one.ura**: 559 | 560 | ```yaml 561 | life: 42 562 | ``` 563 | 564 | **two.ura**: 565 | 566 | ```yaml 567 | import "one.ura" 568 | 569 | $my_var: "My var value" 570 | ``` 571 | 572 | **three.ura**: 573 | 574 | ```yaml 575 | $name: "Elisa" 576 | ``` 577 | 578 | **main.ura**: 579 | 580 | ```yaml 581 | import "two.ura" 582 | import "/absolute/path/to/three.ura" # You can use absolute path too 583 | 584 | # life, $my_var and $name are available here 585 | my_name: $name 586 | 587 | # life: "some value" # This WILL NOT work as it is defined in one.ura which is included in two.ura 588 | ``` 589 | 590 | You can use variables inside import sentences! 591 | 592 | ```yaml 593 | $common_path: "/extremely/long/path/to/some/useful/directory" 594 | 595 | import "$common_path/one.ura" 596 | import "$common_path/two.ura" 597 | ``` 598 | -------------------------------------------------------------------------------- /docs/spec.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | description: 'Gura configuration language specifications' 4 | keywords: ['Gura specs'] 5 | --- 6 | 7 | # Specs 8 | 9 | * Gura is case-sensitive. 10 | * A Gura file must be a valid UTF-8 encoded Unicode document. 11 | * Whitespace means tab (U+0009) or space (U+0020). 12 | * Newline means LF (U+000A) or CRLF (U+000D U+000A). 13 | 14 | 15 | ## Comment 16 | 17 | A hash symbol (U+0023) marks the rest of the line as a comment, except when inside a string. 18 | 19 | ```yaml 20 | # This is a full-line comment 21 | key: "value" # This is a comment at the end of a line 22 | another: "# This is not a comment" 23 | ``` 24 | 25 | Control characters other than tab (U+0000 to U+0008, U+000A to U+001F, U+007F) are not permitted in comments. 26 | 27 | 28 | ## Key/Value Pair 29 | 30 | The primary building block of a Gura document is the key/value pair. 31 | 32 | Keys are on the left of the colon and values are on the right. Whitespace is ignored around key names and values. The key, colon, and value must be on the same line (though some values can be broken over multiple lines). 33 | 34 | ```yaml 35 | key: "value" 36 | ``` 37 | 38 | Values must have one of the following types. 39 | 40 | - [Null](#null) 41 | - [String](#string) 42 | - [Integer](#integer) 43 | - [Float](#float) 44 | - [Boolean](#boolean) 45 | - [Object](#object) 46 | - [Array](#array) 47 | 48 | Unspecified values are invalid. 49 | 50 | ```yaml 51 | key: # INVALID 52 | ``` 53 | 54 | There must be a newline (or EOF) after a key/value pair. 55 | 56 | ``` 57 | first: "Carlitos" last: "Gardel" # INVALID 58 | ``` 59 | 60 | 61 | ## Keys 62 | 63 | In Gura there is only one way to define keys. A key may only contain ASCII letters and underscores (`A-Za-z0-9_`). Dashes are not allowed to keep a simple and consistent key naming convention. Note that keys are allowed to be composed of only ASCII digits, e.g. `1234`, but are always interpreted as strings. 64 | 65 | ```yaml 66 | key: "value" 67 | some_key: "value" 68 | some-key: "value" # INVALID 69 | 1234: "value" 70 | ``` 71 | 72 | A key must be non-empty. 73 | 74 | ```yaml 75 | : "no key name" # INVALID 76 | ``` 77 | 78 | Defining a key multiple times is invalid and must raise a `DuplicatedKeyError` error. 79 | 80 | ```yaml 81 | # DO NOT DO THIS 82 | name: "Carlos" 83 | name: "Anibal" 84 | ``` 85 | 86 | **Literal keys** 87 | 88 | Gura was created with simplicity, maintainability, and **portability** in mind. In a production environment, you will likely have to work with different tools that handle different configuration languages. To make Gura compatible with other configuration schemes, *Literal Keys* are provided, these are defined between grave accents `` ` `` (U+0060 GRAVE ACCENT) and can contain any valid UTF-8 character. 89 | 90 | If the `` ` `` character is required within a Literal Key, it must be escaped. Any character from the list in the [String section](#string) can be escaped inside Literal Keys too. If any other character that has not been previously mentioned is escaped, `InvalidEscapedCharacterError` must be raised, exactly as if it were a string. 91 | 92 | ```yaml 93 | `a/literal.key!`: "Some value" 94 | `Escaped\`char\tWithTabs`: true 95 | `\invalid`: false # INVALID: \i is not a valid escape sentence 96 | ``` 97 | 98 | :::caution 99 | 100 | The purpose of the Literal Keys is solely to provide compatibility with other configuration languages. **It is recommended to avoid them unless strictly necessary**, in order to maintain a clean and standardized configuration. 101 | 102 | ::: 103 | 104 | 105 | ## Null 106 | 107 | The absence of a value can be represented by the `null` value: 108 | 109 | ```yaml 110 | none_value: null 111 | ``` 112 | 113 | 114 | ## String 115 | 116 | There are four ways to express strings: basic, multi-line basic, literal, and multi-line literal. All strings must contain only valid UTF-8 characters. 117 | 118 | Unlike YAML, unquoted strings are not allowed. 119 | 120 | **Basic strings** are surrounded by quotation marks (`"`). Any Unicode character may be used except those that must be escaped: quotation mark, backslash, and the control characters other than tab (U+0000 to U+0008, U+000A to U+001F, U+007F). 121 | 122 | ```yaml 123 | str: "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF." 124 | ``` 125 | 126 | For convenience, some popular characters have a compact escape sequence. 127 | 128 | ``` 129 | \b - backspace (U+0008) 130 | \t - tab (U+0009) 131 | \n - linefeed (U+000A) 132 | \f - form feed (U+000C) 133 | \r - carriage return (U+000D) 134 | \" - quote (U+0022) 135 | \\ - backslash (U+005C) 136 | \$ - dollar sign (variables) (U+0024) 137 | \uXXXX - unicode (U+XXXX) 138 | \UXXXXXXXX - unicode (U+XXXXXXXX) 139 | ``` 140 | 141 | Any Unicode character may be escaped with the `\uXXXX` or `\UXXXXXXXX` forms. The escape codes must be valid Unicode [scalar values](https://unicode.org/glossary/#unicode_scalar_value). 142 | 143 | All other escape sequences not listed above are not valid and must raise `InvalidEscapedCharacterError`. 144 | 145 | Sometimes you need to express passages of text (e.g. translation files) or would like to break up a very long string into multiple lines. Gura makes this easy. 146 | 147 | **Multi-line basic strings** are surrounded by three quotation marks on each side and allow newlines. A newline immediately following the opening delimiter will be trimmed. All other whitespace and newline characters remain intact. 148 | 149 | ```yaml 150 | str1: """ 151 | Roses are red 152 | Violets are blue""" 153 | ``` 154 | 155 | Gura parsers should feel free to normalize newline to whatever makes sense for their platform. 156 | 157 | ```yaml 158 | # On a Unix system, the above multi-line string will most likely be the same as: 159 | str2: "Roses are red\nViolets are blue" 160 | 161 | # On a Windows system, it will most likely be equivalent to: 162 | str3: "Roses are red\r\nViolets are blue" 163 | ``` 164 | 165 | For writing long strings without introducing extraneous whitespace, use a "line ending backslash". When the last non-whitespace character on a line is an unescaped `\`, it will be trimmed along with all whitespace (including newlines) up to the next non-whitespace character or closing delimiter. All of the escape sequences that are valid for basic strings are also valid for multi-line basic strings. 166 | 167 | ```yaml 168 | # The following strings are byte-for-byte equivalent: 169 | str1: "The quick brown fox jumps over the lazy dog." 170 | 171 | str2: """ 172 | The quick brown \ 173 | 174 | 175 | fox jumps over \ 176 | the lazy dog.""" 177 | 178 | str3: """\ 179 | The quick brown \ 180 | fox jumps over \ 181 | the lazy dog.\ 182 | """ 183 | ``` 184 | 185 | Any Unicode character may be used except those that must be escaped: backslash and the control characters other than tab, line feed, and carriage return (U+0000 to U+0008, U+000B, U+000C, U+000E to U+001F, U+007F). 186 | 187 | You can write a quotation mark, or two adjacent quotation marks, anywhere inside a multi-line basic string. They can also be written just inside the delimiters. 188 | 189 | ```yaml 190 | str4: """Here are two quotation marks: "". Simple enough.""" 191 | # str5: """Here are three quotation marks: """.""" # INVALID 192 | str5: """Here are three quotation marks: ""\".""" 193 | str6: """Here are fifteen quotation marks: ""\"""\"""\"""\"""\".""" 194 | ``` 195 | 196 | Unlike TOML, it is invalid to use three quotation marks inside a multi-line string: 197 | 198 | ```yaml 199 | # "This," she said, "is just a pointless statement." 200 | str7: """"This," she said, "is just a pointless statement."""" # INVALID 201 | ``` 202 | 203 | If you're a frequent specifier of Windows paths or regular expressions, then having to escape backslashes quickly becomes tedious and error-prone. To help, Gura supports literal strings which do not allow escaping at all. 204 | 205 | **Literal strings** are surrounded by single quotes. Like basic strings, they must appear on a single line: 206 | 207 | ```yaml 208 | # What you see is what you get. 209 | winpath: 'C:\Users\nodejs\templates' 210 | winpath2: '\\ServerX\admin$\system32\' 211 | quoted: 'John "Dog lover" Wick' 212 | regex: '<\i\c*\s*>' 213 | ``` 214 | 215 | Since there is no escaping, there is no way to write a single quote inside a literal string enclosed by single quotes. Luckily, Gura supports a multi-line version of literal strings that solves this problem. 216 | 217 | **Multi-line literal strings** are surrounded by three single quotes on each side and allow newlines. Like literal strings, there is no escaping whatsoever. A newline immediately following the opening delimiter will be trimmed. All other content between the delimiters is interpreted as-is without modification. 218 | 219 | ```yaml 220 | regex2: '''I [dw]on't need \d{2} apples''' 221 | lines: ''' 222 | The first newline is 223 | trimmed in raw strings. 224 | All other whitespace 225 | is preserved. 226 | ''' 227 | ``` 228 | 229 | You can write 1 or 2 single quotes anywhere within a multi-line literal string, but sequences of three or more single quotes are not permitted. 230 | 231 | ```yaml 232 | quot15: '''Here are fifteen quotation marks: """""""""""""""''' 233 | 234 | # apos15: '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID 235 | apos15: "Here are fifteen apostrophes: '''''''''''''''" 236 | 237 | # 'That,' she said, 'is still pointless.' 238 | str: ''''That,' she said, 'is still pointless.'''' 239 | ``` 240 | 241 | Control characters other than tab are not permitted in a literal string. Thus, for binary data, it is recommended that you use Base64 or another suitable ASCII or UTF-8 encoding. The handling of that encoding will be application-specific. 242 | 243 | 244 | ## Integer 245 | 246 | Integers are whole numbers. Positive numbers may be prefixed with a plus sign. Negative numbers are prefixed with a minus sign. 247 | 248 | ```yaml 249 | int1: +99 250 | int2: 42 251 | int3: 0 252 | int4: -17 253 | ``` 254 | 255 | For large numbers, you may use underscores between digits to enhance readability. Each underscore must be surrounded by at least one digit on each side. 256 | 257 | ```yaml 258 | int5: 1_000 259 | int6: 5_349_221 260 | int7: 53_49_221 # Indian number system grouping 261 | ``` 262 | 263 | Leading zeros are not allowed. Integer values `-0` and `+0` are valid and identical to an unprefixed zero. Non-negative integer values may also be expressed in hexadecimal, octal, or binary. In these formats, leading `+` is not allowed and leading zeros are allowed (after the prefix). Hex values are case-insensitive. Underscores are allowed between digits (but not between the prefix and the value). 264 | 265 | ```yaml 266 | # Hexadecimal with prefix `0x` 267 | hex1: 0xDEADBEEF 268 | hex2: 0xdeadbeef 269 | hex3: 0xdead_beef 270 | 271 | # Octal with prefix `0o` 272 | oct1: 0o01234567 273 | oct2: 0o755 # useful for Unix file permissions 274 | 275 | # Binary with prefix `0b` 276 | bin1: 0b11010110 277 | ``` 278 | 279 | Arbitrary 64-bit signed integers (from −2^63 to 2^63−1) should be accepted and handled losslessly. If an integer cannot be represented losslessly, an error must be thrown. 280 | 281 | 282 | ## Float 283 | 284 | Floats should be implemented as IEEE 754 binary64 values. 285 | 286 | A float consists of an integer part (which follows the same rules as decimal integer values) followed by a fractional part and/or an exponent part. If both a fractional part and exponent part are present, the fractional part must precede the exponent part. 287 | 288 | ```yaml 289 | # Fractional 290 | flt1: +1.0 291 | flt2: 3.1415 292 | flt3: -0.01 293 | 294 | # Exponent 295 | flt4: 5e+22 296 | flt5: 1e06 297 | flt6: -2E-2 298 | 299 | # Both 300 | flt7: 6.626e-34 301 | ``` 302 | 303 | A fractional part is a decimal point followed by one or more digits. 304 | 305 | An exponent part is an E (upper or lower case) followed by an integer part (which follows the same rules as decimal integer values but may include leading zeros). 306 | 307 | The decimal point, if used, must be surrounded by at least one digit on each side. 308 | 309 | ```yaml 310 | # INVALID FLOATS 311 | invalid_float_1: .7 312 | invalid_float_2: 7. 313 | invalid_float_3: 3.e+20 314 | ``` 315 | 316 | Similar to integers, you may use underscores to enhance readability. 317 | 318 | ```yaml 319 | flt8: 224_617.445_991_228 320 | ``` 321 | 322 | Float values `-0.0` and `+0.0` are valid and should map according to IEEE 754. 323 | 324 | Special float values can also be expressed. They are always lowercase. 325 | 326 | ```yaml 327 | # Infinity 328 | sf1: inf # Positive infinity 329 | sf2: +inf # Positive infinity 330 | sf3: -inf # Negative infinity 331 | 332 | # Not a number 333 | sf4: nan # Actual sNaN/qNaN encoding is implementation-specific 334 | sf5: +nan # Same as `nan` 335 | sf6: -nan # Valid, actual encoding is implementation-specific 336 | ``` 337 | 338 | 339 | ## Boolean 340 | 341 | Booleans are just the tokens you're used to. Always lowercase. 342 | 343 | ```yaml 344 | bool1: true 345 | bool2: false 346 | ``` 347 | 348 | 349 | ## Object 350 | 351 | Like YAML, objects have a header (key), a colon and underneath each of their attributes, which must begin in an indented block. This indentation must be respected throughout the entire Gura file and each indentation level must be represented by 4 (four) spaces (U+0020). Unlike YAML, tabs (U+0009) are not allowed to define indentation blocks in order to standardize language formatting and provide users with a convenient way to maintain documents. 352 | 353 | 354 | ```yaml 355 | services: 356 | nginx: 357 | host: "127.0.0.1" 358 | port: 80 359 | 360 | apache: 361 | virtual_host: "10.10.10.4" 362 | port: 81 363 | ``` 364 | 365 | The equivalent JSON would be: 366 | 367 | ```json 368 | { 369 | "services": { 370 | "nginx": { 371 | "host": "127.0.0.1", 372 | "port": 80 373 | }, 374 | "apache": { 375 | "virtual_host": "10.10.10.4", 376 | "port": 81 377 | } 378 | } 379 | } 380 | ``` 381 | 382 | **Some considerations about the indentation** 383 | 384 | A space (U+0020) or a tab (U+0009) can be used on useless lines like comments o empty lines (lines composed of whitespaces and new lines) but only. In case a tab is found as an indentation character, an `InvalidIndentationError` must be raised. 385 | 386 | Also, as mentioned previously, the indentation levels must be divisible by 4, otherwise an `InvalidIndentationError` error must be raised: 387 | 388 | ```yaml 389 | # INVALID as second level has block of 8 spaces as indentation 390 | services: 391 | nginx: 392 | host: "127.0.0.1" 393 | port: 80 394 | 395 | # INVALID as 2 spaces are used as indentation block 396 | user: 397 | name: "Gura" 398 | ``` 399 | 400 | Finally, as empty values are not allowed, the following case considers any value below `name` as an internal block. As the indentation length between parent and child blocks is the same an `InvalidIndentationError` exception will be thrown: 401 | 402 | ```yaml 403 | user: 404 | name: # INVALID 405 | surname: "Troilo" 406 | ``` 407 | 408 | **Empty objects** 409 | 410 | While the idea is that the configuration of a system is valid, complete, and static information, there may be situations where the information is empty. Assume the following case in JSON: 411 | 412 | ```json 413 | { 414 | "empty_object": {} 415 | } 416 | ``` 417 | 418 | To maintain compatibility with existing languages with support for empty objects such as JSON or YAML, Gura provides the `empty` keyword to cover these scenarios. The above example could be represented in Gura as follows: 419 | 420 | ```yaml 421 | empty_object: empty 422 | ``` 423 | 424 | In this way, an explicit and clear syntax is provided to cover these rare cases, without losing the portability of the configuration to and from other languages. 425 | 426 | 427 | ## Array 428 | 429 | Arrays are square brackets with values inside. Whitespace is ignored. Elements are separated by commas. Arrays can contain values of the same data types as allowed in key/value pairs. Values of different types may be mixed. 430 | 431 | ```yaml 432 | integers: [ 1, 2, 3 ] 433 | colors: [ "red", "yellow", "green" ] 434 | nested_arrays_of_ints: [ [ 1, 2 ], [3, 4, 5] ] 435 | nested_mixed_array: [ [ 1, 2 ], ["a", "b", "c"] ] 436 | 437 | # Mixed-type arrays are allowed 438 | numbers: [ 0.1, 0.2, 0.5, 1, 2, 5 ] 439 | tango_singers: [ 440 | user1: 441 | name: "Carlos" 442 | surname: "Gardel" 443 | year_of_birth: 1890, 444 | 445 | user2: 446 | name: "Aníbal" 447 | surname: "Troilo" 448 | year_of_birth: 1914 449 | ] 450 | ``` 451 | 452 | Arrays can span multiple lines. A terminating comma (also called a trailing comma) is permitted after the last value of the array. Any number of newlines and comments may precede values, commas, and the closing bracket. Indentation between array values and commas is treated as whitespace and ignored. 453 | 454 | ```yaml 455 | integers2: [ 456 | 1, 2, 3 457 | ] 458 | 459 | integers3: [ 460 | 1, 461 | 2, # This is ok 462 | ] 463 | ``` 464 | 465 | Since the comma is the only valid element separator for an array, it is recommended to add a line between elements that are objects or multiple key/values to improve legibility: 466 | 467 | ```yaml 468 | # It is valid but a little hard to read 469 | singers: [ 470 | name: "Andrea" 471 | surname: "Bocelli" 472 | gender: "Opera", 473 | name: "Jimi" 474 | surname: "Hendrix" 475 | gender: "Rock" 476 | ] 477 | 478 | # Much better! 479 | singers: [ 480 | name: "Andrea" 481 | surname: "Bocelli" 482 | gender: "Opera", 483 | 484 | name: "Jimi" 485 | surname: "Hendrix" 486 | gender: "Rock" 487 | ] 488 | ``` 489 | 490 | 491 | ## Variables 492 | 493 | You can define variables. They start with a `$` sign, a name and a colon. A variable name has to respect the same regex as keys, and only basic types (null, strings, booleans, numbers, and `empty`) or another variable are allowed as values. If another value type is used, a parsing error must be raised. 494 | 495 | ```yaml 496 | $my_string_var: "127.0.0.1" 497 | $my_integer_var: 8080 498 | $my_bool_var: true 499 | 500 | nginx: 501 | host: $my_string_var 502 | port: $my_integer_var 503 | ignore_warning: $my_bool_var 504 | 505 | $invalid_var: [ 1, 2, 3 ] # INVALID complex types such as arrays or objects are not allowed as variable value 506 | 507 | # INVALID complex types such as arrays or objects are not allowed as variable value 508 | $invalid_var_2: service: 509 | name: "Service name" 510 | ``` 511 | 512 | Variables can not be used as key. 513 | 514 | ```yaml 515 | $hostkey: "host" 516 | nginx: 517 | $hostkey : 4 # INVALID 518 | ``` 519 | 520 | Variables must be specified before they are used, in source code order. Redefining variables must raise a `DuplicatedVariableError` error, even when defined in different files (see [imports](#imports)). 521 | 522 | Variables can be used in *Basic strings* and *Multi-line basic strings*: 523 | 524 | ```yaml 525 | $name: "Gura" 526 | key: "$name is cool" 527 | key_2: """Config languages using variables: 528 | - $name""" 529 | ``` 530 | 531 | **Environment variables** can be accessed using `$` sign too. 532 | 533 | ```yaml 534 | service: 535 | postgres: 536 | environment: 537 | user: $DB_USER 538 | password: $DB_PASS 539 | 540 | # You can store its value in a variable too 541 | $my_path: $PATH 542 | 543 | # You can replace environment variables like normal ones. After all, environment variables are normal variables defined before parsing. 544 | $PATH: "Another value" 545 | ``` 546 | 547 | When a variable is used Gura looks for the definition in the current file and the imported ones. If it is not defined, checks for available environment variables, if it is not defined either, it must raise a `VariableNotDefinedError` error. 548 | 549 | To avoid security issues accessing environments variables in sensitive systems, each implementation must provide an ENV vars disabling mechanism. If they are disabled, only local variables will be considered, if not found the `VariableNotDefinedError` exception will be thrown. 550 | 551 | To use `$` in string just use literal or escape them: 552 | 553 | 554 | ```yaml 555 | basic: "I won \$500 dollars!" 556 | basic_multiline: """I won \$500 dollars!""" 557 | literal: 'I won $500 dollars!' 558 | literal_multiline: '''I won $500 dollars!''' 559 | ``` 560 | 561 | 562 | ## Imports 563 | 564 | You can import one or more Gura files using an `import` statement. The effect of importing a file is the same as replacing the import by the file's contents. Therefore, all the keys and variables defined on them will be available in the file which is importing. 565 | 566 | Imports must occur at the beginning of the file and there must be no blanks in front of the `import` statement. Must be only one whitespace between the `import` and file name. The file name must be between single quotation marks (") and there won't be special character escaping. Importing a non-existing file must raise a `FileNotFoundError` error. 567 | 568 | ```yaml 569 | import "another_file.ura" # Good 570 | import "another_file.ura" # INVALID: there are blanks before import 571 | import "another_file.ura" # INVALID: there are more than one whitespace between import and file name 572 | 573 | some_key: "Some value" 574 | 575 | import "another_file.ura" # INVALID: is not at the beginning of the file 576 | ``` 577 | 578 | A file can only be imported once. Re-importing a file must raise a `DuplicatedImportError` error. 579 | 580 | 581 | **one.ura**: 582 | 583 | ```yaml 584 | life: 42 585 | ``` 586 | 587 | **two.ura**: 588 | 589 | ```yaml 590 | import "one.ura" 591 | 592 | $my_var: "My var value" 593 | ``` 594 | 595 | **three.ura**: 596 | 597 | ```yaml 598 | $name: "Elisa" 599 | ``` 600 | 601 | **main.ura**: 602 | 603 | ```yaml 604 | import "two.ura" 605 | import "/absolute/path/to/three.ura" # You can use absolute path too 606 | 607 | # life, $my_var and $name are available here 608 | my_name: $name 609 | 610 | # life: "some value" # This WILL NOT work as it is defined in one.ura which is included in two.ura 611 | ``` 612 | 613 | You can use variables inside import sentences! 614 | 615 | ```yaml 616 | $common_path: "/extremely/long/path/to/some/useful/directory" 617 | 618 | import "$common_path/one.ura" 619 | import "$common_path/two.ura" 620 | ``` 621 | 622 | To avoid errors in environments without filesystem access, prevent security problems in sensitive environments, or whatever the reason, each implementation must provide an import disabling mechanism. This flag must be part of the process of parsing a text string in Gura format to a structure useful for the implementation (e.g. a dictionary in Python, an object in Javascript, a HashMap in Java and Rust, etc). 623 | 624 | In case the user sets this flag to `true` it should not be possible to import Gura files into one, and any `import` statement encountered should throw `ImportDisabledError`. 625 | 626 | This gives more control to the users to use Gura in the most efficient way for their requirements. 627 | --------------------------------------------------------------------------------