├── .0pdd.yml
├── .gitattributes
├── .github
└── workflows
│ ├── actionlint.yml
│ ├── codecov.yml
│ ├── copyrights.yml
│ ├── jekyll.yml
│ ├── markdown-lint.yml
│ ├── mvn.yml
│ ├── ort.yml
│ ├── pdd.yml
│ ├── python-flake8-lint.yml
│ ├── reuse.yml
│ ├── typos.yml
│ ├── xcop.yml
│ └── yamllint.yml
├── .gitignore
├── .pdd
├── .rultor.yml
├── CITATION.cff
├── LICENSE.txt
├── LICENSES
└── MIT.txt
├── README.md
├── REUSE.toml
├── jekyll
├── 404.md
├── CNAME
├── Gemfile
├── LICENSE.txt
├── README.md
├── _config.yml
├── _layouts
│ ├── default.html
│ └── static.html
├── _posts
│ └── 2014
│ │ ├── jun
│ │ ├── 2014-06-01-example-facebook.md
│ │ ├── 2014-06-22-typical-mistakes.md
│ │ ├── 2014-06-30-requs-in-command-line.md
│ │ └── 2014-06-30-requs-in-maven-build.md
│ │ └── may
│ │ ├── 2014-05-01-syntax.md
│ │ ├── 2014-05-10-feature-attributes.md
│ │ ├── 2014-05-15-feature-nfrs.md
│ │ └── 2014-05-20-feature-types.md
├── _sass
│ ├── _colors.scss
│ └── _highlight.scss
├── css
│ └── layout.scss
├── images
│ ├── fork-me.svg
│ ├── ico-64x64.png
│ └── logo.svg
├── index.md
└── robots.txt
├── logo.svg
├── pom.xml
├── renovate.json
├── requs-core
├── LICENSE.txt
├── pom.xml
└── src
│ ├── main
│ ├── antlr4
│ │ └── org
│ │ │ └── requs
│ │ │ └── facet
│ │ │ └── syntax
│ │ │ └── Spec.g4
│ ├── java
│ │ └── org
│ │ │ └── requs
│ │ │ ├── Compiler.java
│ │ │ ├── Facet.java
│ │ │ ├── XeFacet.java
│ │ │ ├── facet
│ │ │ ├── Aggregate.java
│ │ │ ├── Transform.java
│ │ │ ├── XsltFuncs.java
│ │ │ ├── package-info.java
│ │ │ ├── sa
│ │ │ │ ├── CascadingRule.java
│ │ │ │ ├── IndentationRule.java
│ │ │ │ ├── LineRule.java
│ │ │ │ ├── RegexRule.java
│ │ │ │ ├── Rule.java
│ │ │ │ ├── Rules.java
│ │ │ │ ├── Violation.java
│ │ │ │ └── package-info.java
│ │ │ ├── syntax
│ │ │ │ ├── AntlrFacet.java
│ │ │ │ ├── Errors.java
│ │ │ │ ├── SyntaxException.java
│ │ │ │ ├── ontology
│ │ │ │ │ ├── Acronym.java
│ │ │ │ │ ├── Flow.java
│ │ │ │ │ ├── Informal.java
│ │ │ │ │ ├── Mentioned.java
│ │ │ │ │ ├── Method.java
│ │ │ │ │ ├── Nfr.java
│ │ │ │ │ ├── Ontology.java
│ │ │ │ │ ├── Page.java
│ │ │ │ │ ├── Signature.java
│ │ │ │ │ ├── Slot.java
│ │ │ │ │ ├── Step.java
│ │ │ │ │ ├── Type.java
│ │ │ │ │ ├── XeAcronym.java
│ │ │ │ │ ├── XeFlow.java
│ │ │ │ │ ├── XeInformal.java
│ │ │ │ │ ├── XeMentioned.java
│ │ │ │ │ ├── XeMethod.java
│ │ │ │ │ ├── XeNfr.java
│ │ │ │ │ ├── XeOntology.java
│ │ │ │ │ ├── XePage.java
│ │ │ │ │ ├── XeSignature.java
│ │ │ │ │ ├── XeSlot.java
│ │ │ │ │ ├── XeStep.java
│ │ │ │ │ ├── XeType.java
│ │ │ │ │ └── package-info.java
│ │ │ │ └── package-info.java
│ │ │ └── uml
│ │ │ │ ├── Plant.java
│ │ │ │ └── package-info.java
│ │ │ └── package-info.java
│ ├── resources
│ │ └── org
│ │ │ └── requs
│ │ │ ├── facet
│ │ │ ├── cleanup
│ │ │ │ ├── bindings-in-exception.xsl
│ │ │ │ ├── duplicate-method-bindings.xsl
│ │ │ │ ├── duplicate-method-objects.xsl
│ │ │ │ ├── duplicate-method-signatures.xsl
│ │ │ │ ├── duplicate-signatures.xsl
│ │ │ │ ├── duplicate-step-numbers.xsl
│ │ │ │ ├── duplicate-step-objects.xsl
│ │ │ │ ├── duplicate-step-results.xsl
│ │ │ │ ├── duplicate-step-signatures.xsl
│ │ │ │ ├── incomplete-binding.xsl
│ │ │ │ ├── incomplete-step-object.xsl
│ │ │ │ ├── incomplete-step-result.xsl
│ │ │ │ ├── incomplete-step-signature.xsl
│ │ │ │ ├── lost-methods.xsl
│ │ │ │ └── lost-steps.xsl
│ │ │ ├── count-ambiguity.xsl
│ │ │ ├── find-tbds.xsl
│ │ │ ├── methods-in-markdown.xsl
│ │ │ ├── pages-in-html.xsl
│ │ │ ├── renumber.xsl
│ │ │ ├── sanity
│ │ │ │ ├── actor-is-singleton.xsl
│ │ │ │ ├── broken-order-of-steps.xsl
│ │ │ │ ├── empty-re-throws.xsl
│ │ │ │ ├── exception-rethrow-check.xsl
│ │ │ │ ├── misplaced-failure-check.xsl
│ │ │ │ ├── missed-step-numbers.xsl
│ │ │ │ ├── orphan-types.xsl
│ │ │ │ ├── seals-check.xsl
│ │ │ │ ├── signatures-check.xsl
│ │ │ │ ├── too-many-steps.xsl
│ │ │ │ ├── types-check.xsl
│ │ │ │ └── undeclared-bindings.xsl
│ │ │ ├── seal-methods.xsl
│ │ │ ├── step-refs.xsl
│ │ │ └── uml
│ │ │ │ ├── class-diagrams.xsl
│ │ │ │ ├── functions.xsl
│ │ │ │ ├── sequence-diagrams.xsl
│ │ │ │ └── use-case-diagrams.xsl
│ │ │ └── requs.xsd
│ ├── scss
│ │ └── requs.scss
│ └── xsl
│ │ └── requs.xsl
│ └── test
│ ├── java
│ └── org
│ │ └── requs
│ │ ├── CompilerTest.java
│ │ ├── facet
│ │ ├── TransformTest.java
│ │ ├── package-info.java
│ │ ├── sa
│ │ │ ├── CascadingRuleTest.java
│ │ │ ├── IndentationRuleTest.java
│ │ │ ├── LineRuleTest.java
│ │ │ ├── RegexRuleTest.java
│ │ │ ├── RulesTest.java
│ │ │ └── package-info.java
│ │ ├── syntax
│ │ │ ├── AntlrFacetTest.java
│ │ │ ├── ontology
│ │ │ │ ├── XeFlowTest.java
│ │ │ │ ├── XeMethodTest.java
│ │ │ │ ├── XeOntologyTest.java
│ │ │ │ ├── XeSignatureTest.java
│ │ │ │ ├── XeSlotTest.java
│ │ │ │ ├── XeStepTest.java
│ │ │ │ ├── XeTypeTest.java
│ │ │ │ └── package-info.java
│ │ │ └── package-info.java
│ │ └── uml
│ │ │ ├── PlantTest.java
│ │ │ └── package-info.java
│ │ └── package-info.java
│ └── resources
│ ├── META-INF
│ └── MANIFEST.MF
│ ├── log4j.properties
│ └── org
│ └── requs
│ ├── facet
│ └── syntax
│ │ ├── all-cases.req
│ │ ├── example.req
│ │ ├── samples
│ │ ├── all-possible-mistakes.xml
│ │ ├── informals.xml
│ │ ├── method.xml
│ │ ├── nfr.xml
│ │ ├── pages.xml
│ │ └── types.xml
│ │ └── test-srs.xml
│ └── samples
│ ├── all-possible-constructs.xml
│ ├── all-possible-mistakes.xml
│ ├── clean-spec.xml
│ ├── empty-input.xml
│ ├── exceptions.xml
│ ├── order-of-steps.xml
│ └── wrong-steps-numbering.xml
├── requs-exec
├── LICENSE.txt
├── pom.xml
└── src
│ ├── it
│ ├── compiles-simple-syntax
│ │ ├── invoker.properties
│ │ ├── pom.xml
│ │ ├── requs-src
│ │ │ └── input.req
│ │ └── verify.groovy
│ └── settings.xml
│ ├── main
│ ├── assembly
│ │ └── bin.xml
│ ├── java
│ │ └── org
│ │ │ └── requs
│ │ │ └── exec
│ │ │ ├── Main.java
│ │ │ └── package-info.java
│ └── resources
│ │ └── log4j.properties
│ └── test
│ ├── java
│ └── org
│ │ └── requs
│ │ └── exec
│ │ ├── MainTest.java
│ │ └── package-info.java
│ └── resources
│ ├── META-INF
│ └── MANIFEST.MF
│ └── log4j.properties
├── requs-maven-plugin
├── LICENSE.txt
├── pom.xml
└── src
│ ├── it
│ ├── absent-input-dir
│ │ ├── invoker.properties
│ │ └── pom.xml
│ ├── broken-spec
│ │ ├── invoker.properties
│ │ ├── pom.xml
│ │ ├── src
│ │ │ └── main
│ │ │ │ └── requs
│ │ │ │ └── input.req
│ │ └── verify.groovy
│ ├── report-in-site
│ │ ├── invoker.properties
│ │ ├── pom.xml
│ │ ├── src
│ │ │ └── main
│ │ │ │ └── requs
│ │ │ │ └── input.req
│ │ └── verify.groovy
│ ├── settings.xml
│ └── simple-compile
│ │ ├── invoker.properties
│ │ ├── pom.xml
│ │ ├── src
│ │ └── main
│ │ │ └── requs
│ │ │ └── input.req
│ │ └── verify.groovy
│ ├── main
│ └── java
│ │ └── org
│ │ └── requs
│ │ └── maven
│ │ ├── CompileMojo.java
│ │ ├── ReportMojo.java
│ │ └── package-info.java
│ └── test
│ └── java
│ └── org
│ └── requs
│ └── maven
│ ├── CompileMojoTest.java
│ ├── ReportMojoTest.java
│ └── package-info.java
├── requs_pygment
├── .gitignore
├── requs_pygment.py
└── setup.py
└── sdd
├── .gitignore
├── .latexmkrc
├── README.md
├── logo.pdf
├── sdd.bib
├── sdd.pdf
└── sdd.tex
/.0pdd.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | errors:
5 | - yegor256@gmail.com
6 | # alerts:
7 | # github:
8 | # - yegor256
9 |
10 | tags:
11 | - pdd
12 | - bug
13 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Check out all text files in UNIX format, with LF as end of line
2 | # Don't change this file. If you have any ideas about it, please
3 | # submit a separate issue about it and we'll discuss.
4 |
5 | * text=auto eol=lf
6 | *.java ident
7 | *.xml ident
8 |
--------------------------------------------------------------------------------
/.github/workflows/actionlint.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | name: actionlint
6 | 'on':
7 | push:
8 | branches:
9 | - master
10 | pull_request:
11 | branches:
12 | - master
13 | jobs:
14 | actionlint:
15 | timeout-minutes: 15
16 | runs-on: ubuntu-24.04
17 | steps:
18 | - uses: actions/checkout@v4
19 | - name: Download actionlint
20 | id: get_actionlint
21 | run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
22 | shell: bash
23 | - name: Check workflow files
24 | run: ${{ steps.get_actionlint.outputs.executable }} -color
25 | shell: bash
26 |
--------------------------------------------------------------------------------
/.github/workflows/codecov.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | name: codecov
6 | 'on':
7 | push:
8 | branches:
9 | - master
10 | jobs:
11 | codecov:
12 | timeout-minutes: 15
13 | runs-on: ubuntu-24.04
14 | steps:
15 | - uses: actions/checkout@v4
16 | - uses: actions/setup-java@v4
17 | with:
18 | distribution: 'temurin'
19 | java-version: 11
20 | - uses: actions/cache@v3
21 | with:
22 | path: ~/.m2/repository
23 | key: maven-${{ hashFiles('**/pom.xml') }}
24 | restore-keys: |
25 | maven-
26 | - run: mvn install -Pjacoco
27 | - uses: codecov/codecov-action@v5
28 | with:
29 | files: ./target/site/jacoco/jacoco.xml
30 | fail_ci_if_error: true
31 |
--------------------------------------------------------------------------------
/.github/workflows/copyrights.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | name: copyrights
6 | 'on':
7 | push:
8 | branches:
9 | - master
10 | pull_request:
11 | branches:
12 | - master
13 | jobs:
14 | copyrights:
15 | timeout-minutes: 15
16 | runs-on: ubuntu-24.04
17 | steps:
18 | - uses: actions/checkout@v4
19 | - uses: yegor256/copyrights-action@0.0.8
20 |
--------------------------------------------------------------------------------
/.github/workflows/jekyll.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | name: jekyll
6 | 'on':
7 | push:
8 | branches:
9 | - master
10 | paths: 'jekyll/**'
11 | jobs:
12 | jekyll:
13 | timeout-minutes: 15
14 | runs-on: ubuntu-24.04
15 | steps:
16 | - uses: actions/checkout@v4
17 | - uses: actions/cache@v4
18 | with:
19 | path: vendor/bundle
20 | key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
21 | restore-keys: |
22 | ${{ runner.os }}-gems-
23 | - uses: jeffreytse/jekyll-deploy-action@v0.3.1
24 | with:
25 | provider: 'github'
26 | token: ${{ secrets.GITHUB_TOKEN }} # It's your Personal Access Token(PAT)
27 | branch: 'gh-pages' # Default is gh-pages for github provider
28 | jekyll_src: './jekyll' # Default is root directory
29 |
--------------------------------------------------------------------------------
/.github/workflows/markdown-lint.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | name: markdown-lint
6 | 'on':
7 | push:
8 | branches:
9 | - master
10 | pull_request:
11 | branches:
12 | - master
13 | jobs:
14 | markdown-lint:
15 | timeout-minutes: 15
16 | runs-on: ubuntu-24.04
17 | steps:
18 | - uses: actions/checkout@v4
19 | - uses: DavidAnson/markdownlint-cli2-action@v20.0.0
20 |
--------------------------------------------------------------------------------
/.github/workflows/mvn.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | name: mvn
6 | 'on':
7 | push:
8 | branches:
9 | - master
10 | pull_request:
11 | branches:
12 | - master
13 | jobs:
14 | mvn:
15 | timeout-minutes: 15
16 | runs-on: ${{ matrix.os }}
17 | strategy:
18 | matrix:
19 | os: [ubuntu-24.04, windows-2022, macos-15]
20 | java: [11, 17]
21 | steps:
22 | - uses: actions/checkout@v4
23 | - uses: actions/setup-java@v4
24 | with:
25 | distribution: 'temurin'
26 | java-version: ${{ matrix.java }}
27 | - uses: actions/cache@v3
28 | with:
29 | path: ~/.m2/repository
30 | key: ${{ runner.os }}-jdk-${{ matrix.java }}-maven-${{ hashFiles('**/pom.xml') }}
31 | restore-keys: |
32 | ${{ runner.os }}-jdk-${{ matrix.java }}-maven-
33 | - run: java -version
34 | - run: mvn -version
35 | - run: mvn --errors --batch-mode clean install -Pqulice
36 |
--------------------------------------------------------------------------------
/.github/workflows/ort.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025 Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | name: ort
6 | 'on':
7 | push:
8 | branches:
9 | - master
10 | pull_request:
11 | branches:
12 | - master
13 | jobs:
14 | ort:
15 | timeout-minutes: 15
16 | runs-on: ubuntu-24.04
17 | steps:
18 | - uses: actions/checkout@v4
19 | - uses: oss-review-toolkit/ort-ci-github-action@v1
20 | with:
21 | allow-dynamic-versions: 'true'
22 | fail-on: 'violations'
23 |
--------------------------------------------------------------------------------
/.github/workflows/pdd.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | name: pdd
6 | 'on':
7 | push:
8 | branches:
9 | - master
10 | pull_request:
11 | branches:
12 | - master
13 | jobs:
14 | pdd:
15 | timeout-minutes: 15
16 | runs-on: ubuntu-24.04
17 | steps:
18 | - uses: actions/checkout@v4
19 | - uses: g4s8/pdd-action@master
20 |
--------------------------------------------------------------------------------
/.github/workflows/python-flake8-lint.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | name: Python-Flake8-Linter
6 |
7 | 'on':
8 | push:
9 | branches:
10 | - master
11 | pull_request:
12 | branches:
13 | - master
14 |
15 | jobs:
16 | flake8:
17 | timeout-minutes: 15
18 | runs-on: ubuntu-24.04
19 | steps:
20 | - name: Checkout code
21 | uses: actions/checkout@v4
22 | - name: Set up Python
23 | uses: actions/setup-python@v5
24 | with:
25 | python-version: 3.11
26 | - name: Install dependencies
27 | run: pip install flake8
28 | - name: Run Flake8
29 | run: |
30 | flake8 --max-line-length=120 .
31 |
--------------------------------------------------------------------------------
/.github/workflows/reuse.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | name: reuse
6 | 'on':
7 | push:
8 | branches:
9 | - master
10 | pull_request:
11 | branches:
12 | - master
13 | jobs:
14 | reuse:
15 | timeout-minutes: 15
16 | runs-on: ubuntu-24.04
17 | steps:
18 | - uses: actions/checkout@v4
19 | - uses: fsfe/reuse-action@v5
20 |
--------------------------------------------------------------------------------
/.github/workflows/typos.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | name: typos
6 | 'on':
7 | push:
8 | branches:
9 | - master
10 | pull_request:
11 | branches:
12 | - master
13 | jobs:
14 | typos:
15 | timeout-minutes: 15
16 | runs-on: ubuntu-24.04
17 | steps:
18 | - uses: actions/checkout@v4
19 | - uses: crate-ci/typos@v1.32.0
20 |
--------------------------------------------------------------------------------
/.github/workflows/xcop.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | name: xcop
6 | 'on':
7 | push:
8 | branches:
9 | - master
10 | pull_request:
11 | branches:
12 | - master
13 | jobs:
14 | xcop:
15 | timeout-minutes: 15
16 | runs-on: ubuntu-24.04
17 | steps:
18 | - uses: actions/checkout@v4
19 | - uses: g4s8/xcop-action@master
20 |
--------------------------------------------------------------------------------
/.github/workflows/yamllint.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | name: yamllint
6 | 'on':
7 | push:
8 | branches:
9 | - master
10 | pull_request:
11 | branches:
12 | - master
13 | jobs:
14 | yamllint:
15 | timeout-minutes: 15
16 | runs-on: ubuntu-24.04
17 | steps:
18 | - uses: actions/checkout@v4
19 | - uses: ibiqlik/action-yamllint@v3
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | _site/
2 | .DS_Store
3 | .idea/
4 | .jekyll-cache
5 | .sass-cache
6 | *.iml
7 | Gemfile.lock
8 | node_modules/
9 | target/
10 |
--------------------------------------------------------------------------------
/.pdd:
--------------------------------------------------------------------------------
1 | --source=.
2 | --verbose
3 | --exclude=**/target/**/*
4 | --exclude=**/.sass-cache/**/*
5 | --exclude=.idea/**/*
6 | --exclude=**/.jekyll-cache/**/*
7 | --exclude=jekyll/images/**/*
8 | --exclude=src/main/resources/images/**/*
9 | --rule=min-words:20
10 | --rule=min-estimate:15
11 | --rule=max-estimate:90
12 |
--------------------------------------------------------------------------------
/.rultor.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | # yamllint disable rule:line-length
5 | docker:
6 | image: yegor256/rultor-image:1.24.0
7 | readers:
8 | - "urn:github:526301"
9 | assets:
10 | settings.xml: yegor256/home#assets/requs/settings.xml
11 | pubring.gpg: yegor256/home#assets/pubring.gpg
12 | secring.gpg: yegor256/home#assets/secring.gpg
13 | install: |-
14 | pdd -f /dev/null
15 | merge:
16 | script: |-
17 | mvn clean install -Pqulice --errors --settings ../settings.xml
18 | mvn clean site -Psite --settings ../settings.xml
19 | release:
20 | sensitive:
21 | - setting.xml
22 | script: |-
23 | mvn versions:set "-DnewVersion=${tag}"
24 | git commit -am "${tag}"
25 | mvn clean deploy -Pqulice -Psonatype -Prequs --errors --settings ../settings.xml
26 |
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | cff-version: 1.2.0
2 | message: "If you use this software, please cite it as below."
3 | authors:
4 | - family-names: "Bugayenko"
5 | given-names: "Yegor"
6 | orcid: "https://orcid.org/0000-0001-6370-0678"
7 | title: "REQUS: Controlled Natural Language for Requirements Specification"
8 | version: 0.0.0
9 | date-released: 2022-05-09
10 | url: "https://github.com/yegor256/requs"
11 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2009-2025, Yegor Bugayenko
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions
6 | are met: 1) Redistributions of source code must retain the above
7 | copyright notice, this list of conditions and the following
8 | disclaimer. 2) Redistributions in binary form must reproduce the above
9 | copyright notice, this list of conditions and the following
10 | disclaimer in the documentation and/or other materials provided
11 | with the distribution. 3) Neither the name of the requs.org nor
12 | the names of its contributors may be used to endorse or promote
13 | products derived from this software without specific prior written
14 | permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
18 | NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 | THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 | OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/LICENSES/MIT.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2009-2025, Yegor Bugayenko
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions
6 | are met: 1) Redistributions of source code must retain the above
7 | copyright notice, this list of conditions and the following
8 | disclaimer. 2) Redistributions in binary form must reproduce the above
9 | copyright notice, this list of conditions and the following
10 | disclaimer in the documentation and/or other materials provided
11 | with the distribution. 3) Neither the name of the requs.org nor
12 | the names of its contributors may be used to endorse or promote
13 | products derived from this software without specific prior written
14 | permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
18 | NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 | THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 | OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [](https://www.elegantobjects.org)
4 | [](https://www.rultor.com/p/yegor256/requs)
5 | [](https://www.jetbrains.com/idea/)
6 |
7 | [](https://github.com/yegor256/requs/actions/workflows/mvn.yml)
8 | [](https://codecov.io/gh/yegor256/requs)
9 | [](https://www.0pdd.com/p?name=yegor256/requs)
10 | [](https://maven-badges.herokuapp.com/maven-central/org.requs/requs)
11 | [](https://hitsofcode.com/view/github/yegor256/requs)
12 |
13 | REQUS is a controlled natural language (CNL) for requirements specifications.
14 | It is explained in details in [this paper](https://www.yegor256.com/pdf/2021/requs.pdf),
15 | which was published in the
16 | [Proceedings of the 1st ACM SIGPLAN International Workshop on Beyond Code: No Code (BCNC)](https://dl.acm.org/doi/abs/10.1145/3486949.3486963).
17 | More details about REQUS syntax you can find at [www.requs.org](http://www.requs.org/).
18 |
19 | In order to use it in a Java project, just add this plugin to your `pom.xml`
20 | (get the latest version [from here](https://github.com/yegor256/requs/releases)):
21 |
22 | ```xml
23 |
24 |
25 |
26 | org.requs
27 | requs-maven-plugin
28 | ...
29 |
30 |
31 |
32 | ```
33 |
34 | Then, add REQUS files to `src/main/requs` and name them as `main.req`, etc.
35 |
36 | Then, run `mvn clean site` and you will see a report at `target/site/requs`.
37 |
38 | ## How to contribute?
39 |
40 | Fork the repository, make changes, submit a pull request.
41 | We promise to review your changes same day and apply to
42 | the `master` branch, if they look correct.
43 |
44 | Please run Maven build before submitting a pull request:
45 |
46 | ```
47 | $ mvn clean install -Pqulice
48 | ```
49 |
50 | To render the site and edit its pages:
51 |
52 | ```
53 | $ cd jekyll
54 | $ bundle install
55 | $ bundle exec jekyll serve --drafts
56 | ```
57 |
--------------------------------------------------------------------------------
/REUSE.toml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 |
4 | version = 1
5 | [[annotations]]
6 | path = [
7 | ".DS_Store",
8 | ".gitattributes",
9 | ".gitignore",
10 | ".latexmkrc",
11 | ".pdd",
12 | "**.json",
13 | "**.md",
14 | "**.pdf",
15 | "**.png",
16 | "**.req",
17 | "**.svg",
18 | "**.txt",
19 | "**/.DS_Store",
20 | "**/.gitignore",
21 | "**/.latexmkrc",
22 | "**/.pdd",
23 | "**/*.csv",
24 | "**/*.jpg",
25 | "**/*.json",
26 | "**/*.md",
27 | "**/*.pdf",
28 | "**/*.png",
29 | "**/*.svg",
30 | "**/*.txt",
31 | "**/*.vm",
32 | "**/CITATION.cff",
33 | "**/CNAME",
34 | "**/MANIFEST.MF",
35 | "CITATION.cff",
36 | "CNAME",
37 | "MANIFEST.MF",
38 | "README.md",
39 | "renovate.json",
40 | ]
41 | precedence = "override"
42 | SPDX-FileCopyrightText = "Copyright (c) 2025 Yegor Bugayenko"
43 | SPDX-License-Identifier = "MIT"
44 |
--------------------------------------------------------------------------------
/jekyll/404.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: "Page Not Found"
4 | date: 2014-06-22
5 | description:
6 | Page Not Found
7 | ---
8 |
9 | Perhaps the link you have is expired. Try to start
10 | from [home](/).
11 |
--------------------------------------------------------------------------------
/jekyll/CNAME:
--------------------------------------------------------------------------------
1 | www.requs.org
2 |
--------------------------------------------------------------------------------
/jekyll/Gemfile:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 |
4 | #
5 | # Just run "bundle"
6 | #
7 | source 'https://rubygems.org'
8 |
9 | gem 'jekyll', '4.0.1'
10 | gem 'jekyll-sass', '1.1.0'
11 | gem 'jekyll-sass-converter', '2.1.0'
12 |
--------------------------------------------------------------------------------
/jekyll/LICENSE.txt:
--------------------------------------------------------------------------------
1 | requs
2 |
3 | This source file is subject to the new BSD license that is bundled
4 | with this package in the file LICENSE.txt. It is also available
5 | through the world-wide-web at this URL: http://www.requs.org/LICENSE.txt
6 | If you did not receive a copy of the license and are unable to
7 | obtain it through the world-wide-web, please send an email
8 | to license@requs.org so we can send you a copy immediately.
9 |
10 | Copyright (c) 2009-2025, requs.org
11 | All rights reserved.
12 |
13 | Redistribution and use in source and binary forms, with or
14 | without modification, are permitted provided that the following
15 | conditions are met:
16 |
17 | * Redistributions of source code must retain the above
18 | copyright notice, this list of conditions and the following
19 | disclaimer.
20 |
21 | * Redistributions in binary form must reproduce the above
22 | copyright notice, this list of conditions and the following
23 | disclaimer in the documentation and/or other materials
24 | provided with the distribution.
25 |
26 | * Neither the name of requs.org, Inc. nor the names of its
27 | contributors may be used to endorse or promote products derived
28 | from this software without specific prior written permission.
29 |
30 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
33 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
34 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
35 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
36 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
37 | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
38 | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
39 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
40 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
41 | OF SUCH DAMAGE.
42 |
--------------------------------------------------------------------------------
/jekyll/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/yegor256/requs/actions/workflows/jekyll.yml)
2 |
3 | This directory contains Jekyll sources for the site you see
4 | at [www.requs.org](https://www.requs.org).
5 |
6 | They are built by GitHub actions and deployed automatically every time
7 | you push anything to this directory.
8 |
--------------------------------------------------------------------------------
/jekyll/_config.yml:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 | ---
4 | name: requs.org
5 | markdown: kramdown
6 | highlighter: pygments
7 | permalink: :title.html
8 |
9 | # see https://github.com/noct/jekyll-sass
10 | gems: ['jekyll-sass']
11 | sass:
12 | style: compressed
13 | deploy_style: compressed
14 | compile_in_place: false
15 |
16 | # see https://github.com/kinnetica/jekyll-plugins
17 | sitemap:
18 | file: "/sitemap.xml"
19 | exclude:
20 | - "/rss.xml"
21 | include_posts:
22 | - "/index.html"
23 | change_frequency_name: "change_frequence"
24 | priority_name: "priority"
25 |
--------------------------------------------------------------------------------
/jekyll/_layouts/default.html:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | {{ page.title }}
19 |
20 |
36 |
37 |
38 |
39 |
41 |
42 |
43 |
50 |
{{ page.title }}
51 | {{ content }}
52 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/jekyll/_layouts/static.html:
--------------------------------------------------------------------------------
1 | ---
2 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | # SPDX-License-Identifier: MIT
4 |
5 | layout: default
6 | ---
7 |
8 |
9 |
10 |
11 | {{ page.title }}
12 |
13 |
14 |
15 | {{ content }}
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/jekyll/_posts/2014/jun/2014-06-01-example-facebook.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: "Facebook SRS, Example"
4 | date: 2014-06-01
5 | description:
6 | Requs is a controlled natural language (CNL) for
7 | software requirements specification
8 | categories: blog
9 | ---
10 |
11 | This is an example SRS of Facebook, in
12 | [Requs syntax](./syntax.html):
13 |
14 | {% highlight requs %}
15 | User is "a human being".
16 | User has: email, password, name.
17 |
18 | UC1 where User (a user) socializes:
19 | 1. The user identifies himself;
20 | 2. The user invites User (a user);
21 | 3. The user accepts Invitation (an invite);
22 | 4. The user publishes StatusUpdate (an update);
23 | 5. The user scrolls Timeline (a timeline).
24 |
25 | StatusUpdate is "a text/image/video information posted by a user".
26 | StatusUpdate contains: text, date, author as User.
27 |
28 | Timeline is a "list of status updates from user friends".
29 | Timeline contains: update-s as StatusUpdate.
30 |
31 | Invitation is a "request to become a friend sent from one user to another".
32 | Invitation has: author as User and friend as User.
33 |
34 | UC2 where User identifies himself:
35 | "The user enters his email and password, if he has them. Otherwise,
36 | he registers in the system first, providing his email, full
37 | name, password, and phone number".
38 |
39 | UC3 where User (a user) invites User (a friend):
40 | 1. The user reads the friend
41 | "finding him in a list of all registered users";
42 | 2. The user creates the invitation.
43 | UC3/2 when "the user is banned by the friend":
44 | 1. Fail as "the user is not allowed to invite this friend".
45 |
46 | UC4 where User (a user) accepts Invitation (an invitation):
47 | 1. The user reads the invitation;
48 | 2. "User bans a requester, making impossible any more invitations from him";
49 | 3. The user updates the invitation
50 | "adding the friend to his list of friends".
51 |
52 | UC5 where User (a user) publishes StatusUpdate (an update):
53 | 1. The user creates the update
54 | "and it automatically gets added to his Timeline".
55 |
56 | UC6 where User (a user) scrolls Timeline:
57 | "The user lists all status updates created by his
58 | friends in a reversive chronological order".
59 |
60 | UC1/UI must "be responsive, adapting itself to the width of device".
61 |
62 | UC1/PERF must "guarantee a delivery of any HTTP response
63 | in less than 1 second, with standard equipment and normal
64 | load of the system".
65 |
66 | UC1/SCALE must "handle any number (up to a billion) of users without
67 | performance degrading".
68 | {% endhighlight %}
69 |
--------------------------------------------------------------------------------
/jekyll/_posts/2014/jun/2014-06-30-requs-in-command-line.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: "Requirements Compilation in Command Line"
4 | date: 2014-06-30
5 | description:
6 | Requs can be used in command line for automated
7 | requirements compilation
8 | categories: blog
9 | ---
10 |
11 | First, download the latest `requs-exec.jar` from
12 | [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22requs-exec%22).
13 |
14 | Then, run it like this:
15 |
16 | {% highlight bash %}
17 | $ java -jar requs-exec.jar -i -o
18 | {% endhighlight %}
19 |
20 | `input` is an absolute path of directory with `.req` files.
21 |
22 | `output` is a directory path where result files will be stored.
23 |
24 | That's it.
25 |
--------------------------------------------------------------------------------
/jekyll/_posts/2014/jun/2014-06-30-requs-in-maven-build.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: "Requirements Compilation in Maven Build"
4 | date: 2014-06-30
5 | description:
6 | Requs can be used in Maven build for automated
7 | requirements compilation
8 | categories: blog
9 | ---
10 |
11 | Add this plugin to your Maven build
12 | (get their versions from [Maven Central](http://search.maven.org/)):
13 |
14 | {% highlight xml %}
15 |
16 |
17 |
18 | org.requs
19 | requs-maven-plugin
20 |
21 |
22 |
23 | compile
24 |
25 |
26 |
27 |
28 |
29 | maven-site-plugin
30 |
31 |
32 |
33 | org.requs
34 | requs-maven-plugin
35 |
36 |
37 |
38 | default
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | {% endhighlight %}
49 |
50 | On every run of `compile` phase Requs compiler will
51 | generate its output files in `target/requs`.
52 |
53 | On every run of `site` phase you will get the same files
54 | in `target/site/requs` directory.
55 |
56 | Keep your source files in `src/requs` with `.req` extension. All
57 | of them will be picked up by Requs compiler, recursively searching
58 | in all sub-directories.
59 |
60 | ## Extra Configuration
61 |
62 | You can add extra configuration parameters to be passed
63 | into Requs compiler, using `options` element:
64 |
65 | {% highlight xml %}
66 |
67 |
68 |
69 | org.requs
70 | requs-maven-plugin
71 |
72 |
73 | hello, world!
74 |
75 |
76 |
77 |
78 |
79 | {% endhighlight %}
80 |
81 | All options are passed to the
82 | [`Compiler`](/requs-core/apidoc-1.13/org/requs/Compiler.html)
83 | class as a map of strings.
84 |
--------------------------------------------------------------------------------
/jekyll/_posts/2014/may/2014-05-15-feature-nfrs.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: "Non-Functional Requirements"
4 | date: 2014-05-15
5 | description:
6 | Requs is a controlled natural language (CNL) for
7 | software requirements specification
8 | categories: blog
9 | ---
10 |
11 | Any method (use case) may have an unlimited number of non-functional
12 | requirements (NFRs). They are sometimes called "qualities of service". Wikipedia
13 | has [a list of possible NFRs](http://en.wikipedia.org/wiki/Non-functional_requirement).
14 |
15 | Requs allows NFRs be related only to methods (functional requirements).
16 | In other words, you can't say that your entire product should be "scalable".
17 | Or that it has to be multi-language. Or that its mean time between failure
18 | is more than 24 hours.
19 |
20 | You should always relate such non-functional attributes to specific
21 | functionalities. There is a reason behind this restriction - we want
22 | NFRs to be testable. If they are testable - there is a tester. If there
23 | is a tester - there is some functionality. If there is a functionality -
24 | it has to be documented as a method (use case).
25 |
26 | The syntax is simple:
27 |
28 | {% highlight requs %}
29 | UC3.2/MTBF must "be 5 minutes on a standard equipment".
30 | UC7/PERF must "be less than 500 msec per request".
31 | UC8/UI must "speak English and Spanish".
32 | UC9.5.5/PERF must be "less than 100 milliseconds per HTTP request".
33 | {% endhighlight %}
34 |
35 | In the future vesions of Requs we may have more formal
36 | syntax for NFRs.
37 |
--------------------------------------------------------------------------------
/jekyll/_posts/2014/may/2014-05-20-feature-types.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: "Types"
4 | date: 2014-05-20
5 | description:
6 | Requs is a controlled natural language (CNL) for
7 | software requirements specification
8 | categories: blog
9 | ---
10 |
11 | Type in Requs is a creature similar to a class in
12 | [object-oriented programming](http://en.wikipedia.org/wiki/Object-oriented_programming).
13 | Type has slots and parent types:
14 |
15 | {% highlight requs %}
16 | Image is File.
17 | Image has:
18 | width as "pixels",
19 | height as "pixels", and
20 | format as "PNG, GIF, JPEG, etc".
21 | {% endhighlight %}
22 |
23 | Type names are in [CamelCase Notation](http://en.wikipedia.org/wiki/CamelCase).
24 | For example, these words are valid type names:
25 | `Image`, `ImageFile`, `ImageInCustomFormat`,
26 | `GIFImage`, `PNG`.
27 |
28 | ## Slots
29 |
30 | A type may have a number of slots. A slot is something similar
31 | to a private property of a Java class, for example. The syntax is simple,
32 | in [BNF](http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form):
33 |
34 | {% highlight text %}
35 | ::= ( "has" | "needs" | "requires" | "includes" ) ":" "."
36 | ::= ( ( "," | ";" | "and" ) )*
37 | ::= ( "as" )?
38 | {% endhighlight %}
39 |
40 | ## Good and Bad Types
41 |
42 | Very often we make mistakes when declaring a new type or
43 | modifying an existing one. Read them carefully and try to avoid
44 | in your SRS documents.
45 |
--------------------------------------------------------------------------------
/jekyll/_sass/_colors.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | $black: #4e4e4e;
7 | $blue: lighten(#394e63, 20);
8 | $red: #fd5559;
9 | $white: white;
10 | $green: #62d260;
11 |
--------------------------------------------------------------------------------
/jekyll/_sass/_highlight.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | @import "colors";
7 |
8 | .highlight {
9 | .k,
10 | .kn,
11 | .kd,
12 | .kt {
13 | font-weight: bold;
14 | }
15 | .c1 {
16 | color: #777;
17 | }
18 | .n {
19 | color: $blue;
20 | }
21 | .s {
22 | color: $red;
23 | }
24 | .o {
25 | color: darken($green, 20);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/jekyll/css/layout.scss:
--------------------------------------------------------------------------------
1 | ---
2 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | # SPDX-License-Identifier: MIT
4 | ---
5 |
6 | @import url(//fonts.googleapis.com/css?family=Source+Code+Pro:400,500);
7 | @import url(//fonts.googleapis.com/css?family=Ubuntu);
8 |
9 | @import "colors";
10 | @import "highlight";
11 |
12 | $main-font: 'Ubuntu', 'Arial', sans-serif;
13 | $code-font: 'Source Code Pro', monospace;
14 | $width: 700px;
15 | $em: 19px;
16 |
17 | .desktop-only {
18 | @media all and (max-width: $width) {
19 | display: none !important;
20 | }
21 | }
22 | body {
23 | height: 100%;
24 | font-family: $main-font;
25 | font-weight: 400;
26 | background-color: #fff;
27 | color: $black;
28 | font-size: $em;
29 | margin: 0;
30 | position: relative;
31 | overflow-x: hidden;
32 | }
33 | a, a:visited {
34 | color: $black;
35 | text-decoration: underline;
36 | &:hover {
37 | color: $blue;
38 | }
39 | }
40 | .wrapper {
41 | background-color: $white;
42 | box-sizing: border-box;
43 | line-height: 1.4 * $em;
44 | padding: 2 * $em;
45 | width: 40em;
46 | margin-left: auto;
47 | margin-right: auto;
48 | @media all and (max-width: $width) {
49 | padding: $em;
50 | }
51 | }
52 | .header {
53 | .logo {
54 | width: 192px;
55 | }
56 | }
57 | .footer {
58 | margin-top: 3 * $em;
59 | }
60 | h1 {
61 | margin-top: 3 * $em;
62 | margin-bottom: 2 * $em;
63 | color: darken($blue, 20);
64 | font-size: 2 * $em;
65 | line-height: 2 * $em;
66 | }
67 | h2 {
68 | line-height: 1.6 * $em;
69 | margin-top: 3 * $em;
70 | color: darken($blue, 20);
71 | font-size: 1.6 * $em;
72 | a.link {
73 | margin-left: .3 * $em;
74 | color: lighten($blue, 20);
75 | text-decoration: none;
76 | &:hover {
77 | color: inherit;
78 | }
79 | }
80 | }
81 | p {
82 | width: $width;
83 | @media all and (max-width: $width) {
84 | width: 100%;
85 | }
86 | }
87 | code {
88 | background-color: lighten($black, 60);
89 | border-radius: 0.3 * $em;
90 | padding-left: 0.3 * $em;
91 | padding-right: 0.3 * $em;
92 | }
93 | figure.highlight {
94 | margin: 0;
95 | }
96 | pre {
97 | overflow-x: auto;
98 | background-color: lighten($black, 60);
99 | border-radius: 0.3 * $em;
100 | padding: $em;
101 | width: auto;
102 | font-size: 0.8em;
103 | line-height: 1.2em;
104 | @media all and (max-width: $width) {
105 | padding: 0.5 * $em;
106 | }
107 | code {
108 | background-color: inherit;
109 | padding: 0;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/jekyll/images/ico-64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yegor256/requs/925dd42328c55fa610d8bd3f79898887a21456a3/jekyll/images/ico-64x64.png
--------------------------------------------------------------------------------
/jekyll/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: "Requirements Specifications Automated"
4 | date: 2014-06-22
5 | description:
6 | Requs is a controlled natural language (CNL) for
7 | software requirements specification
8 | ---
9 |
10 | IEEE 830-1998 says: "SRS (software requirements specification) should be
11 | correct, unambiguous, complete, consistent, ranked for importance and/or stability,
12 | verifiable, modifiable, traceable".
13 |
14 | As a controlled natural language (CNL) Requs enables the creation
15 | of such documents in plain text format. Requs resembles English
16 | but has a very strict syntax and semantic.
17 |
18 | Try online demo: [demo.requs.org](http://demo.requs.org/).
19 |
20 | ## Recent Articles
21 |
22 |
23 | {% for post in site.categories.blog %}
24 | {{ post.title }}
25 | {% endfor %}
26 |
27 |
28 | ## Blog Posts
29 |
30 | Check also this blog post:
31 | [Incremental Requirements With Requs](https://www.yegor256.com/2014/04/26/incremental-requirements-with-requs.html).
32 | It explains how Requs is used in [XDSD](https://www.xdsd.org) projects by
33 | [Zerocracy](https://www.zerocracy.co).
34 |
--------------------------------------------------------------------------------
/jekyll/robots.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yegor256/requs/925dd42328c55fa610d8bd3f79898887a21456a3/jekyll/robots.txt
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "config:base"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/requs-core/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2009-2025, Yegor Bugayenko
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions
6 | are met: 1) Redistributions of source code must retain the above
7 | copyright notice, this list of conditions and the following
8 | disclaimer. 2) Redistributions in binary form must reproduce the above
9 | copyright notice, this list of conditions and the following
10 | disclaimer in the documentation and/or other materials provided
11 | with the distribution. 3) Neither the name of the requs.org nor
12 | the names of its contributors may be used to endorse or promote
13 | products derived from this software without specific prior written
14 | permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
18 | NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 | THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 | OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/Facet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs;
6 |
7 | import com.jcabi.aspects.Immutable;
8 | import com.jcabi.xml.XML;
9 | import java.io.IOException;
10 |
11 | /**
12 | * Facet.
13 | *
14 | * @since 0.1
15 | */
16 | @Immutable
17 | public interface Facet {
18 |
19 | /**
20 | * Touch the spec from this facet.
21 | * @param spec Spec in XML
22 | * @return New XML
23 | * @throws IOException If fails on I/O operation
24 | * @since 1.9
25 | */
26 | XML touch(XML spec) throws IOException;
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/Aggregate.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet;
6 |
7 | import com.google.common.collect.Lists;
8 | import com.jcabi.aspects.Immutable;
9 | import com.jcabi.aspects.Tv;
10 | import com.jcabi.log.Logger;
11 | import com.jcabi.xml.XML;
12 | import java.io.File;
13 | import java.io.IOException;
14 | import java.nio.charset.StandardCharsets;
15 | import java.util.Collections;
16 | import java.util.List;
17 | import lombok.EqualsAndHashCode;
18 | import lombok.ToString;
19 | import org.apache.commons.io.FileUtils;
20 | import org.apache.commons.lang3.StringUtils;
21 | import org.requs.XeFacet;
22 | import org.xembly.Directive;
23 | import org.xembly.Directives;
24 |
25 | /**
26 | * Aggregate sources into one file.
27 | *
28 | * @since 1.2
29 | */
30 | @Immutable
31 | @ToString(of = { })
32 | @EqualsAndHashCode(of = "dir")
33 | public final class Aggregate implements XeFacet {
34 |
35 | /**
36 | * Directory with sources.
37 | */
38 | private final transient String dir;
39 |
40 | /**
41 | * Ctor.
42 | * @param path Path to the directory with sources
43 | */
44 | public Aggregate(final File path) {
45 | this.dir = path.getAbsolutePath();
46 | }
47 |
48 | @Override
49 | public Iterable touch(final XML spec) throws IOException {
50 | final StringBuilder text = new StringBuilder(Tv.THOUSAND);
51 | final List files = Lists.newArrayList(
52 | FileUtils.listFiles(
53 | new File(this.dir), new String[]{"req"}, true
54 | )
55 | );
56 | Collections.sort(files);
57 | int idx = 0;
58 | final Directives dirs = new Directives().xpath("/spec").addIf("files");
59 | for (final File file : files) {
60 | int pos = StringUtils.countMatches(text.toString(), "\n");
61 | pos += 1;
62 | Logger.info(this, "source file: %s", file);
63 | text.append(
64 | FileUtils.readFileToString(file, StandardCharsets.UTF_8)
65 | ).append('\n');
66 | dirs.add("file")
67 | .attr("id", Integer.toString(idx))
68 | .attr("line", Integer.toString(pos))
69 | .set(file.getAbsolutePath()).up();
70 | ++idx;
71 | }
72 | return dirs.up().add("input").set(text.toString());
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/Transform.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet;
6 |
7 | import com.jcabi.aspects.Immutable;
8 | import com.jcabi.xml.ClasspathSources;
9 | import com.jcabi.xml.XML;
10 | import com.jcabi.xml.XSLDocument;
11 | import java.net.URL;
12 | import lombok.EqualsAndHashCode;
13 | import lombok.ToString;
14 | import org.requs.Facet;
15 |
16 | /**
17 | * Transform.
18 | *
19 | * @since 0.1
20 | */
21 | @Immutable
22 | @ToString(includeFieldNames = false)
23 | @EqualsAndHashCode(of = "sheet")
24 | public final class Transform implements Facet {
25 |
26 | /**
27 | * XSL sheet to apply.
28 | */
29 | private final transient String sheet;
30 |
31 | /**
32 | * Public ctor.
33 | * @param xsl Name of XSL resource
34 | */
35 | public Transform(final String xsl) {
36 | this.sheet = xsl;
37 | }
38 |
39 | @Override
40 | public XML touch(final XML spec) {
41 | final URL url = Transform.class.getResource(this.sheet);
42 | if (url == null) {
43 | throw new IllegalArgumentException(
44 | String.format("Stylesheet '%s' not found", this.sheet)
45 | );
46 | }
47 | return XSLDocument.make(url)
48 | .with(new ClasspathSources(this.getClass()))
49 | .transform(spec);
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * Facets.
8 | *
9 | * @since 1.2
10 | */
11 | package org.requs.facet;
12 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/sa/CascadingRule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.sa;
6 |
7 | import com.jcabi.aspects.Immutable;
8 | import com.jcabi.aspects.Loggable;
9 | import java.util.Collection;
10 | import java.util.LinkedList;
11 | import lombok.EqualsAndHashCode;
12 | import lombok.ToString;
13 | import org.apache.commons.lang3.StringUtils;
14 |
15 | /**
16 | * Cascading rule.
17 | *
18 | * @since 1.14
19 | */
20 | @Immutable
21 | @ToString
22 | @EqualsAndHashCode
23 | @Loggable(Loggable.DEBUG)
24 | public final class CascadingRule implements Rule {
25 |
26 | @Override
27 | @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
28 | public Collection enforce(final String text) {
29 | final String[] lines = StringUtils.splitPreserveAllTokens(text, '\n');
30 | final Collection violations = new LinkedList<>();
31 | int indent = 0;
32 | for (int idx = 0; idx < lines.length; ++idx) {
33 | final int next = CascadingRule.indent(lines[idx]);
34 | if (indent > 0 && next > indent && next != indent + 2) {
35 | violations.add(
36 | new Violation.Simple(
37 | String.format(
38 | "indented for %d spaces, while %d required: [%s]",
39 | next, indent + 2, lines[idx]
40 | ),
41 | idx + 1, next
42 | )
43 | );
44 | }
45 | indent = next;
46 | }
47 | return violations;
48 | }
49 |
50 | /**
51 | * Calculate indentation of a line.
52 | * @param line Line
53 | * @return Indentation
54 | */
55 | private static int indent(final String line) {
56 | int indent;
57 | for (indent = 0; indent < line.length(); ++indent) {
58 | if (line.charAt(indent) != ' ') {
59 | break;
60 | }
61 | }
62 | return indent;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/sa/IndentationRule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.sa;
6 |
7 | import com.jcabi.aspects.Immutable;
8 | import com.jcabi.aspects.Loggable;
9 | import java.util.Collection;
10 | import java.util.LinkedList;
11 | import lombok.EqualsAndHashCode;
12 | import lombok.ToString;
13 |
14 | /**
15 | * Indentation rule in a single line.
16 | *
17 | * @since 1.14
18 | */
19 | @Immutable
20 | @ToString
21 | @EqualsAndHashCode
22 | @Loggable(Loggable.DEBUG)
23 | public final class IndentationRule implements LineRule {
24 |
25 | @Override
26 | public Collection check(final String line) {
27 | int indent;
28 | for (indent = 0; indent < line.length(); ++indent) {
29 | if (line.charAt(indent) != ' ') {
30 | break;
31 | }
32 | }
33 | final Collection violations = new LinkedList<>();
34 | if (indent % 2 != 0) {
35 | violations.add(
36 | new Violation.Simple(
37 | String.format(
38 | "indented for %d spaces, must be either %d or %d: [%s]",
39 | indent,
40 | indent >> 1 << 1,
41 | indent + 1 >> 1 << 1, line
42 | ),
43 | 0, indent
44 | )
45 | );
46 | }
47 | return violations;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/sa/LineRule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.sa;
6 |
7 | import com.google.common.base.Function;
8 | import com.google.common.collect.Collections2;
9 | import com.jcabi.aspects.Immutable;
10 | import com.jcabi.aspects.Loggable;
11 | import java.util.Collection;
12 | import java.util.LinkedList;
13 | import java.util.concurrent.atomic.AtomicInteger;
14 | import lombok.EqualsAndHashCode;
15 | import lombok.ToString;
16 | import org.apache.commons.lang3.StringUtils;
17 |
18 | /**
19 | * Rule of one line.
20 | *
21 | * @since 1.10
22 | */
23 | @Immutable
24 | public interface LineRule {
25 |
26 | /**
27 | * Validate incoming line.
28 | * @param line One line
29 | * @return Violations
30 | */
31 | Collection check(String line);
32 |
33 | /**
34 | * Wrap.
35 | *
36 | * @since 1.10
37 | */
38 | @Immutable
39 | @ToString
40 | @EqualsAndHashCode(of = "origin")
41 | @Loggable(Loggable.DEBUG)
42 | final class Wrap implements Rule {
43 | /**
44 | * Original rule.
45 | */
46 | private final transient LineRule origin;
47 |
48 | /**
49 | * Ctor.
50 | * @param rule Original rule
51 | */
52 | public Wrap(final LineRule rule) {
53 | this.origin = rule;
54 | }
55 |
56 | @Override
57 | public Collection enforce(final String spec) {
58 | final Collection violations = new LinkedList<>();
59 | final AtomicInteger number = new AtomicInteger(1);
60 | for (final String line
61 | : StringUtils.splitPreserveAllTokens(spec, '\n')) {
62 | final int num = number.getAndIncrement();
63 | violations.addAll(
64 | Collections2.transform(
65 | this.origin.check(line),
66 | // @checkstyle LineLength (1 line)
67 | (Function) vln -> new Violation.Simple(
68 | vln.details(),
69 | num, vln.position()
70 | )
71 | )
72 | );
73 | }
74 | return violations;
75 | }
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/sa/RegexRule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.sa;
6 |
7 | import com.jcabi.aspects.Immutable;
8 | import com.jcabi.aspects.Loggable;
9 | import java.util.Collection;
10 | import java.util.LinkedList;
11 | import java.util.regex.Matcher;
12 | import java.util.regex.Pattern;
13 | import lombok.EqualsAndHashCode;
14 | import lombok.ToString;
15 |
16 | /**
17 | * Regular expression rule.
18 | *
19 | * @since 1.10
20 | */
21 | @Immutable
22 | @ToString
23 | @EqualsAndHashCode(of = { "regex", "text" })
24 | @Loggable(Loggable.DEBUG)
25 | public final class RegexRule implements LineRule {
26 |
27 | /**
28 | * Regular expression.
29 | */
30 | private final transient String regex;
31 |
32 | /**
33 | * Description of violation.
34 | */
35 | private final transient String text;
36 |
37 | /**
38 | * Ctor.
39 | * @param rgx Regular expression
40 | * @param txt Description
41 | */
42 | public RegexRule(final String rgx, final String txt) {
43 | this.regex = rgx;
44 | this.text = txt;
45 | }
46 |
47 | @Override
48 | @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
49 | public Collection check(final String line) {
50 | final Pattern ptn = Pattern.compile(this.regex);
51 | final Matcher matcher = ptn.matcher(line);
52 | final Collection violations = new LinkedList<>();
53 | while (matcher.find()) {
54 | violations.add(
55 | new Violation.Simple(
56 | String.format("%s: [%s]", this.text, line),
57 | 0, matcher.start() + 1
58 | )
59 | );
60 | }
61 | return violations;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/sa/Rule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.sa;
6 |
7 | import com.jcabi.aspects.Immutable;
8 | import java.util.Collection;
9 |
10 | /**
11 | * Rule.
12 | *
13 | * @since 1.10
14 | */
15 | @Immutable
16 | public interface Rule {
17 |
18 | /**
19 | * Validate incoming text.
20 | * @param spec Spec in text format
21 | * @return Violations
22 | */
23 | Collection enforce(String spec);
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/sa/Violation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.sa;
6 |
7 | import com.jcabi.aspects.Immutable;
8 | import com.jcabi.aspects.Loggable;
9 | import lombok.EqualsAndHashCode;
10 | import lombok.ToString;
11 |
12 | /**
13 | * Violation.
14 | *
15 | * @since 1.10
16 | */
17 | @Immutable
18 | public interface Violation {
19 |
20 | /**
21 | * Line number.
22 | * @return Line (starting with 1)
23 | */
24 | int line();
25 |
26 | /**
27 | * Position in line.
28 | * @return Position (start from 1)
29 | */
30 | int position();
31 |
32 | /**
33 | * Description of the violation.
34 | * @return Description
35 | */
36 | String details();
37 |
38 | /**
39 | * Simple implementation.
40 | *
41 | * @since 1.0
42 | */
43 | @Immutable
44 | @ToString
45 | @EqualsAndHashCode
46 | @Loggable(Loggable.DEBUG)
47 | final class Simple implements Violation {
48 | /**
49 | * Descr.
50 | */
51 | private final transient String txt;
52 |
53 | /**
54 | * Line number.
55 | */
56 | private final transient int num;
57 |
58 | /**
59 | * Position in line.
60 | */
61 | private final transient int pos;
62 |
63 | /**
64 | * Ctor.
65 | * @param text Description
66 | * @param line Line number
67 | * @param position Position in line
68 | */
69 | public Simple(final String text, final int line, final int position) {
70 | this.txt = text;
71 | this.num = line;
72 | this.pos = position;
73 | }
74 |
75 | @Override
76 | public int line() {
77 | return this.num;
78 | }
79 |
80 | @Override
81 | public int position() {
82 | return this.pos;
83 | }
84 |
85 | @Override
86 | public String details() {
87 | return this.txt;
88 | }
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/sa/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * Static analysis.
8 | *
9 | * @since 1.10
10 | */
11 | package org.requs.facet.sa;
12 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/AntlrFacet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax;
6 |
7 | import com.jcabi.aspects.Immutable;
8 | import com.jcabi.xml.XML;
9 | import lombok.EqualsAndHashCode;
10 | import lombok.ToString;
11 | import org.antlr.v4.runtime.CharStreams;
12 | import org.antlr.v4.runtime.CommonTokenStream;
13 | import org.antlr.v4.runtime.RecognitionException;
14 | import org.antlr.v4.runtime.TokenStream;
15 | import org.requs.XeFacet;
16 | import org.requs.facet.syntax.ontology.Ontology;
17 | import org.requs.facet.syntax.ontology.XeOntology;
18 | import org.xembly.Directive;
19 | import org.xembly.Directives;
20 |
21 | /**
22 | * Syntax analysis.
23 | *
24 | * @checkstyle ClassDataAbstractionCouplingCheck (500 lines)
25 | * @since 0.1
26 | */
27 | @Immutable
28 | @ToString
29 | @EqualsAndHashCode
30 | public final class AntlrFacet implements XeFacet {
31 |
32 | @Override
33 | public Iterable touch(final XML spec) {
34 | final SpecLexer lexer = new SpecLexer(
35 | CharStreams.fromString(spec.xpath("/spec/input/text()").get(0))
36 | );
37 | final TokenStream tokens = new CommonTokenStream(lexer);
38 | final SpecParser parser = new SpecParser(tokens);
39 | final Errors errors = new Errors();
40 | lexer.removeErrorListeners();
41 | lexer.addErrorListener(errors);
42 | parser.removeErrorListeners();
43 | parser.addErrorListener(errors);
44 | final Ontology onto = new XeOntology();
45 | parser.setOntology(onto);
46 | try {
47 | parser.clauses();
48 | } catch (final RecognitionException | SyntaxException
49 | | StringIndexOutOfBoundsException ex) {
50 | errors.add(ex);
51 | }
52 | return new Directives().append(onto).append(errors);
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/Errors.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax;
6 |
7 | import java.util.Iterator;
8 | import org.antlr.v4.runtime.BaseErrorListener;
9 | import org.antlr.v4.runtime.RecognitionException;
10 | import org.antlr.v4.runtime.Recognizer;
11 | import org.xembly.Directive;
12 | import org.xembly.Directives;
13 |
14 | /**
15 | * Syntax analysis.
16 | *
17 | * @since 0.1
18 | * @checkstyle MultipleStringLiteralsCheck (500 lines)
19 | */
20 | @SuppressWarnings("PMD.AvoidDuplicateLiterals")
21 | final class Errors extends BaseErrorListener implements Iterable {
22 |
23 | /**
24 | * All directives collected.
25 | */
26 | private final transient Directives dirs =
27 | new Directives().xpath("/spec").addIf("errors");
28 |
29 | // @checkstyle ParameterNumberCheck (6 lines)
30 | @Override
31 | public void syntaxError(final Recognizer, ?> recognizer,
32 | final Object symbol, final int line, final int pos, final String msg,
33 | final RecognitionException exc) {
34 | this.dirs.add("error")
35 | .attr("type", "syntax")
36 | .attr("line", Integer.toString(line))
37 | .attr("pos", Integer.toString(pos))
38 | .set(msg).up();
39 | }
40 |
41 | @Override
42 | public Iterator iterator() {
43 | return this.dirs.iterator();
44 | }
45 |
46 | /**
47 | * Add an exception.
48 | * @param error Exception to add
49 | * @since 1.4
50 | */
51 | public void add(final Exception error) {
52 | this.dirs.add("error")
53 | .attr("type", "exception")
54 | .attr("line", "1")
55 | .attr("pos", "0")
56 | .set(error.getLocalizedMessage()).up();
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/SyntaxException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax;
6 |
7 | /**
8 | * Syntax exception.
9 | *
10 | * @since 1.4
11 | */
12 | final class SyntaxException extends RuntimeException {
13 |
14 | /**
15 | * Serialization marker.
16 | */
17 | private static final long serialVersionUID = 1497953278746134529L;
18 |
19 | /**
20 | * Ctor.
21 | * @param cause Cause of it
22 | */
23 | SyntaxException(final String cause) {
24 | super(cause);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/Acronym.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | /**
8 | * Acronym.
9 | *
10 | * @since 1.14
11 | */
12 | public interface Acronym extends Mentioned, Informal {
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/Flow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | /**
8 | * Flow.
9 | *
10 | * @since 1.1
11 | */
12 | public interface Flow extends Informal {
13 |
14 | /**
15 | * SELF binding.
16 | */
17 | String SELF = "_self";
18 |
19 | /**
20 | * Get its step by number.
21 | * @param number Number of the step
22 | * @return Step
23 | */
24 | Step step(int number);
25 |
26 | /**
27 | * Declare a binding used in the method.
28 | * @param name Unique name of it
29 | * @param type Type of it
30 | */
31 | void binding(String name, String type);
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/Informal.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | /**
8 | * Can be informal.
9 | *
10 | * @since 1.1
11 | */
12 | public interface Informal {
13 |
14 | /**
15 | * Explain this slot.
16 | * @param informal Informal explanation
17 | */
18 | void explain(String informal);
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/Mentioned.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | /**
8 | * Something mentioned in source code.
9 | *
10 | * @since 1.1
11 | */
12 | public interface Mentioned {
13 |
14 | /**
15 | * Mention it in the given lines of source.
16 | * @param where Where was it mentioned
17 | */
18 | void mention(int where);
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/Method.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | /**
8 | * Use case.
9 | *
10 | * @since 1.1
11 | */
12 | public interface Method extends Flow, Mentioned, Signature {
13 |
14 | /**
15 | * Add an attributes.
16 | * @param name Attribute name
17 | * @param seal Seal to attach
18 | */
19 | void attribute(String name, String seal);
20 |
21 | /**
22 | * Get an NFR by name.
23 | * @param name NFR name
24 | * @return NFR
25 | */
26 | Nfr nfr(String name);
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/Nfr.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | /**
8 | * Non-functional requirement.
9 | *
10 | * @since 1.5
11 | */
12 | public interface Nfr extends Mentioned, Informal {
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/Ontology.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import org.xembly.Directive;
8 |
9 | /**
10 | * Ontology.
11 | *
12 | * The ontology is write-only. This is how you're supposed to use it:
13 | *
14 | *
15 | * Ontology onto = // make it
16 | * Type type = onto.type("Employee");
17 | * type.mention("3-5");
18 | * type.explain("a person working in a Company");
19 | *
20 | *
21 | * @since 1.1
22 | */
23 | public interface Ontology extends Iterable {
24 |
25 | /**
26 | * Found new type.
27 | * @param name Name of it
28 | * @return Type
29 | */
30 | Type type(String name);
31 |
32 | /**
33 | * Find method.
34 | * @param name Name of it
35 | * @return Method
36 | */
37 | Method method(String name);
38 |
39 | /**
40 | * Find page.
41 | * @param name Name of it
42 | * @return Page
43 | */
44 | Page page(String name);
45 |
46 | /**
47 | * Get acronym.
48 | * @param name Name of it
49 | * @return Acronym
50 | */
51 | Acronym acronym(String name);
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/Page.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | /**
8 | * Page in Markdown.
9 | *
10 | * @since 1.7
11 | */
12 | public interface Page extends Mentioned, Informal {
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/Signature.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | /**
8 | * Signature of a function call or declaration.
9 | *
10 | * @since 1.1
11 | */
12 | public interface Signature extends Informal {
13 |
14 | /**
15 | * Sign it.
16 | * @param text Text to use (in quotes if informal)
17 | */
18 | void sign(String text);
19 |
20 | /**
21 | * Set the object.
22 | * @param name Variable of the object
23 | */
24 | void object(String name);
25 |
26 | /**
27 | * Result variable.
28 | * @param name Variable of the result
29 | */
30 | void result(String name);
31 |
32 | /**
33 | * Input argument.
34 | * @param name Name of the argument
35 | */
36 | void input(String name);
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/Slot.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | /**
8 | * Slot of a type.
9 | *
10 | * @since 1.1
11 | */
12 | public interface Slot extends Mentioned, Informal {
13 |
14 | /**
15 | * Arity.
16 | *
17 | * @since 1.1
18 | */
19 | enum Arity {
20 | /**
21 | * One or many.
22 | */
23 | MANY("1..*"),
24 |
25 | /**
26 | * Zero or many: 0..*.
27 | */
28 | ANY("0..*"),
29 |
30 | /**
31 | * Strictly one.
32 | */
33 | ONE("1");
34 |
35 | /**
36 | * Mnemo.
37 | */
38 | private final transient String text;
39 |
40 | /**
41 | * Ctor.
42 | * @param mnemo Mnemo
43 | */
44 | Arity(final String mnemo) {
45 | this.text = mnemo;
46 | }
47 |
48 | /**
49 | * Mnemo.
50 | * @return Mnemo
51 | */
52 | public String mnemo() {
53 | return this.text;
54 | }
55 | }
56 |
57 | /**
58 | * Assign a type to the slot.
59 | * @param type Type to assign
60 | */
61 | void assign(String type);
62 |
63 | /**
64 | * Set its arity.
65 | * @param arity Arity to set
66 | */
67 | void arity(Slot.Arity arity);
68 |
69 | /**
70 | * Is it a composition?
71 | * @param cmp TRUE if it's a composition
72 | * @since 1.14
73 | */
74 | void composition(boolean cmp);
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/Step.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | /**
8 | * Step.
9 | *
10 | * @since 1.1
11 | */
12 | public interface Step extends Mentioned, Signature {
13 |
14 | /**
15 | * Exception at a step.
16 | * @param text Exception text
17 | * @return Flow for this exception
18 | */
19 | Flow exception(String text);
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/Type.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | /**
8 | * Type.
9 | *
10 | * @since 1.1
11 | */
12 | public interface Type extends Mentioned, Informal {
13 |
14 | /**
15 | * Set parent.
16 | * @param type Name of parent type
17 | */
18 | void parent(String type);
19 |
20 | /**
21 | * Set TRUE if it's an actor.
22 | * @param act TRUE if an actor
23 | * @since 1.14
24 | */
25 | void actor(boolean act);
26 |
27 | /**
28 | * Found a slot of the type.
29 | * @param name Slot name
30 | * @return Slot
31 | */
32 | Slot slot(String name);
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/XeAcronym.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.aspects.Loggable;
8 | import lombok.EqualsAndHashCode;
9 | import lombok.ToString;
10 | import org.xembly.Directives;
11 |
12 | /**
13 | * Xembly acronym.
14 | *
15 | * @since 1.14
16 | */
17 | @ToString
18 | @EqualsAndHashCode
19 | @Loggable(Loggable.DEBUG)
20 | final class XeAcronym implements Acronym {
21 |
22 | /**
23 | * Mentioned helper.
24 | */
25 | private final transient Mentioned mentioned;
26 |
27 | /**
28 | * Informal helper.
29 | */
30 | private final transient Informal informal;
31 |
32 | /**
33 | * Ctor.
34 | * @param directives Directives to extend
35 | * @param xpath XPath to start with
36 | */
37 | XeAcronym(final Directives directives, final String xpath) {
38 | this.mentioned = new XeMentioned(directives, xpath);
39 | this.informal = new XeInformal(directives, xpath);
40 | }
41 |
42 | @Override
43 | public void explain(final String info) {
44 | this.informal.explain(info);
45 | }
46 |
47 | @Override
48 | public void mention(final int where) {
49 | this.mentioned.mention(where);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/XeFlow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.aspects.Loggable;
8 | import lombok.EqualsAndHashCode;
9 | import lombok.ToString;
10 | import org.xembly.Directives;
11 |
12 | /**
13 | * Xembly use case.
14 | *
15 | * @since 1.1
16 | */
17 | @ToString
18 | @EqualsAndHashCode(of = { "dirs", "start" })
19 | @Loggable(Loggable.DEBUG)
20 | final class XeFlow implements Flow {
21 |
22 | /**
23 | * All directives.
24 | */
25 | private final transient Directives dirs;
26 |
27 | /**
28 | * Starting XPath.
29 | */
30 | private final transient String start;
31 |
32 | /**
33 | * Informal helper.
34 | */
35 | private final transient Informal informal;
36 |
37 | /**
38 | * Ctor.
39 | * @param directives Directives to extend
40 | * @param xpath XPath to start with
41 | */
42 | XeFlow(final Directives directives, final String xpath) {
43 | this.informal = new XeInformal(directives, xpath);
44 | this.dirs = directives;
45 | this.start = xpath;
46 | }
47 |
48 | @Override
49 | public Step step(final int number) {
50 | this.dirs.xpath(this.start).strict(1).addIf("steps")
51 | .xpath(this.start)
52 | .xpath(String.format("steps[not(step/number=%d)]", number))
53 | .add("step").add("number").set(Integer.toString(number));
54 | return new XeStep(
55 | this.dirs,
56 | String.format("%s/steps/step[number=%d]", this.start, number)
57 | );
58 | }
59 |
60 | @Override
61 | public void binding(final String name, final String type) {
62 | this.dirs.xpath(this.start).strict(1).addIf("bindings").up().xpath(
63 | String.format(
64 | "bindings[not(binding[name='%s' and type=%s])]",
65 | name, XeOntology.escapeXPath(type)
66 | )
67 | ).add("binding").add("name").set(name).up().add("type").set(type);
68 | }
69 |
70 | @Override
71 | public void explain(final String info) {
72 | this.informal.explain(info);
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/XeInformal.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.aspects.Loggable;
8 | import lombok.EqualsAndHashCode;
9 | import lombok.ToString;
10 | import org.xembly.Directives;
11 |
12 | /**
13 | * Xembly informal.
14 | *
15 | * @since 1.1
16 | */
17 | @ToString
18 | @EqualsAndHashCode(of = { "dirs", "start" })
19 | @Loggable(Loggable.DEBUG)
20 | final class XeInformal implements Informal {
21 |
22 | /**
23 | * All directives.
24 | */
25 | private final transient Directives dirs;
26 |
27 | /**
28 | * Starting XPath.
29 | */
30 | private final transient String start;
31 |
32 | /**
33 | * Ctor.
34 | * @param directives Directives to extend
35 | * @param xpath XPath to start with
36 | */
37 | XeInformal(final Directives directives, final String xpath) {
38 | this.dirs = directives;
39 | this.start = xpath;
40 | }
41 |
42 | @Override
43 | public void explain(final String informal) {
44 | this.dirs.xpath(this.start).strict(1)
45 | .addIf("info").add("informal").set(informal);
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/XeMentioned.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.aspects.Loggable;
8 | import lombok.EqualsAndHashCode;
9 | import lombok.ToString;
10 | import org.xembly.Directives;
11 |
12 | /**
13 | * Xembly mentioned.
14 | *
15 | * @since 1.1
16 | */
17 | @ToString
18 | @EqualsAndHashCode(of = { "dirs", "start" })
19 | @Loggable(Loggable.DEBUG)
20 | final class XeMentioned implements Mentioned {
21 |
22 | /**
23 | * All directives.
24 | */
25 | private final transient Directives dirs;
26 |
27 | /**
28 | * Starting XPath.
29 | */
30 | private final transient String start;
31 |
32 | /**
33 | * Ctor.
34 | * @param directives Directives to extend
35 | * @param xpath XPath to start with
36 | */
37 | XeMentioned(final Directives directives, final String xpath) {
38 | this.dirs = directives;
39 | this.start = xpath;
40 | }
41 |
42 | @Override
43 | public void mention(final int where) {
44 | this.dirs.xpath(this.start).strict(1).addIf("mentioned")
45 | .strict(1)
46 | .add("where").set(Integer.toString(where));
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/XeNfr.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.aspects.Loggable;
8 | import lombok.EqualsAndHashCode;
9 | import lombok.ToString;
10 | import org.xembly.Directives;
11 |
12 | /**
13 | * Xembly NFR.
14 | *
15 | * @since 1.5
16 | */
17 | @ToString
18 | @EqualsAndHashCode(of = "dirs")
19 | @Loggable(Loggable.DEBUG)
20 | final class XeNfr implements Nfr {
21 |
22 | /**
23 | * All directives.
24 | */
25 | private final transient Directives dirs;
26 |
27 | /**
28 | * Starting XPath.
29 | */
30 | private final transient String start;
31 |
32 | /**
33 | * Mentioned helper.
34 | */
35 | private final transient Mentioned mentioned;
36 |
37 | /**
38 | * Informal helper.
39 | */
40 | private final transient Informal informal;
41 |
42 | /**
43 | * Ctor.
44 | * @param directives Directives to extend
45 | * @param xpath XPath to start with
46 | */
47 | XeNfr(final Directives directives, final String xpath) {
48 | this.mentioned = new XeMethod(directives, xpath);
49 | this.informal = new XeInformal(directives, xpath);
50 | this.dirs = directives;
51 | this.start = xpath;
52 | }
53 |
54 | @Override
55 | public void mention(final int where) {
56 | this.mentioned.mention(where);
57 | }
58 |
59 | @Override
60 | public void explain(final String info) {
61 | assert this.dirs != null;
62 | assert this.start != null;
63 | this.informal.explain(info);
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/XePage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.aspects.Loggable;
8 | import lombok.EqualsAndHashCode;
9 | import lombok.ToString;
10 | import org.xembly.Directives;
11 |
12 | /**
13 | * Xembly page.
14 | *
15 | * @since 1.7
16 | */
17 | @ToString
18 | @EqualsAndHashCode
19 | @Loggable(Loggable.DEBUG)
20 | final class XePage implements Page {
21 |
22 | /**
23 | * Mentioned helper.
24 | */
25 | private final transient Mentioned mentioned;
26 |
27 | /**
28 | * Informal helper.
29 | */
30 | private final transient Informal informal;
31 |
32 | /**
33 | * Ctor.
34 | * @param directives Directives to extend
35 | * @param xpath XPath to start with
36 | */
37 | XePage(final Directives directives, final String xpath) {
38 | this.mentioned = new XeMentioned(directives, xpath);
39 | this.informal = new XeInformal(directives, xpath);
40 | }
41 |
42 | @Override
43 | public void explain(final String info) {
44 | this.informal.explain(info);
45 | }
46 |
47 | @Override
48 | public void mention(final int where) {
49 | this.mentioned.mention(where);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/XeSignature.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.aspects.Loggable;
8 | import lombok.EqualsAndHashCode;
9 | import lombok.ToString;
10 | import org.xembly.Directives;
11 |
12 | /**
13 | * Xembly signature.
14 | *
15 | * @since 1.1
16 | */
17 | @ToString
18 | @EqualsAndHashCode(of = { "dirs", "start" })
19 | @Loggable(Loggable.DEBUG)
20 | final class XeSignature implements Signature {
21 |
22 | /**
23 | * All directives.
24 | */
25 | private final transient Directives dirs;
26 |
27 | /**
28 | * Starting XPath.
29 | */
30 | private final transient String start;
31 |
32 | /**
33 | * Informal helper.
34 | */
35 | private final transient Informal informal;
36 |
37 | /**
38 | * Ctor.
39 | * @param directives Directives to extend
40 | * @param xpath XPath to start with
41 | */
42 | XeSignature(final Directives directives, final String xpath) {
43 | this.dirs = directives;
44 | this.start = xpath;
45 | this.informal = new XeInformal(directives, xpath);
46 | }
47 |
48 | @Override
49 | public void sign(final String text) {
50 | this.dirs.xpath(this.start).strict(1)
51 | .add("signature").set(text);
52 | }
53 |
54 | @Override
55 | public void object(final String name) {
56 | this.dirs.xpath(this.start).strict(1)
57 | .add("object").set(name);
58 | }
59 |
60 | @Override
61 | public void result(final String name) {
62 | this.dirs.xpath(this.start).strict(1)
63 | .add("result").set(name);
64 | }
65 |
66 | @Override
67 | public void input(final String name) {
68 | this.dirs.xpath(this.start).strict(1)
69 | .addIf("args").add("arg").set(name);
70 | }
71 |
72 | @Override
73 | public void explain(final String info) {
74 | this.informal.explain(info);
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/XeSlot.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.aspects.Loggable;
8 | import lombok.EqualsAndHashCode;
9 | import lombok.ToString;
10 | import org.xembly.Directives;
11 |
12 | /**
13 | * Xembly slot in a type.
14 | *
15 | * @since 1.1
16 | */
17 | @ToString
18 | @EqualsAndHashCode(of = "dirs")
19 | @Loggable(Loggable.DEBUG)
20 | final class XeSlot implements Slot {
21 |
22 | /**
23 | * All directives.
24 | */
25 | private final transient Directives dirs;
26 |
27 | /**
28 | * Starting XPath.
29 | */
30 | private final transient String start;
31 |
32 | /**
33 | * Mentioned helper.
34 | */
35 | private final transient Mentioned mentioned;
36 |
37 | /**
38 | * Informal helper.
39 | */
40 | private final transient Informal informal;
41 |
42 | /**
43 | * Ctor.
44 | * @param directives Directives to extend
45 | * @param xpath XPath to start with
46 | */
47 | XeSlot(final Directives directives, final String xpath) {
48 | this.mentioned = new XeMethod(directives, xpath);
49 | this.informal = new XeInformal(directives, xpath);
50 | this.dirs = directives;
51 | this.start = xpath;
52 | }
53 |
54 | @Override
55 | public void assign(final String type) {
56 | this.dirs.xpath(this.start).strict(1)
57 | .addIf("type").set(type);
58 | }
59 |
60 | @Override
61 | public void arity(final Slot.Arity arity) {
62 | this.dirs.xpath(this.start).strict(1)
63 | .addIf("arity").set(arity.mnemo());
64 | }
65 |
66 | @Override
67 | public void composition(final boolean cmp) {
68 | this.dirs.xpath(this.start).strict(1)
69 | .addIf("composition").set(Boolean.toString(cmp));
70 | }
71 |
72 | @Override
73 | public void mention(final int where) {
74 | this.mentioned.mention(where);
75 | }
76 |
77 | @Override
78 | public void explain(final String info) {
79 | this.informal.explain(info);
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/XeStep.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.aspects.Loggable;
8 | import lombok.EqualsAndHashCode;
9 | import lombok.ToString;
10 | import org.xembly.Directives;
11 |
12 | /**
13 | * Xembly step.
14 | *
15 | * @since 1.1
16 | */
17 | @ToString
18 | @EqualsAndHashCode(of = { "dirs", "start" })
19 | @Loggable(Loggable.DEBUG)
20 | final class XeStep implements Step {
21 |
22 | /**
23 | * All directives.
24 | */
25 | private final transient Directives dirs;
26 |
27 | /**
28 | * Starting XPath.
29 | */
30 | private final transient String start;
31 |
32 | /**
33 | * Mentioned helper.
34 | */
35 | private final transient Mentioned mentioned;
36 |
37 | /**
38 | * Signature helper.
39 | */
40 | private final transient Signature signature;
41 |
42 | /**
43 | * Ctor.
44 | * @param directives Directives to extend
45 | * @param xpath XPath to start with
46 | */
47 | XeStep(final Directives directives, final String xpath) {
48 | this.mentioned = new XeMentioned(directives, xpath);
49 | this.signature = new XeSignature(directives, xpath);
50 | this.dirs = directives;
51 | this.start = xpath;
52 | }
53 |
54 | @Override
55 | public Flow exception(final String text) {
56 | this.dirs.xpath(this.start)
57 | .strict(1).addIf("exceptions")
58 | .xpath(this.start)
59 | .xpath(
60 | String.format(
61 | "exceptions[not(exception/when=%s)]",
62 | XeOntology.escapeXPath(text)
63 | )
64 | )
65 | .add("exception").add("when").set(text);
66 | return new XeFlow(
67 | this.dirs,
68 | String.format(
69 | "%s/exceptions/exception[when=%s ]",
70 | this.start, XeOntology.escapeXPath(text)
71 | )
72 | );
73 | }
74 |
75 | @Override
76 | public void sign(final String text) {
77 | this.signature.sign(text);
78 | }
79 |
80 | @Override
81 | public void object(final String name) {
82 | this.signature.object(name);
83 | }
84 |
85 | @Override
86 | public void result(final String name) {
87 | this.signature.result(name);
88 | }
89 |
90 | @Override
91 | public void input(final String name) {
92 | this.signature.input(name);
93 | }
94 |
95 | @Override
96 | public void mention(final int where) {
97 | this.mentioned.mention(where);
98 | }
99 |
100 | @Override
101 | public void explain(final String informal) {
102 | this.signature.explain(informal);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/XeType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.aspects.Loggable;
8 | import lombok.EqualsAndHashCode;
9 | import lombok.ToString;
10 | import org.xembly.Directives;
11 |
12 | /**
13 | * Xembly type.
14 | *
15 | * @since 1.1
16 | */
17 | @ToString
18 | @EqualsAndHashCode(of = { "dirs", "start" })
19 | @Loggable(Loggable.DEBUG)
20 | final class XeType implements Type {
21 |
22 | /**
23 | * All directives.
24 | */
25 | private final transient Directives dirs;
26 |
27 | /**
28 | * Starting XPath.
29 | */
30 | private final transient String start;
31 |
32 | /**
33 | * Mentioned helper.
34 | */
35 | private final transient Mentioned mentioned;
36 |
37 | /**
38 | * Informal helper.
39 | */
40 | private final transient Informal informal;
41 |
42 | /**
43 | * Ctor.
44 | * @param directives Directives to extend
45 | * @param xpath XPath to start with
46 | */
47 | XeType(final Directives directives, final String xpath) {
48 | this.mentioned = new XeMentioned(directives, xpath);
49 | this.informal = new XeInformal(directives, xpath);
50 | this.dirs = directives;
51 | this.start = xpath;
52 | }
53 |
54 | @Override
55 | public void parent(final String type) {
56 | this.dirs.xpath(this.start).strict(1)
57 | .addIf("parents").add("type").set(type);
58 | }
59 |
60 | @Override
61 | public void actor(final boolean act) {
62 | this.dirs.xpath(this.start).strict(1)
63 | .addIf("actor").set(Boolean.toString(act));
64 | }
65 |
66 | @Override
67 | public Slot slot(final String name) {
68 | this.dirs.xpath(this.start).strict(1)
69 | .addIf("slots").add("slot").add("name").set(name);
70 | return new XeSlot(
71 | this.dirs,
72 | String.format(
73 | "%s/slots/slot[name=%s]", this.start,
74 | XeOntology.escapeXPath(name)
75 | )
76 | );
77 | }
78 |
79 | @Override
80 | public void explain(final String info) {
81 | this.informal.explain(info);
82 | }
83 |
84 | @Override
85 | public void mention(final int where) {
86 | this.mentioned.mention(where);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/ontology/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * Ontology.
8 | *
9 | * @since 1.1
10 | */
11 | package org.requs.facet.syntax.ontology;
12 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/syntax/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * Syntax analysis.
8 | */
9 | package org.requs.facet.syntax;
10 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/uml/Plant.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.uml;
6 |
7 | import com.jcabi.aspects.Immutable;
8 | import com.jcabi.xml.XMLDocument;
9 | import java.io.ByteArrayOutputStream;
10 | import java.io.IOException;
11 | import lombok.EqualsAndHashCode;
12 | import lombok.ToString;
13 | import net.sourceforge.plantuml.FileFormat;
14 | import net.sourceforge.plantuml.FileFormatOption;
15 | import net.sourceforge.plantuml.SourceStringReader;
16 | import org.apache.commons.lang3.SystemUtils;
17 |
18 | /**
19 | * Plant UML compiler.
20 | *
21 | * @since 1.11
22 | */
23 | @Immutable
24 | @ToString(of = { })
25 | @EqualsAndHashCode
26 | public final class Plant {
27 |
28 | /**
29 | * Utility class.
30 | */
31 | private Plant() {
32 | // empty
33 | }
34 |
35 | /**
36 | * Make a diagram, in SVG.
37 | * @param src PlantUML source
38 | * @return SVG as a text
39 | * @throws IOException If fails
40 | */
41 | @SuppressWarnings("PMD.ProhibitPublicStaticMethods")
42 | public static String svg(final String src) throws IOException {
43 | final String svg;
44 | if (SystemUtils.IS_OS_WINDOWS) {
45 | svg = "SVG can't be rendered in Windows
";
46 | } else {
47 | final SourceStringReader reader = new SourceStringReader(src);
48 | final ByteArrayOutputStream baos = new ByteArrayOutputStream();
49 | reader.generateImage(baos, new FileFormatOption(FileFormat.SVG));
50 | svg = new XMLDocument(
51 | new String(baos.toByteArray())
52 | ).nodes("/*").get(0).toString().replace("xmlns=\"\"", "");
53 | }
54 | return svg;
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/facet/uml/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * UML diagrams.
8 | *
9 | * @since 1.11
10 | */
11 | package org.requs.facet.uml;
12 |
--------------------------------------------------------------------------------
/requs-core/src/main/java/org/requs/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * Requs.
8 | */
9 | package org.requs;
10 |
--------------------------------------------------------------------------------
/requs-core/src/main/resources/org/requs/facet/cleanup/incomplete-binding.xsl:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | method
43 |
44 | has incorrect binding
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/requs-core/src/main/resources/org/requs/facet/cleanup/incomplete-step-signature.xsl:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | step
48 |
49 | doesn't have a signature
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | unknown
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/requs-core/src/main/resources/org/requs/facet/pages-in-html.xsl:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/requs-core/src/main/resources/org/requs/facet/sanity/broken-order-of-steps.xsl:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | Step "
43 |
44 | " is not in order with others
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/requs-core/src/main/resources/org/requs/facet/sanity/empty-re-throws.xsl:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | Exception flow of
43 |
44 | /
45 |
46 | simply re-throws an exception, it is pointless
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/requs-core/src/main/resources/org/requs/facet/sanity/misplaced-failure-check.xsl:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | Step "
43 |
44 | " fails while it is not the last step in the flow
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/requs-core/src/main/resources/org/requs/facet/sanity/missed-step-numbers.xsl:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | Step "
43 |
44 | " follows "
45 |
46 | ", some steps are probably missing
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/requs-core/src/main/resources/org/requs/facet/sanity/orphan-types.xsl:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | Type "
45 |
46 | " is not used in any slot or a use case
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/requs-core/src/main/resources/org/requs/facet/sanity/too-many-steps.xsl:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | There are more than eight steps, the flow is difficult to understand
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/requs-core/src/main/resources/org/requs/facet/seal-methods.xsl:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/requs-core/src/main/resources/org/requs/facet/step-refs.xsl:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/requs-core/src/main/scss/requs.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | * {
7 | padding: 0;
8 | margin: 0;
9 | }
10 |
11 | body {
12 | margin: 2em;
13 | font-family: 'Ubuntu', 'Arial', serif;
14 | font-size: 16px;
15 | color: #4e4e4e;
16 | }
17 |
18 | a {
19 | color: #428bca;
20 | text-decoration: none;
21 | &:hover {
22 | text-decoration: underline;
23 | }
24 | }
25 |
26 | code, pre {
27 | font-family: 'Monaco', 'Courier New', monospace;
28 | background-color: #ccc;
29 | }
30 |
31 | code {
32 | padding: 0 .4em;
33 | }
34 |
35 | p, ul, ol {
36 | margin-top: 1em;
37 | margin-bottom: 1em;
38 | }
39 |
40 | td, th {
41 | padding: .3em;
42 | border-bottom: 1px solid #ccc;
43 | }
44 |
45 | th {
46 | text-align: left;
47 | background-color: #ddd;
48 | border-bottom: 1px solid #444;
49 | font-weight: 500;
50 | }
51 |
52 | h1 {
53 | margin-top: 2em;
54 | font-size: 1.4em;
55 | }
56 |
57 | h2 {
58 | margin-top: 2em;
59 | font-size: 1.2em;
60 | }
61 |
62 | li {
63 | margin-left: 2em;
64 | }
65 |
66 | .intro {
67 | font-size: 0.9em;
68 | color: #999;
69 | }
70 |
71 | .type {
72 | margin-top: 3em;
73 | }
74 |
75 | .slots {
76 | margin-left: 1em;
77 | margin-top: 1em;
78 | }
79 |
80 | .method {
81 | margin-top: 1em;
82 | margin-left: 1em;
83 | }
84 |
85 | .steps {
86 | margin-top: 1em;
87 | margin-left: 1em
88 | }
89 |
90 | .step {
91 | margin-top: 0.25em;
92 | }
93 |
94 | .nfrs {
95 | margin-top: 1em;
96 | margin-left: 1em
97 | }
98 |
99 | .nfr {
100 | margin-top: 0.25em;
101 | }
102 |
103 | .exception {
104 | margin-left: 1em;
105 | margin-top: 1em;
106 | margin-bottom: 1em;
107 | }
108 |
109 | .informal {
110 | color: #666;
111 | }
112 |
113 | .warning {
114 | color: #d9534f;
115 | }
116 |
117 | .crud, .fail {
118 | color: #5cb85c;
119 | }
120 |
121 | .label {
122 | margin-left: 0.5em;
123 | color: white;
124 | border-radius: .25em;
125 | font-size: 0.85em;
126 | padding: .1em .3em .15em;
127 | }
128 |
129 | .attribute {
130 | background-color: #999;
131 | }
132 |
133 | .sealed {
134 | background-color: #5cb85c;
135 | }
136 |
137 | .seal {
138 | background-color: #5bc0de;
139 | }
140 |
141 | .uml {
142 | display: inline-block;
143 | margin-top: 0.5em;
144 | margin-bottom: 0.5em;
145 | border: 1px solid gray;
146 | padding: 1em;
147 | }
148 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * Facets, tests.
8 | *
9 | * @since 1.2
10 | */
11 | package org.requs.facet;
12 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/sa/CascadingRuleTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.sa;
6 |
7 | import com.jcabi.aspects.Tv;
8 | import org.hamcrest.MatcherAssert;
9 | import org.hamcrest.Matchers;
10 | import org.junit.jupiter.api.Test;
11 |
12 | /**
13 | * Test case for {@link CascadingRule}.
14 | * @since 1.14
15 | */
16 | public final class CascadingRuleTest {
17 |
18 | @Test
19 | public void checksInput() {
20 | MatcherAssert.assertThat(
21 | new CascadingRule().enforce("hey\n works\n fine\nstart"),
22 | Matchers.empty()
23 | );
24 | }
25 |
26 | @Test
27 | public void checksInvalidInput() {
28 | MatcherAssert.assertThat(
29 | new CascadingRule().enforce(
30 | "\n\n\n hey\n three!"
31 | ).iterator().next().line(),
32 | Matchers.equalTo(Tv.FIVE)
33 | );
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/sa/IndentationRuleTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.sa;
6 |
7 | import org.hamcrest.MatcherAssert;
8 | import org.hamcrest.Matchers;
9 | import org.junit.jupiter.api.Test;
10 |
11 | /**
12 | * Test case for {@link IndentationRule}.
13 | * @since 1.14
14 | */
15 | public final class IndentationRuleTest {
16 |
17 | @Test
18 | public void checksInput() throws Exception {
19 | MatcherAssert.assertThat(
20 | new IndentationRule().check(" works fine"),
21 | Matchers.empty()
22 | );
23 | }
24 |
25 | @Test
26 | public void checksInvalidInput() throws Exception {
27 | MatcherAssert.assertThat(
28 | new IndentationRule().check(" works fine"),
29 | Matchers.not(Matchers.empty())
30 | );
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/sa/LineRuleTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.sa;
6 |
7 | import com.jcabi.aspects.Tv;
8 | import org.hamcrest.MatcherAssert;
9 | import org.hamcrest.Matchers;
10 | import org.junit.jupiter.api.Test;
11 |
12 | /**
13 | * Test case for {@link LineRule}.
14 | * @since 1.14
15 | */
16 | public final class LineRuleTest {
17 |
18 | @Test
19 | public void checksInvalidInput() throws Exception {
20 | MatcherAssert.assertThat(
21 | new LineRule.Wrap(new RegexRule("[a-z]+", "")).enforce(
22 | "\n\n\nhey"
23 | ).iterator().next().line(),
24 | Matchers.equalTo(Tv.FOUR)
25 | );
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/sa/RegexRuleTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.sa;
6 |
7 | import org.hamcrest.MatcherAssert;
8 | import org.hamcrest.Matchers;
9 | import org.junit.jupiter.api.Test;
10 |
11 | /**
12 | * Test case for {@link RegexRule}.
13 | * @since 1.14
14 | */
15 | public final class RegexRuleTest {
16 |
17 | @Test
18 | public void checksInput() throws Exception {
19 | MatcherAssert.assertThat(
20 | new RegexRule("[a-z]+", "").check("abjkljeklsf"),
21 | Matchers.not(Matchers.empty())
22 | );
23 | }
24 |
25 | @Test
26 | public void checksInvalidInput() throws Exception {
27 | MatcherAssert.assertThat(
28 | new RegexRule("[0-9]", "").check("broken input"),
29 | Matchers.empty()
30 | );
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/sa/RulesTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.sa;
6 |
7 | import com.jcabi.matchers.XhtmlMatchers;
8 | import com.jcabi.xml.XMLDocument;
9 | import java.io.IOException;
10 | import org.apache.commons.lang3.StringUtils;
11 | import org.hamcrest.MatcherAssert;
12 | import org.junit.jupiter.api.Test;
13 | import org.requs.XeFacet;
14 |
15 | /**
16 | * Test case for {@link Rules}.
17 | * @since 1.10
18 | */
19 | public final class RulesTest {
20 |
21 | @Test
22 | public void checksInput() throws IOException {
23 | MatcherAssert.assertThat(
24 | new XeFacet.Wrap(new Rules()).touch(
25 | new XMLDocument(
26 | StringUtils.join(
27 | " ",
28 | "User is\ta "human being". ",
29 | " "
30 | )
31 | )
32 | ),
33 | XhtmlMatchers.hasXPaths(
34 | "/spec/errors",
35 | "/spec/errors[count(error)>2]"
36 | )
37 | );
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/sa/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * Static analysis, tests.
8 | *
9 | * @since 1.10
10 | */
11 | package org.requs.facet.sa;
12 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/syntax/ontology/XeFlowTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.aspects.Tv;
8 | import com.jcabi.matchers.XhtmlMatchers;
9 | import org.hamcrest.MatcherAssert;
10 | import org.junit.jupiter.api.Test;
11 | import org.xembly.Directives;
12 | import org.xembly.Xembler;
13 |
14 | /**
15 | * Test case for {@link XeFlow}.
16 | * @since 1.8
17 | */
18 | public final class XeFlowTest {
19 |
20 | @Test
21 | public void manipulatesWithBindings() throws Exception {
22 | final Directives dirs = new Directives().add("f");
23 | final Flow flow = new XeFlow(dirs, "/f");
24 | flow.binding("emp", "Employee");
25 | flow.binding("one", "One");
26 | MatcherAssert.assertThat(
27 | XhtmlMatchers.xhtml(new Xembler(dirs).xml()),
28 | XhtmlMatchers.hasXPaths(
29 | "/f/bindings/binding[name='emp' and type='Employee']",
30 | "/f/bindings/binding[name='one' and type='One']"
31 | )
32 | );
33 | }
34 |
35 | @Test
36 | public void avoidsDuplicateBindings() throws Exception {
37 | final Directives dirs = new Directives().add("f1");
38 | final Flow flow = new XeFlow(dirs, "/f1");
39 | for (int idx = 0; idx < Tv.FIVE; ++idx) {
40 | flow.binding("a", "alpha");
41 | }
42 | MatcherAssert.assertThat(
43 | XhtmlMatchers.xhtml(new Xembler(dirs).xml()),
44 | XhtmlMatchers.hasXPaths(
45 | "/f1/bindings[count(binding)=1]",
46 | "/f1/bindings/binding[name='a' and type='alpha']"
47 | )
48 | );
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/syntax/ontology/XeOntologyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.matchers.XhtmlMatchers;
8 | import org.hamcrest.MatcherAssert;
9 | import org.junit.jupiter.api.Test;
10 | import org.xembly.Xembler;
11 |
12 | /**
13 | * Test case for {@link XeOntology}.
14 | * @since 1.1
15 | */
16 | public final class XeOntologyTest {
17 |
18 | @Test
19 | public void manipulatesWithTypesAndUseCases() throws Exception {
20 | final XeOntology onto = new XeOntology();
21 | final Type type = onto.type("First");
22 | type.explain("first text");
23 | type.parent("Root");
24 | type.slot("one").assign("Emp");
25 | onto.type("Second").explain("second text");
26 | MatcherAssert.assertThat(
27 | XhtmlMatchers.xhtml(new Xembler(onto).xml()),
28 | XhtmlMatchers.hasXPaths(
29 | "/spec",
30 | "/spec/types/type[name='First']",
31 | "/spec/types/type[name='Second']"
32 | )
33 | );
34 | }
35 |
36 | @Test
37 | public void avoidsDuplication() throws Exception {
38 | final XeOntology onto = new XeOntology();
39 | final String name = "Alpha";
40 | onto.type(name);
41 | onto.type(name);
42 | MatcherAssert.assertThat(
43 | XhtmlMatchers.xhtml(new Xembler(onto).xml()),
44 | XhtmlMatchers.hasXPath("/spec/types[count(type)=1]")
45 | );
46 | }
47 |
48 | @Test
49 | public void avoidsDuplicationOfMethods() throws Exception {
50 | final XeOntology onto = new XeOntology();
51 | final String name = "UC3";
52 | onto.method(name);
53 | onto.method(name);
54 | MatcherAssert.assertThat(
55 | XhtmlMatchers.xhtml(new Xembler(onto).xml()),
56 | XhtmlMatchers.hasXPath("/spec/methods[count(method)=1]")
57 | );
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/syntax/ontology/XeSignatureTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.matchers.XhtmlMatchers;
8 | import org.hamcrest.MatcherAssert;
9 | import org.junit.jupiter.api.Test;
10 | import org.xembly.Directives;
11 | import org.xembly.Xembler;
12 |
13 | /**
14 | * Test case for {@link XeSignature}.
15 | * @since 1.8
16 | */
17 | public final class XeSignatureTest {
18 |
19 | @Test
20 | public void signsMethod() throws Exception {
21 | final Directives dirs = new Directives().add("s");
22 | final Signature signature = new XeSignature(dirs, "/s");
23 | signature.sign("\"informal one\"");
24 | MatcherAssert.assertThat(
25 | XhtmlMatchers.xhtml(new Xembler(dirs).xml()),
26 | XhtmlMatchers.hasXPaths(
27 | "/s[signature='\"informal one\"']"
28 | )
29 | );
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/syntax/ontology/XeSlotTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.matchers.XhtmlMatchers;
8 | import org.hamcrest.MatcherAssert;
9 | import org.junit.jupiter.api.Test;
10 | import org.xembly.Directives;
11 | import org.xembly.Xembler;
12 |
13 | /**
14 | * Test case for {@link XeSlot}.
15 | * @since 1.1
16 | */
17 | public final class XeSlotTest {
18 |
19 | @Test
20 | public void manipulatesWithProperty() throws Exception {
21 | final Directives dirs = new Directives().add("p");
22 | final Slot slot = new XeSlot(dirs, "/p");
23 | slot.explain("first text");
24 | slot.explain("second text");
25 | slot.assign("Employee");
26 | slot.mention(2);
27 | slot.mention(1);
28 | MatcherAssert.assertThat(
29 | XhtmlMatchers.xhtml(new Xembler(dirs).xml()),
30 | XhtmlMatchers.hasXPaths(
31 | "/p/info",
32 | "/p/info[informal='first text']",
33 | "/p/info[informal='second text']",
34 | "/p[type='Employee']",
35 | "/p/mentioned[where='2']",
36 | "/p/mentioned[where='1']"
37 | )
38 | );
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/syntax/ontology/XeStepTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.matchers.XhtmlMatchers;
8 | import org.hamcrest.MatcherAssert;
9 | import org.junit.jupiter.api.Test;
10 | import org.xembly.Directives;
11 | import org.xembly.Xembler;
12 |
13 | /**
14 | * Test case for {@link XeStep}.
15 | * @since 1.1
16 | */
17 | public final class XeStepTest {
18 |
19 | @Test
20 | public void manipulatesWithSteps() throws Exception {
21 | final Directives dirs = new Directives().add("s");
22 | final Step step = new XeStep(dirs, "/s");
23 | step.result("data");
24 | step.sign("\"do something\"");
25 | step.object("boom");
26 | step.input("file");
27 | step.input("document");
28 | step.exception("division by zero").step(1).sign("hey!");
29 | step.mention(2);
30 | step.mention(1);
31 | MatcherAssert.assertThat(
32 | XhtmlMatchers.xhtml(new Xembler(dirs).xml()),
33 | XhtmlMatchers.hasXPaths(
34 | "/s[result='data']",
35 | "/s[object='boom']",
36 | "/s/args[count(arg)=2]",
37 | "/s/args[arg='file']",
38 | "/s/args[arg='document']",
39 | "/s[signature='\"do something\"']",
40 | "/s/exceptions/exception[when='division by zero']",
41 | "/s/exceptions/exception/steps/step[signature='hey!']"
42 | )
43 | );
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/syntax/ontology/XeTypeTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.syntax.ontology;
6 |
7 | import com.jcabi.matchers.XhtmlMatchers;
8 | import org.hamcrest.MatcherAssert;
9 | import org.junit.jupiter.api.Test;
10 | import org.xembly.Directives;
11 | import org.xembly.Xembler;
12 |
13 | /**
14 | * Test case for {@link XeType}.
15 | * @since 1.1
16 | */
17 | public final class XeTypeTest {
18 |
19 | @Test
20 | public void manipulatesWithType() throws Exception {
21 | final Directives dirs = new Directives().add("t");
22 | final Type type = new XeType(dirs, "/t");
23 | type.explain("first text");
24 | type.explain("second text");
25 | type.parent("Root");
26 | type.slot("'one").assign("Emp");
27 | type.mention(2);
28 | type.mention(1);
29 | MatcherAssert.assertThat(
30 | XhtmlMatchers.xhtml(new Xembler(dirs).xml()),
31 | XhtmlMatchers.hasXPaths(
32 | "/t/info",
33 | "/t/info[informal='first text']",
34 | "/t/info[informal='second text']",
35 | "/t/parents[type='Root']",
36 | "/t/mentioned[where='2']",
37 | "/t/mentioned[where='1']",
38 | "/t/slots/slot[type='Emp']"
39 | )
40 | );
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/syntax/ontology/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * Ontology, tests.
8 | *
9 | * @since 1.1
10 | */
11 | package org.requs.facet.syntax.ontology;
12 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/syntax/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * Syntax analysis, tests.
8 | */
9 | package org.requs.facet.syntax;
10 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/uml/PlantTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.facet.uml;
6 |
7 | import com.jcabi.matchers.XhtmlMatchers;
8 | import java.io.IOException;
9 | import org.hamcrest.MatcherAssert;
10 | import org.junit.jupiter.api.Test;
11 | import org.junit.jupiter.api.condition.DisabledOnOs;
12 | import org.junit.jupiter.api.condition.OS;
13 |
14 | /**
15 | * Test case for {@link Plant}.
16 | * @since 1.11
17 | */
18 | public final class PlantTest {
19 |
20 | @Test
21 | @DisabledOnOs(OS.WINDOWS)
22 | public void buildsSvg() throws IOException {
23 | MatcherAssert.assertThat(
24 | XhtmlMatchers.xhtml(
25 | Plant.svg("@startuml\nBob -> Alice : hello\n@enduml\n")
26 | ),
27 | XhtmlMatchers.hasXPath("//svg:g")
28 | );
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/facet/uml/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * UML diagrams, tests.
8 | *
9 | * @since 1.11
10 | */
11 | package org.requs.facet.uml;
12 |
--------------------------------------------------------------------------------
/requs-core/src/test/java/org/requs/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * Requs, tests.
8 | */
9 | package org.requs;
10 |
--------------------------------------------------------------------------------
/requs-core/src/test/resources/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Requs-Version: 1.0-SNAPSHOT
2 | Requs-Revision: 12345
3 | Requs-Date: 9-Dec-2012
4 |
--------------------------------------------------------------------------------
/requs-core/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2009-2025, Yegor Bugayenko
2 | # All rights reserved.
3 | #
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions
6 | # are met: 1) Redistributions of source code must retain the above
7 | # copyright notice, this list of conditions and the following
8 | # disclaimer. 2) Redistributions in binary form must reproduce the above
9 | # copyright notice, this list of conditions and the following
10 | # disclaimer in the documentation and/or other materials provided
11 | # with the distribution. 3) Neither the name of the requs.org nor
12 | # the names of its contributors may be used to endorse or promote
13 | # products derived from this software without specific prior written
14 | # permission.
15 | #
16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
18 | # NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
19 | # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 | # THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 | # OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #
30 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
31 | # SPDX-License-Identifier: MIT
32 |
33 | log4j.rootLogger=WARN, CONSOLE
34 |
35 | log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
36 | log4j.appender.CONSOLE.layout=com.jcabi.log.MulticolorLayout
37 | log4j.appender.CONSOLE.layout.ConversionPattern=[%color{%p}] %t %c: %m%n
38 |
39 | log4j.logger.org.requs=WARN
40 |
--------------------------------------------------------------------------------
/requs-core/src/test/resources/org/requs/facet/syntax/all-cases.req:
--------------------------------------------------------------------------------
1 | :UC5 is a must.
2 | :UC3 is delivered.
3 |
4 | "Just a text".
5 |
6 | System is "a simple calculator app".
7 |
8 | Fraction is """a math calculator""".
9 |
10 | Fraction needs:
11 | numerator as Float, and
12 | denominator as Float.
13 |
14 | UC1 where User (a user) divides two numbers:
15 | 1. The user creates Fraction (a fraction);
16 | 2. The fraction calculates Float (a quotient);
17 | 3. The user "receives results" using the quotient.
18 |
19 | UC1/2 when "division by zero":
20 | 1. Fail as """denominator can't be zero""".
21 |
22 | User includes: name, address-s, photo-s?.
23 |
24 | User is a Visitor.
25 |
26 | UC2 where Fraction calculates Float:
27 | "just divide numerator to denominator".
28 |
29 | UC3 where System (a system) archives data:
30 | 1. The system "archives all data";
31 | 2. The user "reads some data" of the file;
32 | 3. The file saves itself in binary form using the encoding and the system.
33 |
34 | UC5 where User reads important information of System:
35 | "this is a multi-line
36 | informal use case".
37 |
38 | UC5/UX must "be amazing for 90% of our users".
39 |
40 | Vision: """
41 | This is Markdown.
42 |
43 | This is also
44 | """.
45 |
--------------------------------------------------------------------------------
/requs-core/src/test/resources/org/requs/facet/syntax/example.req:
--------------------------------------------------------------------------------
1 | :UC1 is a must.
2 |
3 | Fraction is "a math calculator".
4 |
5 | Fraction needs:
6 | numerator as Float, and
7 | denominator as Float.
8 |
9 | UC1 where User (a user) divides two numbers:
10 | 1. The user creates Fraction (a fraction);
11 | 2. The fraction calculates Float (a quotient);
12 | 3. The user "receives results" using the quotient.
13 |
14 | UC1/2 when "division by zero":
15 | 1. Fail as "denominator can't be zero".
16 |
17 | UC1/PRF must "be 500 milliseconds per HTTP request".
18 |
--------------------------------------------------------------------------------
/requs-core/src/test/resources/org/requs/facet/syntax/samples/all-possible-mistakes.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 | Test is "a test".
34 | "This is an informal text"
35 | UC1 where User (a user) saves "a file".
36 | UC1 where another User saves.
37 | " some user saves something"""...
38 |
39 | "duplicate signatures of the same method".
40 | UC5 where User loads file:
41 | 1. User loads.
42 | UC5 where User loads file:
43 | 1. User loads another file.
44 |
45 | "duplicate signatures of the same methods".
46 | UC7 where User loads some file: "something".
47 | UC7 where Customer loads some file: "tbd".
48 |
49 | "duplicate signatures of the different methods".
50 | UC9 where User saves good file: "something".
51 | UC11 where Customer saves good file: "tbd".
52 |
53 | UC1 where System (a system) works:
54 | 1. The system creates Message (a.
55 |
56 | UC76 where User does it:
57 | 1. User creates Message (a.
58 | UC76/1 when "something happens":
59 | 1. User send Message (a message).
60 |
61 |
62 | /spec/errors/error
63 |
64 |
65 |
--------------------------------------------------------------------------------
/requs-core/src/test/resources/org/requs/facet/syntax/samples/nfr.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 | UC1 where User saves file: "empty".
34 | UC1/UX must "be awesome".
35 |
36 |
37 | /spec/errors[not(error)]
38 | /spec/methods[count(method)=1]
39 | //method[id='UC1']
40 | //method/nfrs[count(nfr)=1]
41 | //nfr[id='UX']
42 | //nfr/info[informal='be awesome']
43 |
44 |
45 |
--------------------------------------------------------------------------------
/requs-core/src/test/resources/org/requs/facet/syntax/samples/pages.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 | User is "a human being".
34 | Vision: """ this is a "test" """.
35 |
36 |
37 | /spec/errors[not(error)]
38 | /spec[not(methods)]
39 | /spec/types[count(type)=1]
40 | /spec/pages[count(page)=1]
41 | /spec/pages/page[title='Vision' and info/informal=' this is a "test" ']
42 |
43 |
44 |
--------------------------------------------------------------------------------
/requs-core/src/test/resources/org/requs/facet/syntax/samples/types.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 | User is a "human being".
34 | S3Repo is a "repository".
35 | BmwMPower is a "car".
36 |
37 |
38 | /spec/errors[not(error)]
39 | /spec/types[count(type)=3]
40 |
41 |
42 |
--------------------------------------------------------------------------------
/requs-core/src/test/resources/org/requs/samples/clean-spec.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 | User is a "human being".
34 |
35 | File is a "binary object on disc".
36 |
37 | File includes:
38 | name as "unique text",
39 | content as Binary "that complies to our requirements".
40 |
41 | Binary is "a collection of bytes".
42 |
43 | UC1 where User (a user) saves very complex File (a file):
44 | 1. The user "opens Excel";
45 | 2. The user "clicks SAVE and saves the content" using the file;
46 | 3. The user creates the file;
47 | 4. The user validates the file;
48 | 5. Storage (a storage) reads the user.
49 |
50 | UC2 where User validates File: "we'll define later".
51 |
52 | """This is a comment""".
53 |
54 | Vision: "some **Markdown** document".
55 |
56 | :UC1 is a must.
57 |
58 | UC1/UX must "be cool".
59 |
60 | Storage is an actor.
61 |
62 |
63 | /spec/errors[count(error)=0]
64 |
65 |
66 |
--------------------------------------------------------------------------------
/requs-core/src/test/resources/org/requs/samples/empty-input.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 | /processing-instruction()[contains(.,'href')]
35 | /spec/errors[count(error)=0]
36 |
37 |
38 |
--------------------------------------------------------------------------------
/requs-core/src/test/resources/org/requs/samples/exceptions.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 | UC1 where User (a user) works:
34 | 1. The user creates;
35 | 2. Fail as "it doesn't work";
36 | 3. The user reads.
37 | UC1/1 when "something goes wrong":
38 | 1. Fail as "something went wrong".
39 | UC1/2 when "something goes wrong":
40 | 1. "Do something else".
41 |
42 |
43 | /processing-instruction()[contains(.,'href')]
44 | /spec/errors[count(error)=3]
45 |
46 |
47 |
--------------------------------------------------------------------------------
/requs-core/src/test/resources/org/requs/samples/order-of-steps.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 | UC1 where User (a user) works:
34 | 1. The user creates;
35 | 3. The user reads;
36 | 2. The user updates.
37 | UC2 where User (a user) works again:
38 | 1. The user creates;
39 | 2. The user reads;
40 | 3. The user reads;
41 | 4. The user reads;
42 | 5. The user reads;
43 | 6. The user reads;
44 | 7. The user reads;
45 | 8. The user reads;
46 | 9. The user reads;
47 | 10. The user reads.
48 |
49 |
50 | /processing-instruction()[contains(.,'href')]
51 | /spec/errors[count(error)=4]
52 |
53 |
54 |
--------------------------------------------------------------------------------
/requs-core/src/test/resources/org/requs/samples/wrong-steps-numbering.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 | UC1 where User (a user) works:
34 | 1. The user creates;
35 | 2. The user reads;
36 | 5. The user updates.
37 |
38 |
39 | /spec/errors[count(error)=1]
40 |
41 |
42 |
--------------------------------------------------------------------------------
/requs-exec/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2009-2025, Yegor Bugayenko
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions
6 | are met: 1) Redistributions of source code must retain the above
7 | copyright notice, this list of conditions and the following
8 | disclaimer. 2) Redistributions in binary form must reproduce the above
9 | copyright notice, this list of conditions and the following
10 | disclaimer in the documentation and/or other materials provided
11 | with the distribution. 3) Neither the name of the requs.org nor
12 | the names of its contributors may be used to endorse or promote
13 | products derived from this software without specific prior written
14 | permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
18 | NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 | THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 | OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/requs-exec/src/it/compiles-simple-syntax/invoker.properties:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 |
4 | invoker.goals = test
5 |
--------------------------------------------------------------------------------
/requs-exec/src/it/compiles-simple-syntax/requs-src/input.req:
--------------------------------------------------------------------------------
1 | Fraction is a "math calculator".
2 |
3 | Fraction needs:
4 | numerator as Float, and
5 | denominator as Float.
6 |
7 | UC1 where User (a user) divides two numbers:
8 | 1. The user creates Fraction (a fraction);
9 | 2. The fraction "calculates" Float (a quotient);
10 | 3. The user "receives results" using the quotient.
11 |
12 | UC1/2 when "division by zero":
13 | 1. Fail as "denominator can't be zero".
14 |
15 | UC1/UX must "look amazing".
16 |
--------------------------------------------------------------------------------
/requs-exec/src/it/compiles-simple-syntax/verify.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | import com.jcabi.matchers.XhtmlMatchers
7 | import org.hamcrest.MatcherAssert
8 |
9 | def xml = new File(basedir, 'target/requs/requs.xml')
10 | if (!xml.exists()) {
11 | throw new IllegalStateException(
12 | 'XML was not generated at ' + xml
13 | )
14 | }
15 | MatcherAssert.assertThat(
16 | XhtmlMatchers.xhtml(xml.text),
17 | XhtmlMatchers.hasXPaths(
18 | '/spec/types/type[name="Fraction"]',
19 | '/spec/types/type[name="User"]'
20 | )
21 | )
22 |
--------------------------------------------------------------------------------
/requs-exec/src/it/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 | it-repo
35 |
36 | true
37 |
38 |
39 |
40 | local.central
41 | @localRepositoryUrl@
42 |
43 | true
44 |
45 |
46 | true
47 |
48 |
49 |
50 |
51 |
52 | local.central
53 | @localRepositoryUrl@
54 |
55 | true
56 |
57 |
58 | true
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/requs-exec/src/main/assembly/bin.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 | bin
33 | false
34 |
35 | jar
36 |
37 |
38 |
39 | ${project.build.outputDirectory}
40 | /
41 |
42 |
43 |
44 |
45 | false
46 |
47 |
48 | true
49 | runtime
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/requs-exec/src/main/java/org/requs/exec/Main.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.exec;
6 |
7 | import com.jcabi.manifests.Manifests;
8 | import java.io.File;
9 | import java.io.IOException;
10 | import java.io.PrintStream;
11 | import java.nio.charset.StandardCharsets;
12 | import joptsimple.OptionParser;
13 | import joptsimple.OptionSet;
14 | import org.apache.commons.io.IOUtils;
15 |
16 | /**
17 | * Entry point of the JAR.
18 | *
19 | * @since 1.1
20 | * @checkstyle MultipleStringLiteralsCheck (500 lines)
21 | */
22 | public final class Main {
23 |
24 | /**
25 | * Private ctor, to avoid instantiation of this class.
26 | */
27 | private Main() {
28 | // intentionally empty
29 | }
30 |
31 | /**
32 | * Entry point of the entire JAR.
33 | * @param args List of command-line arguments
34 | * @throws IOException If something goes wrong inside
35 | */
36 | @SuppressWarnings("PMD.ProhibitPublicStaticMethods")
37 | public static void main(final String... args) throws IOException {
38 | final OptionParser parser = new OptionParser("h*vi:o:");
39 | final PrintStream out = System.out;
40 | parser.posixlyCorrect(true);
41 | final OptionSet options = parser.parse(args);
42 | if (options.has("v")) {
43 | IOUtils.write(
44 | String.format(
45 | "%s/%s",
46 | Manifests.read("Requs-Version"),
47 | Manifests.read("Requs-Revision")
48 | ),
49 | out,
50 | StandardCharsets.UTF_8
51 | );
52 | } else if (options.has("i") && options.has("o")) {
53 | new org.requs.Compiler(
54 | new File(options.valueOf("i").toString()),
55 | new File(options.valueOf("o").toString())
56 | ).compile();
57 | } else {
58 | out.println("Usage: java -jar requs-exec.jar [options]");
59 | out.println("where options include:\n");
60 | parser.printHelpOn(out);
61 | }
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/requs-exec/src/main/java/org/requs/exec/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * Command Line Interface (CLI) classes.
8 | */
9 | package org.requs.exec;
10 |
--------------------------------------------------------------------------------
/requs-exec/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2009-2025, Yegor Bugayenko
2 | # All rights reserved.
3 | #
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions
6 | # are met: 1) Redistributions of source code must retain the above
7 | # copyright notice, this list of conditions and the following
8 | # disclaimer. 2) Redistributions in binary form must reproduce the above
9 | # copyright notice, this list of conditions and the following
10 | # disclaimer in the documentation and/or other materials provided
11 | # with the distribution. 3) Neither the name of the requs.org nor
12 | # the names of its contributors may be used to endorse or promote
13 | # products derived from this software without specific prior written
14 | # permission.
15 | #
16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
18 | # NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
19 | # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 | # THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 | # OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #
30 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
31 | # SPDX-License-Identifier: MIT
32 |
33 | log4j.rootLogger=WARN, CONSOLE
34 |
35 | log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
36 | log4j.appender.CONSOLE.layout=com.jcabi.log.MulticolorLayout
37 | log4j.appender.CONSOLE.layout.ConversionPattern=[%color{%p}] %t %c: %m%n
38 | log4j.logger.org.requs=INFO
39 |
--------------------------------------------------------------------------------
/requs-exec/src/test/java/org/requs/exec/MainTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.exec;
6 |
7 | import com.jcabi.matchers.XhtmlMatchers;
8 | import java.io.ByteArrayOutputStream;
9 | import java.io.File;
10 | import java.io.PrintStream;
11 | import java.nio.charset.StandardCharsets;
12 | import java.nio.file.Path;
13 | import org.apache.commons.io.FileUtils;
14 | import org.hamcrest.MatcherAssert;
15 | import org.hamcrest.Matchers;
16 | import org.junit.jupiter.api.AfterEach;
17 | import org.junit.jupiter.api.BeforeEach;
18 | import org.junit.jupiter.api.Test;
19 | import org.junit.jupiter.api.io.TempDir;
20 |
21 | /**
22 | * Test case for {@link Main}.
23 | * @since 1.1
24 | */
25 | public final class MainTest {
26 |
27 | /**
28 | * Output stream for tests.
29 | */
30 | private transient ByteArrayOutputStream out;
31 |
32 | @BeforeEach
33 | public void changeSystemOutputSteam() throws Exception {
34 | this.out = new ByteArrayOutputStream();
35 | System.setOut(new PrintStream(this.out, true));
36 | }
37 |
38 | @AfterEach
39 | public void revertChangedSystemOutputStream() throws Exception {
40 | System.setOut(null);
41 | }
42 |
43 | @Test
44 | public void displaysVersionNumber() throws Exception {
45 | Main.main(new String[]{"-v"});
46 | MatcherAssert.assertThat(
47 | this.out.toString(),
48 | Matchers.containsString("-SNAPSHOT")
49 | );
50 | }
51 |
52 | @Test
53 | public void rendersHelpMessage() throws Exception {
54 | Main.main(new String[] {"-h"});
55 | MatcherAssert.assertThat(
56 | this.out.toString(),
57 | Matchers.containsString("Usage:")
58 | );
59 | }
60 |
61 | @Test
62 | public void compilesRequsSources(@TempDir final Path temp) throws Exception {
63 | final File input = temp.resolve("input").toFile();
64 | final File output = temp.resolve("output").toFile();
65 | FileUtils.write(
66 | new File(input, "employee.req"),
67 | "Employee is a \"user of the system\".",
68 | StandardCharsets.UTF_8
69 | );
70 | Main.main(
71 | new String[] {
72 | "-i", input.getAbsolutePath(),
73 | "-o", output.getAbsolutePath(),
74 | }
75 | );
76 | MatcherAssert.assertThat(
77 | this.out.toString(),
78 | Matchers.containsString("compiled and saved to")
79 | );
80 | MatcherAssert.assertThat(
81 | XhtmlMatchers.xhtml(
82 | FileUtils.readFileToString(
83 | new File(output, "requs.xml"),
84 | StandardCharsets.UTF_8
85 | )
86 | ),
87 | XhtmlMatchers.hasXPaths("/spec/types/type[name='Employee']")
88 | );
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/requs-exec/src/test/java/org/requs/exec/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * Command Line Interface (CLI) classes, tests.
8 | */
9 | package org.requs.exec;
10 |
--------------------------------------------------------------------------------
/requs-exec/src/test/resources/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Requs-Version: 1.0-SNAPSHOT
2 | Requs-Revision: 1a2b3e4f
3 | Requs-Date: 1-Jan-2017
4 |
--------------------------------------------------------------------------------
/requs-exec/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2009-2025, Yegor Bugayenko
2 | # All rights reserved.
3 | #
4 | # Redistribution and use in source and binary forms, with or without
5 | # modification, are permitted provided that the following conditions
6 | # are met: 1) Redistributions of source code must retain the above
7 | # copyright notice, this list of conditions and the following
8 | # disclaimer. 2) Redistributions in binary form must reproduce the above
9 | # copyright notice, this list of conditions and the following
10 | # disclaimer in the documentation and/or other materials provided
11 | # with the distribution. 3) Neither the name of the requs.org nor
12 | # the names of its contributors may be used to endorse or promote
13 | # products derived from this software without specific prior written
14 | # permission.
15 | #
16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
18 | # NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
19 | # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 | # THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 | # OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 | #
30 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
31 | # SPDX-License-Identifier: MIT
32 |
33 | log4j.rootLogger=WARN, CONSOLE
34 |
35 | log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
36 | log4j.appender.CONSOLE.layout=com.jcabi.log.MulticolorLayout
37 | log4j.appender.CONSOLE.layout.ConversionPattern=[%color{%p}] %t %c: %m%n
38 |
39 | log4j.logger.org.requs=INFO
40 |
--------------------------------------------------------------------------------
/requs-maven-plugin/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2009-2025, Yegor Bugayenko
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions
6 | are met: 1) Redistributions of source code must retain the above
7 | copyright notice, this list of conditions and the following
8 | disclaimer. 2) Redistributions in binary form must reproduce the above
9 | copyright notice, this list of conditions and the following
10 | disclaimer in the documentation and/or other materials provided
11 | with the distribution. 3) Neither the name of the requs.org nor
12 | the names of its contributors may be used to endorse or promote
13 | products derived from this software without specific prior written
14 | permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
18 | NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 | THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 | OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/absent-input-dir/invoker.properties:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 |
4 | invoker.goals = compile
5 | invoker.buildResult = success
6 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/absent-input-dir/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 | 4.0.0
33 | org.requs
34 | requs-test
35 | 2.0-SNAPSHOT
36 | absent-input-dir
37 |
38 |
39 |
40 | org.requs
41 | requs-maven-plugin
42 | @project.version@
43 |
44 |
45 |
46 | compile
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/broken-spec/invoker.properties:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 |
4 | invoker.goals = compile
5 | invoker.buildResult = failure
6 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/broken-spec/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 | 4.0.0
33 | org.requs
34 | requs-test
35 | 2.0-SNAPSHOT
36 | broken-facet
37 |
38 |
39 |
40 | org.requs
41 | requs-maven-plugin
42 | @project.version@
43 |
44 |
45 |
46 | compile
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/broken-spec/src/main/requs/input.req:
--------------------------------------------------------------------------------
1 | Fraction is a math calculator.
2 |
3 | Fraction needs some data.
4 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/broken-spec/verify.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | import com.jcabi.matchers.XhtmlMatchers
7 | import org.hamcrest.MatcherAssert
8 | import org.hamcrest.Matchers
9 |
10 | def log = new File(basedir, 'build.log')
11 | MatcherAssert.assertThat(
12 | log.text,
13 | Matchers.containsString(' requs error(s)')
14 | )
15 | def xml = new File(basedir, 'target/requs/requs.xml')
16 | if (!xml.exists()) {
17 | throw new IllegalStateException(
18 | 'XML was not generated at ' + xml
19 | )
20 | }
21 | MatcherAssert.assertThat(
22 | XhtmlMatchers.xhtml(xml.text),
23 | XhtmlMatchers.hasXPaths(
24 | '/spec/types/type[name="Fraction"]',
25 | '/spec/errors/error'
26 | )
27 | )
28 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/report-in-site/invoker.properties:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 |
4 | invoker.goals = site
5 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/report-in-site/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 | 4.0.0
33 | org.requs
34 | requs-test
35 | 2.0-SNAPSHOT
36 | report-in-site
37 |
38 |
39 |
40 | org.requs
41 | requs-maven-plugin
42 | @project.version@
43 |
44 |
45 |
46 |
47 |
48 |
49 | org.requs
50 | requs-maven-plugin
51 | @project.version@
52 |
53 |
54 | maven-site-plugin
55 | 3.9.1
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/report-in-site/src/main/requs/input.req:
--------------------------------------------------------------------------------
1 | Fraction is a "math calculator".
2 |
3 | Fraction needs:
4 | numerator as Float, and
5 | denominator as Float.
6 |
7 | UC1 where User (a user) divides two numbers:
8 | 1. The user creates Fraction (a fraction);
9 | 2. The fraction "calculates" Float (a quotient);
10 | 3. The user "receives results" using the quotient.
11 |
12 | UC1/2 when "division by zero":
13 | 1. Fail as "denominator can't be zero".
14 |
15 | UC1/MTBF must "be 3 minutes".
16 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/report-in-site/verify.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | def index = new File(basedir, 'target/site/requs.html')
7 | if (!index.exists()) {
8 | throw new IllegalStateException(
9 | 'Index was not generated at ' + index
10 | )
11 | }
12 | if (!index.text.contains('SRS')) {
13 | throw new IllegalStateException(
14 | 'SRS is not in the index ' + index
15 | )
16 | }
17 |
18 | def dir = new File(basedir, 'target/site/requs')
19 | if (!dir.exists()) {
20 | throw new IllegalStateException(
21 | 'Report was not generated at ' + dir
22 | )
23 | }
24 | if (!dir.isDirectory()) {
25 | throw new IllegalStateException(
26 | 'Report is not a directory: ' + dir
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
34 | it-repo
35 |
36 | true
37 |
38 |
39 |
40 | local.central
41 | @localRepositoryUrl@
42 |
43 | true
44 |
45 |
46 | true
47 |
48 |
49 |
50 |
51 |
52 | local.central
53 | @localRepositoryUrl@
54 |
55 | true
56 |
57 |
58 | true
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/simple-compile/invoker.properties:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | # SPDX-License-Identifier: MIT
3 |
4 | invoker.goals = compile
5 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/simple-compile/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 | 4.0.0
33 | org.requs
34 | requs-test
35 | 2.0-SNAPSHOT
36 | simple-read
37 |
38 |
39 |
40 | org.requs
41 | requs-maven-plugin
42 | @project.version@
43 |
44 |
45 |
46 | compile
47 |
48 |
49 |
50 | hello
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/simple-compile/src/main/requs/input.req:
--------------------------------------------------------------------------------
1 | Float is "a number".
2 |
3 | Fraction is "a math calculator".
4 |
5 | Fraction needs:
6 | numerator as Float, and
7 | denominator as Float.
8 | UC1 where User (a user) divides two numbers:
9 | 1. The user creates Fraction (a fraction);
10 | 2. The fraction "calculates" Float (a quotient);
11 | 3. The user "receives results" using the quotient.
12 |
13 | UC1/2 when "division by zero":
14 | 1. The user "gets notification";
15 | 2. Fail as "denominator can't be zero".
16 |
17 | UC1/PERF must "be 500 millisecond per request".
18 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/it/simple-compile/verify.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | import com.jcabi.matchers.XhtmlMatchers
7 | import org.hamcrest.MatcherAssert
8 |
9 | def xml = new File(basedir, 'target/requs/requs.xml')
10 | if (!xml.exists()) {
11 | throw new IllegalStateException(
12 | 'XML was not generated at ' + xml
13 | )
14 | }
15 | MatcherAssert.assertThat(
16 | XhtmlMatchers.xhtml(xml.text),
17 | XhtmlMatchers.hasXPaths(
18 | '/spec/types/type[name="Fraction"]',
19 | '/spec/types/type[name="User"]'
20 | )
21 | )
22 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/main/java/org/requs/maven/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * The requs-maven-plugin.
8 | *
9 | * @since 1.1
10 | */
11 | package org.requs.maven;
12 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/test/java/org/requs/maven/CompileMojoTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.maven;
6 |
7 | import org.junit.jupiter.api.Test;
8 |
9 | /**
10 | * Test case for {@link CompileMojo}.
11 |
12 | * @since 1.0
13 | */
14 | public final class CompileMojoTest {
15 |
16 | /**
17 | * CompileMojo can work.
18 | * @throws Exception If fails
19 | */
20 | @Test
21 | public void testMojoGoal() throws Exception {
22 | // todo
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/test/java/org/requs/maven/ReportMojoTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 | package org.requs.maven;
6 |
7 | import org.junit.jupiter.api.Test;
8 |
9 | /**
10 | * Test case for {@link ReportMojo}.
11 | *
12 | * @since 1.0
13 | */
14 | public class ReportMojoTest {
15 |
16 | /**
17 | * ReportMojo can work.
18 | * @throws Exception If fails
19 | */
20 | @Test
21 | public void testMojoReportGoal() throws Exception {
22 | // todo
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/requs-maven-plugin/src/test/java/org/requs/maven/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
3 | * SPDX-License-Identifier: MIT
4 | */
5 |
6 | /**
7 | * The requs-maven-plugin, tests.
8 | */
9 | package org.requs.maven;
10 |
--------------------------------------------------------------------------------
/requs_pygment/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | requs_pygment.egg-info
3 |
--------------------------------------------------------------------------------
/requs_pygment/requs_pygment.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
4 | # SPDX-License-Identifier: MIT
5 |
6 | from pygments.lexer import RegexLexer
7 | from pygments.token import Punctuation, Text, Keyword, Name, String, Operator
8 | from pygments.util import shebang_matches
9 |
10 |
11 | class RequsLexer(RegexLexer):
12 | name = 'requs'
13 | aliases = ['requs']
14 | tokens = {
15 | 'root': [
16 | (r'"""[\n.]+"""', Text),
17 | (r'"[^"]+"', String),
18 | (
19 | r'\b(includes|requires|contains|actor|needs|means|using|of|with|when|must|is|a|(T|t)he|as|where|and)\b',
20 | Keyword,
21 | ),
22 | (r'\b(creates|reads|updates|deletes|Fail\s+since)\b', Operator),
23 | (r'\b[A-Z]+\b', Name),
24 | (r'\b([A-Z][a-z0-9]*)+\b', Name),
25 | (r'[,;:]', Punctuation),
26 | ],
27 | }
28 |
29 | def analyse_text(text):
30 | return shebang_matches(text, r'requs')
31 |
--------------------------------------------------------------------------------
/requs_pygment/setup.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
4 | # SPDX-License-Identifier: MIT
5 |
6 | from setuptools import setup, find_packages
7 |
8 | setup(
9 | name='requs_pygment',
10 | version='0.1',
11 | packages=find_packages(),
12 | install_requires=['pygments'],
13 | py_modules=['requs_pygment'],
14 | author='Yegor Bugayenko',
15 | author_email='yegor256@gmail.com',
16 | description='Requs Highlighting Pygment',
17 | license='BSD',
18 | keywords='requs',
19 | url='http://www.requs.org/',
20 | entry_points={
21 | 'pygments.lexers': [
22 | 'requs = requs_pygment:RequsLexer'
23 | ]
24 | }
25 | )
26 |
--------------------------------------------------------------------------------
/sdd/.gitignore:
--------------------------------------------------------------------------------
1 | *.bbl
2 | *.bcf
3 | *.blg
4 | *.fdb_latexmk
5 | _minted-*
6 | *.fls
7 | *.log
8 | *.run.xml
9 | *.aux
10 | *.pyg
11 | *.out
12 | wp.pdf
13 |
--------------------------------------------------------------------------------
/sdd/.latexmkrc:
--------------------------------------------------------------------------------
1 | $pdflatex = 'pdflatex %O --shell-escape %S';
2 |
3 | $success_cmd = 'texqc && texsc';
4 |
--------------------------------------------------------------------------------
/sdd/README.md:
--------------------------------------------------------------------------------
1 | To build it you need to have LaTeX, GNU aspell,
2 | [texqc](https://github.com/yegor256/texqc),
3 | and
4 | [texsc](https://github.com/yegor256/texsc) installed.
5 | Then, just do this:
6 |
7 | ```bash
8 | $ latexmk -pdf
9 | ```
10 |
11 | Everything will be built just fine and you will get the `.pdf` file.
12 |
--------------------------------------------------------------------------------
/sdd/logo.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yegor256/requs/925dd42328c55fa610d8bd3f79898887a21456a3/sdd/logo.pdf
--------------------------------------------------------------------------------
/sdd/sdd.bib:
--------------------------------------------------------------------------------
1 | % SPDX-FileCopyrightText: Copyright (c) 2009-2025, Yegor Bugayenko
2 | % SPDX-License-Identifier: MIT
3 |
4 | @techreport{mof2,
5 | Author = {Object Management Group},
6 | Institution = {Object Management Group},
7 | Month = {January},
8 | Number = {formal/06-01-01},
9 | Title = {Meta Object Facility {(MOF)} Core Specification, version 2.0},
10 | Year = {2006}}
11 |
12 | @book{shapiro94,
13 | Author = {Ehud Shapiro and Sterling, Leon},
14 | Publisher = {{The MIT Press}},
15 | Title = {The Art of {PROLOG}: Advanced Programming Techniques},
16 | Year = {1994}}
17 |
18 | @webpage{xml,
19 | Author = {Tim Bray and Jean Paoli and C. M. Sperberg-McQueen and Eve Maler and Fran{\c c}ois Yergeau},
20 | Date-Added = {2010-01-08 11:36:30 +0100},
21 | Date-Modified = {2010-07-23 18:01:48 +0200},
22 | Keywords = {XML},
23 | Month = {November},
24 | Read = {Yes},
25 | Title = {Extensible Markup Language {(XML)} 1.0 (Fifth Edition)},
26 | Url = {http://www.w3.org/TR/2008/REC-xml-20081126/},
27 | Urldate = {3/4/09},
28 | Year = {2008},
29 | Bdsk-Url-1 = {http://www.w3.org/TR/2008/REC-xml-20081126/}}
30 |
31 | @book{graham93,
32 | Author = {Paul Graham},
33 | Publisher = {{Prentice Hall}},
34 | Title = {On {LISP}: Advanced Techniques for Common {LISP}},
35 | Year = {1993}}
36 |
37 | @techreport{mof-to-xmi,
38 | Author = {OMG},
39 | Institution = {Object Management Group},
40 | Title = {{MOF} 2.0/{XMI} Mapping, Version 2.1.1},
41 | Year = {2007}}
42 |
43 | @techreport{ieee830,
44 | Author = {IEEE},
45 | Institution = {The Institute of Electrical and Electronics Engineers},
46 | Number = {IEEE Std 830-1998},
47 | Title = {Recommended Practice for Software Requirements Specifications},
48 | Year = {1998}}
49 |
--------------------------------------------------------------------------------
/sdd/sdd.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yegor256/requs/925dd42328c55fa610d8bd3f79898887a21456a3/sdd/sdd.pdf
--------------------------------------------------------------------------------