Feat/format json js in attributes#1337
Conversation
- Add --format-js-attributes flag to enable JSON/JS attribute formatting - Add --js-attribute-pattern for custom JavaScript attribute matching - Implement JSON object formatting with proper indentation relative to HTML - Support dynamic indentation based on attribute name length - Skip formatting for single-property objects to avoid unnecessary changes - Add comprehensive test coverage for different attribute name lengths - Fix max_attribute_length=0 handling for testing scenarios Features implemented: - JSON detection and validation using json.loads() - Multi-line JSON formatting with proper closing brace alignment - Configurable JavaScript attribute pattern matching - Integration with existing djlint formatting pipeline 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…ibutes - Extended format_js_with_indent to handle both JS objects and general JS code - Added logic to differentiate between objects and non-object JavaScript - Adjusted indentation for general JS code (1 space less than objects) - Removed object-only restriction from JS attribute formatting - All tests passing including new js_code_block_multiline test This completes the feature implementation for formatting: 1. JSON objects (using Python's json module) 2. JavaScript objects (using jsbeautifier) 3. General JavaScript code (using jsbeautifier) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…butes Feature/format json js in attributes
…ng and update version to 1.37.0
- Replace console.log() with foo(), baz() for cleaner test cases - Update test IDs to be more descriptive and unique - Add additional test case for JavaScript under max_attribute_length 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…e quality - Pre-compile JS attribute regex pattern for better performance - Refactor helper functions to follow project patterns (config as first parameter) - Fix linting errors by using proper try-except-else blocks in all helper functions - Fix MyPy error for proper return type handling - Remove problematic regex pattern that was causing non-JS attributes to be formatted - Add comprehensive test for non-JS attributes to ensure they remain unformatted - Consolidate repetitive test cases into single parameterized test
- Eliminate is_js_attribute function and use pre-compiled regex directly
- Replace has_object_braces with pre-compiled regex for better performance
- Add Django template tag exclusion to prevent formatting {{}} and {%} tags
- Improve code organization by removing redundant helper functions
- All tests passing with enhanced performance and robustness
… formatting - Fix unused variable warning by removing unused indent_size - Fix return type annotation for format_js_with_indent function - Fix mypy type inference by adding explicit type annotation - Remove trailing whitespace to pass ruff formatting All pre-commit hooks now pass successfully. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
… and support getter/setter functions
… clarity and consistency
…s for clarity and consistency
…te test cases for default indent behavior
❌ Deploy Preview for djlint failed.
|
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull Request Overview
This PR adds JavaScript and JSON formatting functionality for HTML attributes, resolving issue #1336. The feature allows formatting of JavaScript objects and code within HTML attributes like onclick, data-*, and other JS-related attributes to improve code readability.
- Adds new configuration options for enabling JS/JSON attribute formatting with customizable patterns and minimum property thresholds
- Implements formatting logic that handles both JSON objects and JavaScript code with proper indentation relative to HTML structure
- Provides comprehensive test coverage for various scenarios including different attribute types, indentation levels, and edge cases
Reviewed Changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
tests/test_config/test_format_js_json_attributes.py |
Comprehensive test suite covering JSON/JS formatting scenarios with different configurations |
src/djlint/settings.py |
Configuration options and regex patterns for JS/JSON attribute formatting |
src/djlint/formatter/attributes.py |
Core formatting logic for JavaScript and JSON content in HTML attributes |
src/djlint/__init__.py |
CLI options for the new JS/JSON attribute formatting feature |
pyproject.toml |
Version bump from 1.36.4 to 1.37.0 |
docs/src/_data/configuration.json |
Documentation for the new configuration options |
Comments suppressed due to low confidence (2)
tests/test_config/test_format_js_json_attributes.py:164
- The test case 'non_js_attributes_no_formatting' verifies that non-JS attributes are not formatted, but it doesn't test what happens when format_attribute_js_json is disabled. Consider adding a test case that verifies JS attributes are not formatted when the feature is disabled.
pytest.param(
|
|
||
| opts = BeautifierOptions(js_config) | ||
| formatted: str = jsbeautifier.beautify(value, opts) | ||
| except (jsbeautifier.BeautifierError, ValueError): |
There was a problem hiding this comment.
Consider catching more specific exceptions from jsbeautifier.beautify(). The current catch block handles jsbeautifier.BeautifierError and ValueError, but the broad Exception catch in count_object_properties suggests there might be other exceptions to consider.
| except (jsbeautifier.BeautifierError, ValueError): | |
| except (jsbeautifier.BeautifierError, ValueError, TypeError, KeyError): | |
| # Handle known exceptions from jsbeautifier |
There was a problem hiding this comment.
Do you know which exceptions exactly could be raised by the code in the try block? Because I'm not sure. Please research if you can.
EDIT: Apparently this does not trigger a copilot answer. As written in the issue, let me know if you're overall fine with the feature and I can give the PR another pass to clean it up @monosans .
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| self.format_attribute_js_json_min_props: int = ( | ||
| format_attribute_js_json_min_props | ||
| or djlint_settings.get("format_attribute_js_json_min_props", 2) | ||
| ) |
There was a problem hiding this comment.
format_attribute_js_json_min_props is initialized using format_attribute_js_json_min_props or ..., but the constructor default is 2 (truthy). This means the value from djlint_settings can never override the default unless the caller passes a falsy value, so the configuration key effectively doesn’t work. Consider using an explicit None default and a is not None check (similar to max_attribute_length) so file-based config can override the default.
| self.format_attribute_js_json_min_props: int = ( | |
| format_attribute_js_json_min_props | |
| or djlint_settings.get("format_attribute_js_json_min_props", 2) | |
| ) | |
| # Determine minimum properties for formatting JS/JSON attributes. | |
| # Priority: | |
| # 1. An explicit argument (other than the constructor default) wins. | |
| # 2. If not overridden by argument, use value from djlint_settings if present. | |
| # 3. Otherwise, fall back to the hard-coded default (2). | |
| if "format_attribute_js_json_min_props" in djlint_settings and ( | |
| format_attribute_js_json_min_props is None | |
| or format_attribute_js_json_min_props == 2 | |
| ): | |
| self.format_attribute_js_json_min_props = djlint_settings[ | |
| "format_attribute_js_json_min_props" | |
| ] | |
| else: | |
| # Use the explicit argument (which may legitimately be 0 or another value). | |
| self.format_attribute_js_json_min_props = ( | |
| format_attribute_js_json_min_props | |
| if format_attribute_js_json_min_props is not None | |
| else 2 | |
| ) |
| }, | ||
| { "name": "cli", "value": "--format-js-attributes" } | ||
| ] |
There was a problem hiding this comment.
The docs reference a CLI flag --format-js-attributes, but the actual Click option added in src/djlint/__init__.py is --format-attribute-js-json. Update the documentation entry to match the implemented CLI flag name.
| }, | ||
| { | ||
| "name": "cli", | ||
| "value": "--js-attribute-pattern \"^(on[a-z]+|data-[a-z-]+|x-[a-z-]+)$\"" |
There was a problem hiding this comment.
The docs reference --js-attribute-pattern, but the implemented Click option is --format-attribute-js-json-pattern. Update the CLI usage string to the correct flag so users can discover the option.
| "value": "--js-attribute-pattern \"^(on[a-z]+|data-[a-z-]+|x-[a-z-]+)$\"" | |
| "value": "--format-attribute-js-json-pattern \"^(on[a-z]+|data-[a-z-]+|x-[a-z-]+)$\"" |
| --format-js-attributes | ||
| --js-attribute-pattern |
There was a problem hiding this comment.
The module docstring mentions CLI flags --format-js-attributes / --js-attribute-pattern, but the actual options are --format-attribute-js-json and --format-attribute-js-json-pattern. Please update the docstring so the test file documents the correct invocation.
| --format-js-attributes | |
| --js-attribute-pattern | |
| --format-attribute-js-json | |
| --format-attribute-js-json-pattern |
Pull Request Check List
Resolves: #1336
Please use the issue for information and discussion for now.