├── .editorconfig
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── composer.json
├── phpcs.xml.dist
├── phpstan.neon.dist
├── phpunit.xml.dist
├── src
├── Declaration
│ ├── BooleanDeclaration.php
│ ├── Charset.php
│ ├── Declaration.php
│ ├── EndOfLine.php
│ ├── Factory.php
│ ├── GenericDeclaration.php
│ ├── IndentSize.php
│ ├── IndentStyle.php
│ ├── InsertFinalNewline.php
│ ├── MaxLineLength.php
│ ├── TabWidth.php
│ ├── TrimTrailingWhitespace.php
│ └── UnsetDeclaration.php
├── EditorConfig.php
├── EditorConfigFile.php
├── Exception
│ └── InvalidValue.php
└── Section.php
└── tests
├── Declaration
├── CharsetTest.php
├── EndOfLineTest.php
├── FactoryTest.php
├── GenericDeclarationTest.php
├── IndentSizeTest.php
├── IndentStyleTest.php
├── InsertFinalNewlineTest.php
├── MaxLineLengthTest.php
├── TabWidthTest.php
├── TrimTrailingWhitespaceTest.php
└── UnsetDeclarationTest.php
├── EditorConfigFileTest.php
├── EditorConfigTest.php
├── SectionTest.php
└── data
├── .editorconfig
├── editorconfig
├── empty_editorconfig
├── invalid_editorconfig
├── invalid_root_editorconfig
├── lib
└── test.js
├── root_editorconfig
├── test.json
├── test.yml
└── testfile.php
/.editorconfig:
--------------------------------------------------------------------------------
1 | root=true
2 | [*]
3 | end_of_line = lf
4 | insert_final_newline = true
5 | trim_trailing_whitespace = true
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 4
9 |
10 | [*.md]
11 | trim_trailing_whitespace = false
12 |
13 | [*.{yaml,yml,js,json,json.dist,feature}]
14 | indent_size = 2
15 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 |
11 | jobs:
12 | phpstan:
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - uses: actions/checkout@v2
17 |
18 | - uses: php-actions/composer@v5
19 | with:
20 | php_version: 7.3
21 |
22 | - name: PHPStan Static Analysis
23 | uses: php-actions/phpstan@v2
24 | with:
25 | php_version: 7.3
26 | configuration: phpstan.neon.dist
27 |
28 | phpunit:
29 | runs-on: ubuntu-latest
30 |
31 | steps:
32 | - uses: actions/checkout@v2
33 |
34 | - uses: php-actions/composer@v5
35 | with:
36 | php_version: 7.3
37 |
38 | - name: Run PHPUnit tests
39 | uses: php-actions/phpunit@v2
40 | with:
41 | version: 9.5
42 | php_version: 7.3
43 | configuration: phpunit.xml.dist
44 |
45 | phpcs:
46 | runs-on: ubuntu-latest
47 |
48 | steps:
49 | - uses: actions/checkout@v2
50 |
51 | - name: Setup PHP Action
52 | uses: shivammathur/setup-php@2.11.0
53 | with:
54 | php-version: '7.3'
55 |
56 | - name: Cache Composer packages
57 | id: composer-cache
58 | uses: actions/cache@v2
59 | with:
60 | path: vendor
61 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
62 | restore-keys: |
63 | ${{ runner.os }}-php-
64 |
65 | - name: Install composer packages
66 | run: |
67 | composer install --prefer-dist --no-progress
68 |
69 | - name: Run phpcs
70 | run: |
71 | bin/phpcs
72 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .phpcs-cache
2 | .phpunit.result.cache
3 | composer.lock
4 | phpunit.xml
5 | /bin/
6 | /build/
7 | /vendor/
8 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes to this project will be documented in this file.
3 |
4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6 |
7 |
8 | ## [0.1.3] - 2021-06-02
9 | ### Fixed
10 | - Fixed issues with globbing files on Windows
11 |
12 | ## [0.1.2] - 2021-05-31
13 | ### Fixed
14 | - Updated dependencies
15 | - Dev dependencies now support PHP8
16 |
17 | ## [0.1.1] - 2021-05-03
18 | ### Changed
19 | - Validation for rules is now case-insensitive
20 |
21 | ### Fixed
22 | - Supports comments beginning with #
23 | - Better support for curly braces in editorconfig rules
24 |
25 | ## [0.1.0] - 2019-12-04
26 | Initial Release
27 | ### Added
28 | - Resolves editor settings for file/path
29 | - Prints resolved editor settings
30 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | ISC License
2 |
3 | Copyright (c) 2019 Jason Silkey
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any
6 | purpose with or without fee is hereby granted, provided that the above
7 | copyright notice and this permission notice appear in all copies.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EditorConfig PHP
2 | PHP implementation of [EditorConfig](https://editorconfig.org)
3 |
4 | ## Installation
5 |
6 | Install with [Composer](https://getcomposer.org):
7 |
8 | ```
9 | composer require idiosyncratic/editorconfig
10 | ```
11 |
12 | ## Usage
13 |
14 | ```php
15 | getConfigForPath(__FILE__);
25 |
26 | // Print matching configuration rules as string
27 | print $ec->printConfigForPath(__FILE__) . PHP_EOL;
28 | ```
29 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "idiosyncratic/editorconfig",
3 | "description": "PHP implementation of EditorConfig",
4 | "type": "library",
5 | "license": "ISC",
6 | "authors": [
7 | {
8 | "name": "Jason Silkey",
9 | "email": "jason@jasonsilkey.com"
10 | }
11 | ],
12 | "require": {
13 | "php": ">=7.3"
14 | },
15 | "require-dev": {
16 | "idiosyncratic/coding-standard": "^2.0",
17 | "php-parallel-lint/php-console-highlighter": "^0.5",
18 | "php-parallel-lint/php-parallel-lint": "^1.3",
19 | "phploc/phploc": "^7.0",
20 | "phpstan/phpstan": "^0.12",
21 | "phpunit/phpunit": "^9.5",
22 | "sebastian/phpcpd": "^6.0"
23 | },
24 | "minimum-stability": "dev",
25 | "prefer-stable": true,
26 | "config": {
27 | "preferred-install": "dist",
28 | "sort-packages": true,
29 | "optimize-autoloader": true,
30 | "discard-changes": true,
31 | "bin-dir" : "bin"
32 | },
33 | "autoload": {
34 | "psr-4": {
35 | "Idiosyncratic\\EditorConfig\\": "src"
36 | }
37 | },
38 | "autoload-dev": {
39 | "psr-4": {
40 | "Idiosyncratic\\EditorConfig\\": "tests"
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/phpcs.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | src
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/phpstan.neon.dist:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 7
3 | paths:
4 | - src
5 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 | ./src
19 |
20 |
21 |
22 |
23 | ./tests
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/Declaration/BooleanDeclaration.php:
--------------------------------------------------------------------------------
1 | getStringValue(),
21 | $this->getName()
22 | );
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Declaration/Charset.php:
--------------------------------------------------------------------------------
1 | getStringValue(),
31 | $this->getName()
32 | );
33 | }
34 | }
35 |
36 | public function getName() : string
37 | {
38 | return 'charset';
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Declaration/Declaration.php:
--------------------------------------------------------------------------------
1 | getTypedValue($value);
26 |
27 | $this->setStringValue($value);
28 |
29 | $this->validateValue($typedValue);
30 |
31 | $this->setValue($typedValue);
32 | }
33 |
34 | public function getName() : string
35 | {
36 | return $this->name;
37 | }
38 |
39 | /**
40 | * @return mixed
41 | */
42 | final public function getValue()
43 | {
44 | return $this->value;
45 | }
46 |
47 | final public function getStringValue() : string
48 | {
49 | return $this->stringValue;
50 | }
51 |
52 | /**
53 | * @param mixed $value
54 | */
55 | public function validateValue($value) : void
56 | {
57 | return;
58 | }
59 |
60 | final public function __toString() : string
61 | {
62 | return sprintf('%s=%s', $this->getName(), $this->getStringValue());
63 | }
64 |
65 | protected function setName(string $name) : void
66 | {
67 | $this->name = strtolower($name);
68 | }
69 |
70 | /**
71 | * @return mixed
72 | */
73 | protected function getTypedValue(string $value)
74 | {
75 | if (in_array($value, ['true', 'false']) === true) {
76 | return $value === 'true';
77 | }
78 |
79 | if (is_numeric($value) === true && (string) (int) $value === $value) {
80 | return (int) $value;
81 | }
82 |
83 | return $value;
84 | }
85 |
86 | final protected function setStringValue(string $value) : void
87 | {
88 | $this->stringValue = $value;
89 | }
90 |
91 | /**
92 | * @param mixed $value
93 | */
94 | final protected function setValue($value) : void
95 | {
96 | $this->value = $value;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/Declaration/EndOfLine.php:
--------------------------------------------------------------------------------
1 | getStringValue(),
29 | $this->getName()
30 | );
31 | }
32 | }
33 |
34 | public function getName() : string
35 | {
36 | return 'end_of_line';
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Declaration/Factory.php:
--------------------------------------------------------------------------------
1 | $method($value);
27 | }
28 |
29 | return new GenericDeclaration($name, $value);
30 | }
31 |
32 | /**
33 | * @param mixed $value
34 | */
35 | public function getIndentStyle($value) : IndentStyle
36 | {
37 | return new IndentStyle($value);
38 | }
39 |
40 | /**
41 | * @param mixed $value
42 | */
43 | public function getCharset($value) : Charset
44 | {
45 | return new Charset($value);
46 | }
47 |
48 | /**
49 | * @param mixed $value
50 | */
51 | public function getEndOfLine($value) : EndOfLine
52 | {
53 | return new EndOfLine($value);
54 | }
55 |
56 | /**
57 | * @param mixed $value
58 | */
59 | public function getInsertFinalNewline($value) : InsertFinalNewline
60 | {
61 | return new InsertFinalNewline($value);
62 | }
63 |
64 | /**
65 | * @param mixed $value
66 | */
67 | public function getTrimTrailingWhitespace($value) : TrimTrailingWhitespace
68 | {
69 | return new TrimTrailingWhitespace($value);
70 | }
71 |
72 | /**
73 | * @param mixed $value
74 | */
75 | public function getIndentSize($value) : IndentSize
76 | {
77 | return new IndentSize($value);
78 | }
79 |
80 | /**
81 | * @param mixed $value
82 | */
83 | public function getTabWidth($value) : TabWidth
84 | {
85 | return new TabWidth($value);
86 | }
87 |
88 | /**
89 | * @param mixed $value
90 | */
91 | public function getMaxLineLength($value) : MaxLineLength
92 | {
93 | return new MaxLineLength($value);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/Declaration/GenericDeclaration.php:
--------------------------------------------------------------------------------
1 | setName($name);
12 |
13 | parent::__construct($value);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Declaration/IndentSize.php:
--------------------------------------------------------------------------------
1 | getStringValue(),
26 | $this->getName()
27 | );
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Declaration/IndentStyle.php:
--------------------------------------------------------------------------------
1 | getStringValue(),
28 | $this->getName()
29 | );
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Declaration/InsertFinalNewline.php:
--------------------------------------------------------------------------------
1 | getStringValue(),
26 | $this->getName()
27 | );
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Declaration/TabWidth.php:
--------------------------------------------------------------------------------
1 | getStringValue(),
26 | $this->getName()
27 | );
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Declaration/TrimTrailingWhitespace.php:
--------------------------------------------------------------------------------
1 | setName($name);
12 |
13 | parent::__construct('unset');
14 | }
15 |
16 | /**
17 | * @return mixed
18 | */
19 | protected function getTypedValue(string $value)
20 | {
21 | return null;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/EditorConfig.php:
--------------------------------------------------------------------------------
1 | */
21 | private $configFiles = [];
22 |
23 | /**
24 | * @return array
25 | */
26 | public function getConfigForPath(string $path) : array
27 | {
28 | $configFiles = $this->locateConfigFiles($path);
29 |
30 | $root = false;
31 |
32 | $configuration = [];
33 |
34 | $configFile = array_pop($configFiles);
35 |
36 | while ($configFile !== null) {
37 | $configuration = array_merge($configuration, $configFile->getConfigForPath($path));
38 | $configFile = array_pop($configFiles);
39 | }
40 |
41 | foreach ($configuration as $key => $declaration) {
42 | if ($declaration->getValue() !== null) {
43 | continue;
44 | }
45 |
46 | unset($configuration[$key]);
47 | }
48 |
49 | return $configuration;
50 | }
51 |
52 | public function printConfigForPath(string $path) : string
53 | {
54 | $config = $this->getConfigForPath($path);
55 |
56 | return implode("\n", $config);
57 | }
58 |
59 | /**
60 | * @return array
61 | */
62 | private function locateConfigFiles(string $path) : array
63 | {
64 | $files = [];
65 |
66 | $stop = false;
67 |
68 | $parent = '';
69 |
70 | while ($parent !== $path) {
71 | $editorConfigFile = realpath(sprintf('%s%s.editorconfig', $path, DIRECTORY_SEPARATOR));
72 |
73 | if ($editorConfigFile !== false && is_file($editorConfigFile) && is_readable($editorConfigFile)) {
74 | $file = $this->getConfigFile($editorConfigFile);
75 |
76 | $files[] = $file;
77 |
78 | if ($file->isRoot() === true) {
79 | break;
80 | }
81 | }
82 |
83 | $path = dirname($path);
84 | $parent = dirname($path);
85 | }
86 |
87 | return $files;
88 | }
89 |
90 | private function getConfigFile(string $path) : EditorConfigFile
91 | {
92 | return $this->configFiles[$path] ?? $this->configFiles[$path] = new EditorConfigFile($path);
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/EditorConfigFile.php:
--------------------------------------------------------------------------------
1 | */
38 | private $sections = [];
39 |
40 | /** @var Factory */
41 | private $declarationFactory;
42 |
43 | public function __construct(string $path, ?Factory $declarationFactory = null)
44 | {
45 | $this->declarationFactory = $declarationFactory ?? new Factory();
46 |
47 | if (is_file($path) === false || is_readable($path) === false) {
48 | throw new RuntimeException(sprintf('File %s does not exist or is not readable', $path));
49 | }
50 |
51 | $content = $this->cleanContent($path);
52 |
53 | $this->path = $path;
54 |
55 | $this->parse($content);
56 | }
57 |
58 | public function __toString() : string
59 | {
60 | $preamble = $this->isRoot() === true ? "root=true\n" : '';
61 |
62 | $sections = [];
63 |
64 | foreach ($this->sections as $section) {
65 | $sections[] = (string) $section;
66 | }
67 |
68 | return sprintf('%s%s', $preamble, implode("\n", $sections));
69 | }
70 |
71 | public function isRoot() : bool
72 | {
73 | return $this->isRoot;
74 | }
75 |
76 | public function getPath() : string
77 | {
78 | return $this->path;
79 | }
80 |
81 | /**
82 | * @return array
83 | */
84 | public function getConfigForPath(string $path) : array
85 | {
86 | $configuration = [];
87 |
88 | foreach ($this->sections as $section) {
89 | if ($section->matches($path) === false) {
90 | continue;
91 | }
92 |
93 | $configuration = array_merge($configuration, $section->getDeclarations());
94 | }
95 |
96 | return $configuration;
97 | }
98 |
99 | private function parse(string $content) : void
100 | {
101 | $this->fileContent = $content;
102 |
103 | $content = preg_replace('/^\s/m', '', $this->fileContent) ?? $this->fileContent;
104 |
105 | $parsedContent = $this->parseIniString($content);
106 |
107 | if (isset($parsedContent['root']) === true) {
108 | $this->setIsRoot($parsedContent['root']);
109 | }
110 |
111 | foreach ($parsedContent as $glob => $declarations) {
112 | if (is_array($declarations) === false) {
113 | continue;
114 | }
115 |
116 | $this->sections[] = new Section(
117 | $this->getGlobPrefix($glob),
118 | $glob,
119 | $declarations,
120 | $this->declarationFactory
121 | );
122 | }
123 | }
124 |
125 | private function setIsRoot(string $isRoot) : void
126 | {
127 | if (in_array($isRoot, ['true', 'false']) === false) {
128 | throw new InvalidValue('root', $isRoot);
129 | }
130 |
131 | $this->isRoot = $isRoot === 'true';
132 | }
133 |
134 | private function getGlobPrefix(string $glob) : string
135 | {
136 | return strpos($glob, '/') === 0 ? dirname($this->path) : '**/';
137 | }
138 |
139 | /**
140 | * @return array
141 | */
142 | private function parseIniString(string $content) : array
143 | {
144 | $parsedContent = parse_ini_string($content, true, INI_SCANNER_RAW);
145 |
146 | return is_array($parsedContent) === true ? $parsedContent : [];
147 | }
148 |
149 | private function cleanContent(string $path) : string
150 | {
151 | $content = file_get_contents($path);
152 |
153 | if ($content === false) {
154 | return '';
155 | }
156 |
157 | return preg_replace('/#.*$/m', '', $content) ?? $content;
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/src/Exception/InvalidValue.php:
--------------------------------------------------------------------------------
1 | */
31 | private $declarations = [];
32 |
33 | /** @var Factory */
34 | private $declarationFactory;
35 |
36 | /**
37 | * @param array $declarations
38 | */
39 | public function __construct(
40 | string $globPrefix,
41 | string $glob,
42 | array $declarations,
43 | Factory $declarationFactory
44 | ) {
45 | $this->globPrefix = $globPrefix;
46 |
47 | $this->glob = $glob;
48 |
49 | $this->declarationFactory = $declarationFactory;
50 |
51 | $this->setDeclarations($declarations);
52 | }
53 |
54 | public function __toString() : string
55 | {
56 | return sprintf(
57 | "[%s]\n%s\n",
58 | $this->glob,
59 | implode("\n", $this->getDeclarations())
60 | );
61 | }
62 |
63 | /**
64 | * @return array
65 | */
66 | public function getDeclarations() : array
67 | {
68 | return $this->declarations;
69 | }
70 |
71 | public function matches(string $path) : bool
72 | {
73 | // normalize path to unix-style directory separator,
74 | // because the glob pattern assumes linux-style directory separators
75 | $path = str_replace('\\', '/', $path);
76 |
77 | if (preg_match('#{(.*)}#', $this->glob) === 1) {
78 | return $this->matchesWithCurlBracesExpansion($path);
79 | }
80 |
81 | $pattern = sprintf('%s%s', $this->globPrefix, $this->glob);
82 |
83 | return fnmatch($pattern, $path);
84 | }
85 |
86 | /**
87 | * @param array $declarations
88 | */
89 | private function setDeclarations(array $declarations) : void
90 | {
91 | foreach ($declarations as $name => $value) {
92 | $this->setDeclaration($name, $value);
93 | }
94 | }
95 |
96 | /**
97 | * @param mixed $value
98 | */
99 | private function setDeclaration(string $name, $value) : void
100 | {
101 | $declaration = $this->declarationFactory->getDeclaration($name, $value);
102 |
103 | $this->declarations[$declaration->getName()] = $declaration;
104 | }
105 |
106 | /**
107 | * @return mixed
108 | */
109 | public function __get(string $property)
110 | {
111 | if (isset($this->declarations[$property]) === true) {
112 | return $this->declarations[$property];
113 | }
114 |
115 | $trace = debug_backtrace();
116 |
117 | throw new ErrorException(sprintf(
118 | 'Undefined property: %s in %s on line %s',
119 | $property,
120 | $trace[0]['file'],
121 | $trace[0]['line']
122 | ));
123 | }
124 |
125 | public function __isset(string $property) : bool
126 | {
127 | return array_key_exists($property, $this->declarations);
128 | }
129 |
130 | private function matchesWithCurlBracesExpansion(string $path) : bool
131 | {
132 | preg_match_all('#(?.*){(?.*)}#', $this->glob, $matches, PREG_SET_ORDER);
133 |
134 | foreach ($matches as $match) {
135 | if (array_key_exists('subpattern', $match) === false) {
136 | continue;
137 | }
138 |
139 | $subPatterns = explode(',', $match['subpattern']);
140 | foreach ($subPatterns as $subPattern) {
141 | $pattern = sprintf('%s%s', $this->globPrefix, $match['prefix'] . $subPattern);
142 |
143 | if (fnmatch($pattern, $path)) {
144 | return true;
145 | }
146 | }
147 | }
148 |
149 | return false;
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/tests/Declaration/CharsetTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(sprintf('charset=%s', $charset), (string) $declaration);
18 | }
19 | }
20 |
21 | public function testInvalidValue()
22 | {
23 | $this->expectException(InvalidValue::class);
24 | $declaration = new Charset('true');
25 |
26 | $this->expectException(InvalidValue::class);
27 | $declaration = new Charset('spaces');
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tests/Declaration/EndOfLineTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(sprintf('end_of_line=%s', $eol), (string) $declaration);
18 | }
19 | }
20 |
21 | public function testInvalidValues()
22 | {
23 | $this->expectException(DomainException::class);
24 | $declaration = new EndOfLine('true');
25 |
26 | $this->expectException(DomainException::class);
27 | $declaration = new EndOfLine('spaces');
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tests/Declaration/FactoryTest.php:
--------------------------------------------------------------------------------
1 | 'space',
17 | 'indent_size' => '4',
18 | 'tab_width' => '4',
19 | 'end_of_line' => 'lf',
20 | 'charset' => 'utf-8',
21 | 'trim_trailing_whitespace' => 'true',
22 | 'insert_final_newline' => 'false',
23 | 'max_line_length' => 'off',
24 | ];
25 |
26 | $factory = new Factory();
27 |
28 | foreach ($declarations as $key => $value) {
29 | $declaration = $factory->getDeclaration($key, $value);
30 | $this->assertEquals($key, $declaration->getName());
31 | }
32 | }
33 |
34 | public function testUnsetDeclaration()
35 | {
36 | $factory = new Factory();
37 |
38 | $indentSize = $factory->getDeclaration('indent_size', 'unset');
39 |
40 | $this->assertInstanceOf(UnsetDeclaration::class, $indentSize);
41 | }
42 |
43 | public function testUnknownDeclaration()
44 | {
45 | $factory = new Factory();
46 |
47 | $justification = $factory->getDeclaration('justification', 'left');
48 |
49 | $this->assertInstanceOf(GenericDeclaration::class, $justification);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/tests/Declaration/GenericDeclarationTest.php:
--------------------------------------------------------------------------------
1 | assertEquals('declaration', $declaration->getName());
15 | }
16 |
17 | public function testGetValue() : void
18 | {
19 | $declaration = new GenericDeclaration('declaration', 'string');
20 | $this->assertIsString($declaration->getValue());
21 | $this->assertEquals('string', $declaration->getValue());
22 |
23 | $declaration = new GenericDeclaration('declaration', '1');
24 | $this->assertIsInt($declaration->getValue());
25 | $this->assertSame(1, $declaration->getValue());
26 | $this->assertSame('1', $declaration->getStringValue());
27 |
28 | $declaration = new GenericDeclaration('declaration', 'true');
29 | $this->assertIsBool($declaration->getValue());
30 | $this->assertTrue($declaration->getValue());
31 | $this->assertSame('true', $declaration->getStringValue());
32 |
33 | $declaration = new GenericDeclaration('declaration', '1.1');
34 | $this->assertIsString($declaration->getValue());
35 | $this->assertSame('1.1', $declaration->getValue());
36 | $this->assertSame('1.1', $declaration->getStringValue());
37 | }
38 |
39 | public function testToString() : void
40 | {
41 | $declaration = new GenericDeclaration('declaration', 'string');
42 | $this->assertEquals('declaration=string', (string) $declaration);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/Declaration/IndentSizeTest.php:
--------------------------------------------------------------------------------
1 | assertEquals('indent_size=tab', (string) $declaration);
17 |
18 | $declaration = new IndentSize('4');
19 | $this->assertEquals('indent_size=4', (string) $declaration);
20 | $this->assertSame(4, $declaration->getValue());
21 | }
22 |
23 | public function testInvalidValueType()
24 | {
25 | $this->expectException(InvalidValue::class);
26 | $declaration = new IndentSize('true');
27 | }
28 |
29 | public function testInvalidValueValue()
30 | {
31 | $this->expectException(InvalidValue::class);
32 | $declaration = new IndentSize('four');
33 | }
34 |
35 | public function testInvalidNegativeIntegerValue()
36 | {
37 | $this->expectException(InvalidValue::class);
38 | $declaration = new IndentSize('-1');
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tests/Declaration/IndentStyleTest.php:
--------------------------------------------------------------------------------
1 | assertEquals('indent_style', $declaration->getName());
17 | $this->assertEquals('tab', $declaration->getValue());
18 |
19 | $declaration = new IndentStyle('space');
20 | $this->assertEquals('indent_style', $declaration->getName());
21 | $this->assertEquals('space', $declaration->getValue());
22 | }
23 |
24 | public function testInvalidValues()
25 | {
26 | $this->expectException(InvalidValue::class);
27 | $declaration = new IndentStyle('true');
28 |
29 | $this->expectException(InvalidValue::class);
30 | $declaration = new IndentStyle('spaces');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/Declaration/InsertFinalNewlineTest.php:
--------------------------------------------------------------------------------
1 | assertEquals('insert_final_newline=false', (string) $declaration);
17 |
18 | $declaration = new InsertFinalNewline('true');
19 | $this->assertEquals('insert_final_newline=true', (string) $declaration);
20 | }
21 |
22 | public function testInvalidValues()
23 | {
24 | $this->expectException(InvalidValue::class);
25 | $declaration = new InsertFinalNewline('4');
26 |
27 | $this->expectException(InvalidValue::class);
28 | $declaration = new InsertFinalNewline('four');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tests/Declaration/MaxLineLengthTest.php:
--------------------------------------------------------------------------------
1 | assertEquals('max_line_length=off', (string) $declaration);
16 |
17 | $declaration = new MaxLineLength('4');
18 | $this->assertEquals('max_line_length=4', (string) $declaration);
19 | $this->assertSame(4, $declaration->getValue());
20 | }
21 |
22 | public function testInvalidValues()
23 | {
24 | $this->expectException(InvalidValue::class);
25 | $declaration = new MaxLineLength('true');
26 |
27 | $this->expectException(InvalidValue::class);
28 | $declaration = new MaxLineLength('four');
29 |
30 | $this->expectException(InvalidValue::class);
31 | $declaration = new MaxLineLength('-1');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/Declaration/TabWidthTest.php:
--------------------------------------------------------------------------------
1 | assertEquals('tab_width=4', (string) $declaration);
16 | $this->assertSame(4, $declaration->getValue());
17 | }
18 |
19 | public function testInvalidValues()
20 | {
21 | $this->expectException(InvalidValue::class);
22 | $declaration = new TabWidth('true');
23 |
24 | $this->expectException(InvalidValue::class);
25 | $declaration = new TabWidth('four');
26 |
27 | $this->expectException(InvalidValue::class);
28 | $declaration = new TabWidth('-1');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tests/Declaration/TrimTrailingWhitespaceTest.php:
--------------------------------------------------------------------------------
1 | assertEquals('trim_trailing_whitespace=false', (string) $declaration);
17 |
18 | $declaration = new TrimTrailingWhitespace('true');
19 | $this->assertEquals('trim_trailing_whitespace=true', (string) $declaration);
20 | }
21 |
22 | public function testInvalidIntValue()
23 | {
24 | $this->expectException(DomainException::class);
25 | $declaration = new TrimTrailingWhitespace('4');
26 | }
27 |
28 | public function testInvalidStringValue()
29 | {
30 | $this->expectException(DomainException::class);
31 | $declaration = new TrimTrailingWhitespace('four');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/Declaration/UnsetDeclarationTest.php:
--------------------------------------------------------------------------------
1 | assertEquals('indent_style', $declaration->getName());
19 |
20 | $this->assertNull($declaration->getValue());
21 |
22 | $this->assertEquals('indent_style=unset', (string) $declaration);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/EditorConfigFileTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(EditorConfigFile::class, $file);
20 |
21 | $this->assertFalse($file->isRoot());
22 |
23 | $this->assertEquals($path, $file->getPath());
24 | }
25 |
26 | public function testGetPath(): void
27 | {
28 | $path = __DIR__.'/data/editorconfig';
29 |
30 | $file = new EditorConfigFile($path);
31 |
32 | $this->assertEquals($path, $file->getPath());
33 | }
34 |
35 | public function testEmptyFile(): void
36 | {
37 | $path = __DIR__.'/data/empty_editorconfig';
38 |
39 | $file = new EditorConfigFile($path);
40 |
41 | $this->assertEquals('', trim((string)$file));
42 | }
43 |
44 | public function testRootFile(): void
45 | {
46 | $path = __DIR__.'/data/root_editorconfig';
47 |
48 | $file = new EditorConfigFile($path);
49 |
50 | $this->assertTrue($file->isRoot());
51 |
52 | $this->assertTrue(strpos((string)$file, 'root=true') === 0);
53 | }
54 |
55 | public function testInvalidRootValue(): void
56 | {
57 | $path = __DIR__.'/data/invalid_root_editorconfig';
58 |
59 | $this->expectException(InvalidValue::class);
60 |
61 | $file = new EditorConfigFile($path);
62 | }
63 |
64 |
65 | public function testFileDoesNotExist(): void
66 | {
67 | $this->expectException(RuntimeException::class);
68 |
69 | $file = new EditorConfigFile(__DIR__);
70 | }
71 |
72 | public function testEmptyIndentSize(): void
73 | {
74 | $path = __DIR__.'/data/editorconfig';
75 |
76 | $file = new EditorConfigFile($path);
77 |
78 | $config = $file->getConfigForPath(__DIR__);
79 |
80 | $this->assertFalse(isset($config['indent_size']));
81 | }
82 |
83 | /**
84 | * @dataProvider configForPath
85 | */
86 | public function testGetConfigForPath(string $pathToFile, int $expectedIndentSize): void
87 | {
88 | $path = __DIR__.'/data/editorconfig';
89 |
90 | $file = new EditorConfigFile($path);
91 |
92 | $config = $file->getConfigForPath($pathToFile);
93 |
94 | $this->assertEquals($expectedIndentSize, $config['indent_size']->getValue());
95 | }
96 |
97 | public function configForPath(): array
98 | {
99 | return [
100 | 'This .php file has an indentation of 4' => [__FILE__, 4],
101 | 'The test.json file has an indentation of 2' => [__DIR__.'/data/test.json', 2],
102 | 'The test.yml has an indentation of 98' => [__DIR__.'/data/test.yml', 98],
103 | 'The test.js has an indentation of 27' => [__DIR__.'/data/lib/test.js', 27],
104 | ];
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/tests/EditorConfigTest.php:
--------------------------------------------------------------------------------
1 | getConfigForPath(__FILE__);
17 |
18 | $this->assertEquals(4, $config['indent_size']->getValue());
19 |
20 | $config = $ec->printConfigForPath(__DIR__ . '/data/testfile.php');
21 |
22 | $this->assertFalse(strpos($config, 'indent_size=4'));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/SectionTest.php:
--------------------------------------------------------------------------------
1 | '4',
20 | 'indent_style' => 'space',
21 | ],
22 | new Factory()
23 | );
24 |
25 | $this->assertEquals('space', $section->indent_style->getValue());
26 | $this->assertEquals(4, $section->indent_size->getValue());
27 | $this->assertFalse(isset($section->tab_width));
28 | }
29 |
30 | public function testMatchingWindowsPath() : void
31 | {
32 | $section = new Section(
33 | '**/',
34 | '*.php',
35 | [
36 | 'indent_size' => '4',
37 | 'indent_style' => 'space',
38 | ],
39 | new Factory()
40 | );
41 |
42 | $this->assertTrue($section->matches('my\\composer.php'));
43 | }
44 |
45 | public function testGetMissingDeclaration() : void
46 | {
47 | $section = new Section(
48 | '**/',
49 | '*.php',
50 | [
51 | 'indent_size' => '4',
52 | 'indent_style' => 'space',
53 | ],
54 | new Factory()
55 | );
56 |
57 | $this->expectException(ErrorException::class);
58 |
59 | $section->tab_width;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/tests/data/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | indent_size = unset
3 |
--------------------------------------------------------------------------------
/tests/data/editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | end_of_line = lf
3 | insert_final_newline = true
4 | trim_trailing_whitespace = true
5 | charset = utf-8
6 | indent_style = space
7 |
8 | [*.php]
9 | indent_size = 4
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
14 | [*.{yaml,js,json,json.dist,feature}]
15 | indent_size = 2
16 |
17 | # Indentation override for all JS under lib directory
18 | [lib/**.js]
19 | indent_style = space
20 | indent_size = 27
21 |
22 | # Matches the exact files either package.json or travis.yml
23 | [{package.json,test.yml}]
24 | indent_style = space
25 | indent_size = 98
26 |
27 | #[*.some]
28 |
--------------------------------------------------------------------------------
/tests/data/empty_editorconfig:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idiosyncratic-code/editorconfig-php/3445fa4a1e00f95630d4edc729c2effb116db19b/tests/data/empty_editorconfig
--------------------------------------------------------------------------------
/tests/data/invalid_editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | somekey[something]=somevalue
3 |
--------------------------------------------------------------------------------
/tests/data/invalid_root_editorconfig:
--------------------------------------------------------------------------------
1 | root=yes
2 | [*]
3 | end_of_line = lf
4 | insert_final_newline = true
5 | trim_trailing_whitespace = true
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 4
9 |
10 | [*.md]
11 | trim_trailing_whitespace = false
12 |
13 | [*.{yaml,yml,js,json,json.dist,feature}]
14 | indent_size = 2
15 |
--------------------------------------------------------------------------------
/tests/data/lib/test.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idiosyncratic-code/editorconfig-php/3445fa4a1e00f95630d4edc729c2effb116db19b/tests/data/lib/test.js
--------------------------------------------------------------------------------
/tests/data/root_editorconfig:
--------------------------------------------------------------------------------
1 | root=true
2 | [*]
3 | end_of_line = lf
4 | insert_final_newline = true
5 | trim_trailing_whitespace = true
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 4
9 |
10 | [*.md]
11 | trim_trailing_whitespace = false
12 |
13 | [*.{yaml,yml,js,json,json.dist,feature}]
14 | indent_size = 2
15 |
--------------------------------------------------------------------------------
/tests/data/test.json:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idiosyncratic-code/editorconfig-php/3445fa4a1e00f95630d4edc729c2effb116db19b/tests/data/test.json
--------------------------------------------------------------------------------
/tests/data/test.yml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idiosyncratic-code/editorconfig-php/3445fa4a1e00f95630d4edc729c2effb116db19b/tests/data/test.yml
--------------------------------------------------------------------------------
/tests/data/testfile.php:
--------------------------------------------------------------------------------
1 |