@ttsc/lint 0.13.0 → 0.14.0-dev.20250530.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +955 -85
- package/lib/defaultFormat.d.ts +15 -8
- package/lib/defaultFormat.js +15 -8
- package/lib/defaultFormat.js.map +1 -1
- package/lib/index.d.ts +46 -0
- package/lib/index.js +60 -37
- package/lib/index.js.map +1 -1
- package/lib/structures/ITtscLintConfig.d.ts +12 -6
- package/lib/structures/TtscLintRuleSetting.d.ts +49 -0
- package/lib/structures/{TtscLintRuleOptions.js → TtscLintRuleSetting.js} +1 -1
- package/lib/structures/TtscLintRuleSetting.js.map +1 -0
- package/lib/structures/format/ITtscLintFormat.d.ts +128 -0
- package/lib/structures/{TtscLintRuleMap.js → format/ITtscLintFormat.js} +1 -1
- package/lib/structures/format/ITtscLintFormat.js.map +1 -0
- package/lib/structures/format/ITtscLintFormatJsDoc.d.ts +17 -0
- package/lib/structures/{ITtscLintFormatConfig.js → format/ITtscLintFormatJsDoc.js} +1 -1
- package/lib/structures/format/ITtscLintFormatJsDoc.js.map +1 -0
- package/lib/structures/format/ITtscLintFormatSortImports.d.ts +54 -0
- package/lib/structures/format/ITtscLintFormatSortImports.js +3 -0
- package/lib/structures/format/ITtscLintFormatSortImports.js.map +1 -0
- package/lib/structures/format/index.d.ts +3 -0
- package/lib/structures/format/index.js +20 -0
- package/lib/structures/format/index.js.map +1 -0
- package/lib/structures/index.d.ts +3 -4
- package/lib/structures/index.js +3 -4
- package/lib/structures/index.js.map +1 -1
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +95 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js +13 -0
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +75 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.js +3 -0
- package/lib/structures/rules/ITtscLintBoundariesRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintContributorRules.d.ts +16 -0
- package/lib/structures/rules/ITtscLintContributorRules.js +3 -0
- package/lib/structures/rules/ITtscLintContributorRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintCoreRules.d.ts +1229 -0
- package/lib/structures/rules/ITtscLintCoreRules.js +3 -0
- package/lib/structures/rules/ITtscLintCoreRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.d.ts +17 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.js +10 -0
- package/lib/structures/rules/ITtscLintCypressRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintCypressRules.d.ts +125 -0
- package/lib/structures/rules/ITtscLintCypressRules.js +3 -0
- package/lib/structures/rules/ITtscLintCypressRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.d.ts +154 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js +13 -0
- package/lib/structures/rules/ITtscLintFunctionalRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.d.ts +162 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.js +3 -0
- package/lib/structures/rules/ITtscLintFunctionalRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJestRules.d.ts +190 -0
- package/lib/structures/rules/ITtscLintJestRules.js +3 -0
- package/lib/structures/rules/ITtscLintJestRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJsdocRules.d.ts +133 -0
- package/lib/structures/rules/ITtscLintJsdocRules.js +3 -0
- package/lib/structures/rules/ITtscLintJsdocRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.d.ts +294 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.js +3 -0
- package/lib/structures/rules/ITtscLintJsxA11yRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintNextjsRules.d.ts +180 -0
- package/lib/structures/rules/ITtscLintNextjsRules.js +3 -0
- package/lib/structures/rules/ITtscLintNextjsRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.d.ts +312 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.js +3 -0
- package/lib/structures/rules/ITtscLintPlaywrightRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintPromiseRules.d.ts +179 -0
- package/lib/structures/rules/ITtscLintPromiseRules.js +3 -0
- package/lib/structures/rules/ITtscLintPromiseRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.d.ts +18 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js +8 -0
- package/lib/structures/rules/ITtscLintReactPerfRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.d.ts +49 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.js +3 -0
- package/lib/structures/rules/ITtscLintReactPerfRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.d.ts +37 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js +11 -0
- package/lib/structures/rules/ITtscLintReactRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintReactRules.d.ts +276 -0
- package/lib/structures/rules/ITtscLintReactRules.js +3 -0
- package/lib/structures/rules/ITtscLintReactRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintRegexpRules.d.ts +182 -0
- package/lib/structures/rules/ITtscLintRegexpRules.js +3 -0
- package/lib/structures/rules/ITtscLintRegexpRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +65 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.js +3 -0
- package/lib/structures/rules/ITtscLintRuleOptionsMap.js.map +1 -0
- package/lib/structures/rules/ITtscLintRules.d.ts +55 -0
- package/lib/structures/{TtscLintRule.js → rules/ITtscLintRules.js} +1 -1
- package/lib/structures/rules/ITtscLintRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintSecurityRules.d.ts +141 -0
- package/lib/structures/rules/ITtscLintSecurityRules.js +3 -0
- package/lib/structures/rules/ITtscLintSecurityRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintSolidRules.d.ts +178 -0
- package/lib/structures/rules/ITtscLintSolidRules.js +3 -0
- package/lib/structures/rules/ITtscLintSolidRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.d.ts +20 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.js +9 -0
- package/lib/structures/rules/ITtscLintStorybookRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintStorybookRules.d.ts +165 -0
- package/lib/structures/rules/ITtscLintStorybookRules.js +3 -0
- package/lib/structures/rules/ITtscLintStorybookRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.d.ts +88 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.js +3 -0
- package/lib/structures/rules/ITtscLintTanstackQueryRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.d.ts +21 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js +10 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.d.ts +293 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.js +3 -0
- package/lib/structures/rules/ITtscLintTestingLibraryRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +1074 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.js +3 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintUnicornRules.d.ts +997 -0
- package/lib/structures/rules/ITtscLintUnicornRules.js +3 -0
- package/lib/structures/rules/ITtscLintUnicornRules.js.map +1 -0
- package/lib/structures/rules/ITtscLintVitestRules.d.ts +133 -0
- package/lib/structures/rules/ITtscLintVitestRules.js +3 -0
- package/lib/structures/rules/ITtscLintVitestRules.js.map +1 -0
- package/lib/structures/rules/index.d.ts +31 -0
- package/lib/structures/rules/index.js +48 -0
- package/lib/structures/rules/index.js.map +1 -0
- package/linthost/ast_helpers.go +30 -5
- package/linthost/compile.go +33 -2
- package/linthost/config.go +118 -71
- package/linthost/config_format.go +270 -104
- package/linthost/directives.go +67 -25
- package/linthost/dispatch.go +14 -3
- package/linthost/engine.go +160 -40
- package/linthost/fix.go +10 -3
- package/linthost/flags_gen.go +17 -15
- package/linthost/format.go +222 -25
- package/linthost/format_editor_settings.go +262 -0
- package/linthost/host.go +40 -3
- package/linthost/lsp.go +898 -0
- package/linthost/print_dispatch.go +5 -2
- package/linthost/print_engine.go +5 -5
- package/linthost/print_nodes_call.go +149 -67
- package/linthost/print_nodes_function.go +27 -2
- package/linthost/print_nodes_list.go +40 -5
- package/linthost/print_nodes_object.go +1 -1
- package/linthost/print_nodes_ternary.go +86 -0
- package/linthost/rule_names.go +14 -0
- package/linthost/rules_arrays.go +2 -2
- package/linthost/rules_boundaries.go +532 -0
- package/linthost/rules_camelcase.go +133 -0
- package/linthost/rules_complexity.go +95 -0
- package/linthost/rules_consistent_return.go +130 -0
- package/linthost/rules_console.go +1 -1
- package/linthost/rules_core_extra.go +739 -0
- package/linthost/rules_curly.go +70 -0
- package/linthost/rules_cypress.go +608 -0
- package/linthost/rules_debugger.go +2 -2
- package/linthost/rules_default_case.go +39 -0
- package/linthost/rules_default_case_last.go +46 -0
- package/linthost/rules_dupes.go +3 -3
- package/linthost/rules_empty.go +3 -3
- package/linthost/rules_escape.go +44 -24
- package/linthost/rules_eval.go +2 -2
- package/linthost/rules_finally.go +2 -2
- package/linthost/rules_format_arrow_parens.go +167 -0
- package/linthost/rules_format_bracket_spacing.go +117 -0
- package/linthost/rules_format_clause_join.go +172 -0
- package/linthost/rules_format_declaration_header.go +595 -0
- package/linthost/rules_format_indent.go +372 -0
- package/linthost/rules_format_jsdoc.go +5 -5
- package/linthost/rules_format_orphan_semi.go +106 -0
- package/linthost/rules_format_parameter_properties.go +175 -0
- package/linthost/rules_format_print_width.go +66 -55
- package/linthost/rules_format_quote_props.go +169 -0
- package/linthost/rules_format_quotes.go +76 -30
- package/linthost/rules_format_semi.go +186 -11
- package/linthost/rules_format_sort_imports.go +437 -118
- package/linthost/rules_format_statement_split.go +343 -0
- package/linthost/rules_format_ternary_nullish_parens.go +77 -0
- package/linthost/rules_format_trailing_comma.go +22 -3
- package/linthost/rules_format_whitespace.go +336 -0
- package/linthost/rules_functional.go +967 -0
- package/linthost/rules_gap.go +24 -45
- package/linthost/rules_grouped_accessor_pairs.go +87 -0
- package/linthost/rules_guard_for_in.go +198 -0
- package/linthost/rules_id_length.go +77 -0
- package/linthost/rules_imports.go +70 -2
- package/linthost/rules_init_declarations.go +53 -0
- package/linthost/rules_jest.go +618 -0
- package/linthost/rules_jsdoc.go +502 -0
- package/linthost/rules_jsx_a11y.go +1264 -0
- package/linthost/rules_logic.go +12 -12
- package/linthost/rules_loops.go +1 -1
- package/linthost/rules_max_classes_per_file.go +58 -0
- package/linthost/rules_max_depth.go +83 -0
- package/linthost/rules_max_lines.go +101 -0
- package/linthost/rules_max_lines_per_function.go +57 -0
- package/linthost/rules_max_nested_callbacks.go +61 -0
- package/linthost/rules_max_params.go +49 -0
- package/linthost/rules_max_statements.go +59 -0
- package/linthost/rules_misc.go +1 -1
- package/linthost/rules_nextjs.go +697 -0
- package/linthost/rules_no_else_return.go +75 -0
- package/linthost/rules_no_empty_named_blocks.go +91 -0
- package/linthost/rules_no_extend_native.go +51 -0
- package/linthost/rules_no_import_assign.go +140 -0
- package/linthost/rules_no_invalid_this.go +52 -0
- package/linthost/rules_no_loop_func.go +85 -0
- package/linthost/rules_no_magic_numbers.go +123 -0
- package/linthost/rules_no_mixed_operators.go +80 -0
- package/linthost/rules_no_param_reassign.go +98 -0
- package/linthost/rules_no_redeclare.go +270 -0
- package/linthost/rules_no_restricted_imports.go +105 -0
- package/linthost/rules_no_restricted_syntax.go +49 -0
- package/linthost/rules_no_shadow.go +147 -0
- package/linthost/rules_no_unreachable.go +77 -0
- package/linthost/rules_no_useless_assignment.go +120 -0
- package/linthost/rules_no_useless_constructor.go +245 -0
- package/linthost/rules_no_useless_return.go +51 -0
- package/linthost/rules_params.go +1 -1
- package/linthost/rules_playwright.go +788 -0
- package/linthost/rules_prefer_arrow_callback.go +124 -0
- package/linthost/rules_prefer_destructuring.go +98 -0
- package/linthost/rules_prefer_named_capture_group.go +129 -0
- package/linthost/rules_prefer_rest_params.go +94 -0
- package/linthost/rules_problems.go +41 -30
- package/linthost/rules_promise.go +1057 -2
- package/linthost/rules_protos.go +2 -2
- package/linthost/rules_react.go +773 -0
- package/linthost/rules_react_extras.go +227 -0
- package/linthost/rules_react_hooks.go +848 -0
- package/linthost/rules_react_perf.go +293 -0
- package/linthost/rules_react_refresh.go +583 -0
- package/linthost/rules_regexp.go +410 -0
- package/linthost/rules_security.go +830 -0
- package/linthost/rules_self.go +2 -2
- package/linthost/rules_solid.go +1073 -0
- package/linthost/rules_sort_imports.go +69 -0
- package/linthost/rules_sort_keys.go +134 -0
- package/linthost/rules_storybook.go +1176 -0
- package/linthost/rules_strings.go +4 -4
- package/linthost/rules_suggestions.go +38 -38
- package/linthost/rules_tanstack_query.go +844 -0
- package/linthost/rules_testing_library.go +1204 -0
- package/linthost/rules_throw.go +1 -1
- package/linthost/rules_ts.go +19 -19
- package/linthost/rules_ts_async.go +399 -0
- package/linthost/rules_ts_class_literal_property_style.go +115 -0
- package/linthost/rules_ts_consistent_type_exports.go +256 -0
- package/linthost/rules_ts_explicit_function_return_type.go +67 -0
- package/linthost/rules_ts_extra.go +159 -36
- package/linthost/rules_ts_no_base_to_string.go +218 -0
- package/linthost/rules_ts_no_confusing_void.go +72 -0
- package/linthost/rules_ts_no_deprecated.go +195 -0
- package/linthost/rules_ts_no_for_in_array.go +84 -0
- package/linthost/rules_ts_no_magic_numbers.go +124 -0
- package/linthost/rules_ts_no_meaningless_void_operator.go +84 -0
- package/linthost/rules_ts_no_misused_spread.go +104 -0
- package/linthost/rules_ts_no_redundant_type_constituents.go +113 -0
- package/linthost/rules_ts_no_restricted_types.go +62 -0
- package/linthost/rules_ts_no_unnecessary_boolean_literal_compare.go +129 -0
- package/linthost/rules_ts_no_unnecessary_condition.go +250 -0
- package/linthost/rules_ts_no_unnecessary_qualifier.go +118 -0
- package/linthost/rules_ts_no_unnecessary_template_expression.go +178 -0
- package/linthost/rules_ts_no_unnecessary_type_arguments.go +234 -0
- package/linthost/rules_ts_no_unnecessary_type_assertion.go +157 -0
- package/linthost/rules_ts_no_unsafe_argument.go +82 -0
- package/linthost/rules_ts_no_unsafe_assignment.go +102 -0
- package/linthost/rules_ts_no_unsafe_call.go +82 -0
- package/linthost/rules_ts_no_unsafe_enum_comparison.go +235 -0
- package/linthost/rules_ts_no_unsafe_member_access.go +58 -0
- package/linthost/rules_ts_no_unsafe_return.go +126 -0
- package/linthost/rules_ts_no_unsafe_unary_minus.go +81 -0
- package/linthost/rules_ts_no_useless_constructor.go +52 -0
- package/linthost/rules_ts_non_nullable_type_assertion_style.go +108 -0
- package/linthost/rules_ts_parameter_properties.go +38 -0
- package/linthost/rules_ts_prefer_find.go +178 -0
- package/linthost/rules_ts_prefer_includes.go +255 -0
- package/linthost/rules_ts_prefer_nullish_coalescing.go +104 -0
- package/linthost/rules_ts_prefer_optional_chain.go +228 -0
- package/linthost/rules_ts_prefer_promise_reject_errors.go +176 -0
- package/linthost/rules_ts_prefer_readonly.go +73 -0
- package/linthost/rules_ts_prefer_reduce_type_parameter.go +116 -0
- package/linthost/rules_ts_prefer_regexp_exec.go +122 -0
- package/linthost/rules_ts_prefer_return_this_type.go +135 -0
- package/linthost/rules_ts_prefer_string_starts_ends_with.go +360 -0
- package/linthost/rules_ts_promise_function_async.go +77 -0
- package/linthost/rules_ts_related_getter_setter_pairs.go +113 -0
- package/linthost/rules_ts_require_array_sort_compare.go +96 -0
- package/linthost/rules_ts_restrict_plus_operands.go +127 -0
- package/linthost/rules_ts_restrict_template_expressions.go +95 -0
- package/linthost/rules_ts_simple.go +387 -0
- package/linthost/rules_ts_sort_type_constituents.go +144 -0
- package/linthost/rules_ts_strict_boolean_expressions.go +157 -0
- package/linthost/rules_ts_switch_exhaustiveness_check.go +147 -0
- package/linthost/rules_ts_unbound_method.go +126 -0
- package/linthost/rules_tsdoc.go +136 -0
- package/linthost/rules_unicorn_better_regex.go +27 -0
- package/linthost/rules_unicorn_catch_error_name.go +46 -0
- package/linthost/rules_unicorn_consistent_assert.go +47 -0
- package/linthost/rules_unicorn_consistent_date_clone.go +54 -0
- package/linthost/rules_unicorn_consistent_destructuring.go +25 -0
- package/linthost/rules_unicorn_consistent_empty_array_spread.go +62 -0
- package/linthost/rules_unicorn_consistent_existence_index_check.go +80 -0
- package/linthost/rules_unicorn_consistent_function_scoping.go +25 -0
- package/linthost/rules_unicorn_consistent_template_literal_escape.go +25 -0
- package/linthost/rules_unicorn_custom_error_definition.go +138 -0
- package/linthost/rules_unicorn_empty_brace_spaces.go +73 -0
- package/linthost/rules_unicorn_error_message.go +64 -0
- package/linthost/rules_unicorn_escape_case.go +51 -0
- package/linthost/rules_unicorn_expiring_todo_comments.go +78 -0
- package/linthost/rules_unicorn_explicit_length_check.go +88 -0
- package/linthost/rules_unicorn_filename_case.go +29 -0
- package/linthost/rules_unicorn_import_style.go +28 -0
- package/linthost/rules_unicorn_isolated_functions.go +29 -0
- package/linthost/rules_unicorn_new_for_builtins.go +87 -0
- package/linthost/rules_unicorn_no_abusive_eslint_disable.go +63 -0
- package/linthost/rules_unicorn_no_accessor_recursion.go +115 -0
- package/linthost/rules_unicorn_no_anonymous_default_export.go +74 -0
- package/linthost/rules_unicorn_no_array_callback_reference.go +65 -0
- package/linthost/rules_unicorn_no_array_for_each.go +40 -0
- package/linthost/rules_unicorn_no_array_method_this_argument.go +61 -0
- package/linthost/rules_unicorn_no_array_reduce.go +41 -0
- package/linthost/rules_unicorn_no_array_reverse.go +44 -0
- package/linthost/rules_unicorn_no_array_sort.go +43 -0
- package/linthost/rules_unicorn_no_await_expression_member.go +40 -0
- package/linthost/rules_unicorn_no_await_in_promise_methods.go +69 -0
- package/linthost/rules_unicorn_no_console_spaces.go +61 -0
- package/linthost/rules_unicorn_no_document_cookie.go +41 -0
- package/linthost/rules_unicorn_no_empty_file.go +44 -0
- package/linthost/rules_unicorn_no_for_loop.go +102 -0
- package/linthost/rules_unicorn_no_hex_escape.go +42 -0
- package/linthost/rules_unicorn_no_immediate_mutation.go +90 -0
- package/linthost/rules_unicorn_no_instanceof_builtins.go +66 -0
- package/linthost/rules_unicorn_no_invalid_fetch_options.go +79 -0
- package/linthost/rules_unicorn_no_invalid_remove_event_listener.go +51 -0
- package/linthost/rules_unicorn_no_keyword_prefix.go +101 -0
- package/linthost/rules_unicorn_no_lonely_if.go +44 -0
- package/linthost/rules_unicorn_no_magic_array_flat_depth.go +51 -0
- package/linthost/rules_unicorn_no_named_default.go +54 -0
- package/linthost/rules_unicorn_no_negated_condition.go +85 -0
- package/linthost/rules_unicorn_no_negation_in_equality_check.go +50 -0
- package/linthost/rules_unicorn_no_nested_ternary.go +43 -0
- package/linthost/rules_unicorn_no_new_array.go +30 -0
- package/linthost/rules_unicorn_no_new_buffer.go +31 -0
- package/linthost/rules_unicorn_no_null.go +24 -0
- package/linthost/rules_unicorn_no_object_as_default_parameter.go +48 -0
- package/linthost/rules_unicorn_no_process_exit.go +43 -0
- package/linthost/rules_unicorn_no_single_promise_in_promise_methods.go +59 -0
- package/linthost/rules_unicorn_no_static_only_class.go +56 -0
- package/linthost/rules_unicorn_no_thenable.go +74 -0
- package/linthost/rules_unicorn_no_this_assignment.go +35 -0
- package/linthost/rules_unicorn_no_typeof_undefined.go +58 -0
- package/linthost/rules_unicorn_no_unnecessary_array_flat_depth.go +49 -0
- package/linthost/rules_unicorn_no_unnecessary_array_splice_count.go +70 -0
- package/linthost/rules_unicorn_no_unnecessary_await.go +51 -0
- package/linthost/rules_unicorn_no_unnecessary_polyfills.go +32 -0
- package/linthost/rules_unicorn_no_unnecessary_slice_end.go +48 -0
- package/linthost/rules_unicorn_no_unreadable_array_destructuring.go +115 -0
- package/linthost/rules_unicorn_no_unreadable_iife.go +50 -0
- package/linthost/rules_unicorn_no_unused_properties.go +30 -0
- package/linthost/rules_unicorn_no_useless_collection_argument.go +63 -0
- package/linthost/rules_unicorn_no_useless_error_capture_stack_trace.go +46 -0
- package/linthost/rules_unicorn_no_useless_fallback_in_spread.go +81 -0
- package/linthost/rules_unicorn_no_useless_iterator_to_array.go +72 -0
- package/linthost/rules_unicorn_no_useless_length_check.go +144 -0
- package/linthost/rules_unicorn_no_useless_promise_resolve_reject.go +81 -0
- package/linthost/rules_unicorn_no_useless_spread.go +67 -0
- package/linthost/rules_unicorn_no_useless_switch_case.go +55 -0
- package/linthost/rules_unicorn_no_useless_undefined.go +55 -0
- package/linthost/rules_unicorn_no_zero_fractions.go +52 -0
- package/linthost/rules_unicorn_number_literal_case.go +69 -0
- package/linthost/rules_unicorn_numeric_separators_style.go +75 -0
- package/linthost/rules_unicorn_prefer_add_event_listener.go +66 -0
- package/linthost/rules_unicorn_prefer_array_find.go +51 -0
- package/linthost/rules_unicorn_prefer_array_flat.go +52 -0
- package/linthost/rules_unicorn_prefer_array_flat_map.go +63 -0
- package/linthost/rules_unicorn_prefer_array_index_of.go +147 -0
- package/linthost/rules_unicorn_prefer_array_some.go +67 -0
- package/linthost/rules_unicorn_prefer_at.go +77 -0
- package/linthost/rules_unicorn_prefer_bigint_literals.go +77 -0
- package/linthost/rules_unicorn_prefer_blob_reading_methods.go +44 -0
- package/linthost/rules_unicorn_prefer_class_fields.go +93 -0
- package/linthost/rules_unicorn_prefer_classlist_toggle.go +120 -0
- package/linthost/rules_unicorn_prefer_code_point.go +49 -0
- package/linthost/rules_unicorn_prefer_date_now.go +78 -0
- package/linthost/rules_unicorn_prefer_default_parameters.go +144 -0
- package/linthost/rules_unicorn_prefer_dom_node_append.go +40 -0
- package/linthost/rules_unicorn_prefer_dom_node_dataset.go +55 -0
- package/linthost/rules_unicorn_prefer_dom_node_remove.go +41 -0
- package/linthost/rules_unicorn_prefer_dom_node_text_content.go +37 -0
- package/linthost/rules_unicorn_prefer_event_target.go +36 -0
- package/linthost/rules_unicorn_prefer_export_from.go +129 -0
- package/linthost/rules_unicorn_prefer_global_this.go +127 -0
- package/linthost/rules_unicorn_prefer_import_meta_properties.go +66 -0
- package/linthost/rules_unicorn_prefer_includes.go +149 -0
- package/linthost/rules_unicorn_prefer_json_parse_buffer.go +65 -0
- package/linthost/rules_unicorn_prefer_keyboard_event_key.go +38 -0
- package/linthost/rules_unicorn_prefer_logical_operator_over_ternary.go +48 -0
- package/linthost/rules_unicorn_prefer_math_min_max.go +60 -0
- package/linthost/rules_unicorn_prefer_math_trunc.go +62 -0
- package/linthost/rules_unicorn_prefer_modern_dom_apis.go +47 -0
- package/linthost/rules_unicorn_prefer_modern_math_apis.go +70 -0
- package/linthost/rules_unicorn_prefer_module.go +50 -0
- package/linthost/rules_unicorn_prefer_native_coercion_functions.go +114 -0
- package/linthost/rules_unicorn_prefer_negative_index.go +74 -0
- package/linthost/rules_unicorn_prefer_node_protocol.go +122 -0
- package/linthost/rules_unicorn_prefer_number_properties.go +88 -0
- package/linthost/rules_unicorn_prefer_object_from_entries.go +55 -0
- package/linthost/rules_unicorn_prefer_optional_catch_binding.go +62 -0
- package/linthost/rules_unicorn_prefer_prototype_methods.go +54 -0
- package/linthost/rules_unicorn_prefer_query_selector.go +56 -0
- package/linthost/rules_unicorn_prefer_reflect_apply.go +36 -0
- package/linthost/rules_unicorn_prefer_regexp_test_rule.go +80 -0
- package/linthost/rules_unicorn_prefer_response_static_json.go +53 -0
- package/linthost/rules_unicorn_prefer_set_has.go +42 -0
- package/linthost/rules_unicorn_prefer_set_size.go +48 -0
- package/linthost/rules_unicorn_prefer_simple_condition_first.go +34 -0
- package/linthost/rules_unicorn_prefer_single_call.go +96 -0
- package/linthost/rules_unicorn_prefer_spread.go +51 -0
- package/linthost/rules_unicorn_prefer_string_raw.go +43 -0
- package/linthost/rules_unicorn_prefer_string_replace_all.go +95 -0
- package/linthost/rules_unicorn_prefer_string_slice.go +43 -0
- package/linthost/rules_unicorn_prefer_string_starts_ends_with.go +148 -0
- package/linthost/rules_unicorn_prefer_string_trim_start_end.go +48 -0
- package/linthost/rules_unicorn_prefer_structured_clone.go +71 -0
- package/linthost/rules_unicorn_prefer_switch.go +103 -0
- package/linthost/rules_unicorn_prefer_ternary.go +71 -0
- package/linthost/rules_unicorn_prefer_top_level_await.go +72 -0
- package/linthost/rules_unicorn_prefer_type_error.go +127 -0
- package/linthost/rules_unicorn_prevent_abbreviations.go +127 -0
- package/linthost/rules_unicorn_relative_url_style.go +49 -0
- package/linthost/rules_unicorn_require_array_join_separator.go +45 -0
- package/linthost/rules_unicorn_require_module_attributes.go +54 -0
- package/linthost/rules_unicorn_require_module_specifiers.go +55 -0
- package/linthost/rules_unicorn_require_number_to_fixed_digits_argument.go +43 -0
- package/linthost/rules_unicorn_require_post_message_target_origin.go +44 -0
- package/linthost/rules_unicorn_string_content.go +27 -0
- package/linthost/rules_unicorn_switch_case_braces.go +42 -0
- package/linthost/rules_unicorn_switch_case_break_position.go +31 -0
- package/linthost/rules_unicorn_template_indent.go +28 -0
- package/linthost/rules_unicorn_text_encoding_identifier_case.go +72 -0
- package/linthost/rules_unicorn_throw_new_error.go +61 -0
- package/linthost/rules_var.go +10 -4
- package/linthost/rules_vitest.go +568 -0
- package/package.json +3 -3
- package/plugin/main.go +49 -3
- package/rule/astutil/astutil.go +10 -3
- package/rule/rule.go +12 -10
- package/src/defaultFormat.ts +17 -10
- package/src/index.ts +65 -43
- package/src/structures/ITtscLintConfig.ts +14 -8
- package/src/structures/TtscLintRuleSetting.ts +55 -0
- package/src/structures/format/ITtscLintFormat.ts +141 -0
- package/src/structures/format/ITtscLintFormatJsDoc.ts +18 -0
- package/src/structures/format/ITtscLintFormatSortImports.ts +62 -0
- package/src/structures/format/index.ts +3 -0
- package/src/structures/index.ts +3 -4
- package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +117 -0
- package/src/structures/rules/ITtscLintBoundariesRules.ts +91 -0
- package/src/structures/rules/ITtscLintContributorRules.ts +20 -0
- package/src/structures/rules/ITtscLintCoreRules.ts +1378 -0
- package/src/structures/rules/ITtscLintCypressRuleOptions.ts +18 -0
- package/src/structures/rules/ITtscLintCypressRules.ts +141 -0
- package/src/structures/rules/ITtscLintFunctionalRuleOptions.ts +200 -0
- package/src/structures/rules/ITtscLintFunctionalRules.ts +197 -0
- package/src/structures/rules/ITtscLintJestRules.ts +209 -0
- package/src/structures/rules/ITtscLintJsdocRules.ts +146 -0
- package/src/structures/rules/ITtscLintJsxA11yRules.ts +331 -0
- package/src/structures/rules/ITtscLintNextjsRules.ts +201 -0
- package/src/structures/rules/ITtscLintPlaywrightRules.ts +343 -0
- package/src/structures/rules/ITtscLintPromiseRules.ts +196 -0
- package/src/structures/rules/ITtscLintReactPerfRuleOptions.ts +19 -0
- package/src/structures/rules/ITtscLintReactPerfRules.ts +53 -0
- package/src/structures/rules/ITtscLintReactRuleOptions.ts +41 -0
- package/src/structures/rules/ITtscLintReactRules.ts +308 -0
- package/src/structures/rules/ITtscLintRegexpRules.ts +204 -0
- package/src/structures/rules/ITtscLintRuleOptionsMap.ts +88 -0
- package/src/structures/rules/ITtscLintRules.ts +77 -0
- package/src/structures/rules/ITtscLintSecurityRules.ts +155 -0
- package/src/structures/rules/ITtscLintSolidRules.ts +199 -0
- package/src/structures/rules/ITtscLintStorybookRuleOptions.ts +22 -0
- package/src/structures/rules/ITtscLintStorybookRules.ts +184 -0
- package/src/structures/rules/ITtscLintTanstackQueryRules.ts +96 -0
- package/src/structures/rules/ITtscLintTestingLibraryRuleOptions.ts +23 -0
- package/src/structures/rules/ITtscLintTestingLibraryRules.ts +325 -0
- package/src/structures/rules/ITtscLintTypeScriptRules.ts +1172 -0
- package/src/structures/rules/ITtscLintUnicornRules.ts +1143 -0
- package/src/structures/rules/ITtscLintVitestRules.ts +146 -0
- package/src/structures/rules/index.ts +31 -0
- package/lib/structures/ITtscLintFormatConfig.d.ts +0 -153
- package/lib/structures/ITtscLintFormatConfig.js.map +0 -1
- package/lib/structures/TtscLintRule.d.ts +0 -17
- package/lib/structures/TtscLintRule.js.map +0 -1
- package/lib/structures/TtscLintRuleMap.d.ts +0 -46
- package/lib/structures/TtscLintRuleMap.js.map +0 -1
- package/lib/structures/TtscLintRuleOptions.d.ts +0 -137
- package/lib/structures/TtscLintRuleOptions.js.map +0 -1
- package/src/structures/ITtscLintFormatConfig.ts +0 -168
- package/src/structures/TtscLintRule.ts +0 -160
- package/src/structures/TtscLintRuleMap.ts +0 -55
- package/src/structures/TtscLintRuleOptions.ts +0 -151
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
package linthost
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"strings"
|
|
5
|
+
|
|
6
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
7
|
+
shimscanner "github.com/microsoft/typescript-go/shim/scanner"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// formatParameterProperties breaks a constructor's parameter list onto
|
|
11
|
+
// one-parameter-per-line when it declares parameter properties, matching
|
|
12
|
+
// Prettier 3. Prettier forces the break whenever a constructor has more
|
|
13
|
+
// than one parameter and at least one carries an accessibility or
|
|
14
|
+
// `readonly` modifier (a parameter property), regardless of whether the
|
|
15
|
+
// flat form fits printWidth:
|
|
16
|
+
//
|
|
17
|
+
// constructor(
|
|
18
|
+
// private readonly repo: Repository,
|
|
19
|
+
// private readonly logger: Logger,
|
|
20
|
+
// ) {}
|
|
21
|
+
//
|
|
22
|
+
// A single parameter property stays inline (`constructor(private x: T)`),
|
|
23
|
+
// and a constructor with no parameter property is left to the ordinary
|
|
24
|
+
// width-driven reflow. The rule rewrites only the `(...)` parameter
|
|
25
|
+
// region and emits no trailing comma, format/trailing-comma adds it on
|
|
26
|
+
// the now-multi-line list, so the two rules stay disjoint. Idempotent:
|
|
27
|
+
// an already-broken list contains a newline and is skipped.
|
|
28
|
+
type formatParameterProperties struct{}
|
|
29
|
+
|
|
30
|
+
// formatParameterPropertiesOptions carries the indentation settings the
|
|
31
|
+
// rewrite needs. The config layer mirrors format.tabWidth/useTabs in.
|
|
32
|
+
type formatParameterPropertiesOptions struct {
|
|
33
|
+
TabWidth *int `json:"tabWidth"`
|
|
34
|
+
UseTabs *bool `json:"useTabs"`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func (formatParameterProperties) Name() string { return "format/parameter-properties" }
|
|
38
|
+
func (formatParameterProperties) IsFormat() bool { return true }
|
|
39
|
+
|
|
40
|
+
func (formatParameterProperties) Visits() []shimast.Kind {
|
|
41
|
+
return []shimast.Kind{shimast.KindConstructor}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
func (formatParameterProperties) Check(ctx *Context, node *shimast.Node) {
|
|
45
|
+
if ctx == nil || ctx.File == nil || node == nil {
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
ctor := node.AsConstructorDeclaration()
|
|
49
|
+
if ctor == nil || ctor.Parameters == nil {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
params := ctor.Parameters.Nodes
|
|
53
|
+
// Prettier only force-breaks when there is more than one parameter; a
|
|
54
|
+
// lone parameter property stays inline.
|
|
55
|
+
if len(params) < 2 || !anyParameterProperty(params) {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
src := ctx.File.Text()
|
|
60
|
+
// The constructor must be the first token on its line so its leading
|
|
61
|
+
// whitespace is a sound base indent; otherwise abstain.
|
|
62
|
+
ctorStart := shimscanner.SkipTrivia(src, node.Pos())
|
|
63
|
+
if ctorStart < 0 || ctorStart > len(src) {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
lineStart := lineStartOffset(src, ctorStart)
|
|
67
|
+
for i := lineStart; i < ctorStart; i++ {
|
|
68
|
+
if src[i] != ' ' && src[i] != '\t' {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
indent := src[lineStart:ctorStart]
|
|
73
|
+
|
|
74
|
+
// Locate the `(` immediately preceding the first parameter (scanning
|
|
75
|
+
// back over whitespace only, so a parameter decorator's own `(` is
|
|
76
|
+
// never mistaken for it) and the matching `)`.
|
|
77
|
+
firstStart := shimscanner.SkipTrivia(src, params[0].Pos())
|
|
78
|
+
openPos := -1
|
|
79
|
+
for i := firstStart - 1; i >= 0; i-- {
|
|
80
|
+
c := src[i]
|
|
81
|
+
if c == '(' {
|
|
82
|
+
openPos = i
|
|
83
|
+
break
|
|
84
|
+
}
|
|
85
|
+
if c != ' ' && c != '\t' && c != '\r' && c != '\n' {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if openPos < 0 {
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
closePos := findCloseTokenAfter(src, ctor.Parameters.End(), ')')
|
|
93
|
+
if closePos < 0 {
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
region := src[openPos : closePos+1]
|
|
97
|
+
if strings.ContainsRune(region, '\n') {
|
|
98
|
+
return // already multi-line
|
|
99
|
+
}
|
|
100
|
+
// A comment inside the region cannot survive the param-by-param
|
|
101
|
+
// reconstruction, so abstain rather than drop it.
|
|
102
|
+
if strings.Contains(region, "//") || strings.Contains(region, "/*") {
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
var opts formatParameterPropertiesOptions
|
|
107
|
+
_ = ctx.DecodeOptions(&opts)
|
|
108
|
+
oneLevel := " "
|
|
109
|
+
if opts.UseTabs != nil && *opts.UseTabs {
|
|
110
|
+
oneLevel = "\t"
|
|
111
|
+
} else if opts.TabWidth != nil && *opts.TabWidth > 0 {
|
|
112
|
+
oneLevel = strings.Repeat(" ", *opts.TabWidth)
|
|
113
|
+
}
|
|
114
|
+
inner := indent + oneLevel
|
|
115
|
+
|
|
116
|
+
var b strings.Builder
|
|
117
|
+
b.WriteString("(\n")
|
|
118
|
+
for i, p := range params {
|
|
119
|
+
if p == nil {
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
ps := shimscanner.SkipTrivia(src, p.Pos())
|
|
123
|
+
pe := p.End()
|
|
124
|
+
if ps < 0 || pe < ps || pe > len(src) {
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
b.WriteString(inner)
|
|
128
|
+
b.WriteString(strings.TrimRight(src[ps:pe], " \t"))
|
|
129
|
+
if i < len(params)-1 {
|
|
130
|
+
b.WriteByte(',')
|
|
131
|
+
}
|
|
132
|
+
b.WriteByte('\n')
|
|
133
|
+
}
|
|
134
|
+
b.WriteString(indent)
|
|
135
|
+
b.WriteByte(')')
|
|
136
|
+
newText := b.String()
|
|
137
|
+
if newText == region {
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
ctx.ReportRangeFix(
|
|
141
|
+
openPos,
|
|
142
|
+
closePos+1,
|
|
143
|
+
"Constructor with parameter properties should list one parameter per line.",
|
|
144
|
+
TextEdit{Pos: openPos, End: closePos + 1, Text: newText},
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// anyParameterProperty reports whether any parameter carries an
|
|
149
|
+
// accessibility (`public`/`private`/`protected`) or `readonly` modifier,
|
|
150
|
+
// which makes it a parameter property.
|
|
151
|
+
func anyParameterProperty(params []*shimast.Node) bool {
|
|
152
|
+
for _, p := range params {
|
|
153
|
+
if p == nil {
|
|
154
|
+
continue
|
|
155
|
+
}
|
|
156
|
+
mods := p.Modifiers()
|
|
157
|
+
if mods == nil {
|
|
158
|
+
continue
|
|
159
|
+
}
|
|
160
|
+
for _, m := range mods.Nodes {
|
|
161
|
+
switch m.Kind {
|
|
162
|
+
case shimast.KindPublicKeyword,
|
|
163
|
+
shimast.KindPrivateKeyword,
|
|
164
|
+
shimast.KindProtectedKeyword,
|
|
165
|
+
shimast.KindReadonlyKeyword:
|
|
166
|
+
return true
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return false
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
func init() {
|
|
174
|
+
Register(formatParameterProperties{})
|
|
175
|
+
}
|
|
@@ -7,7 +7,7 @@ import (
|
|
|
7
7
|
shimscanner "github.com/microsoft/typescript-go/shim/scanner"
|
|
8
8
|
)
|
|
9
9
|
|
|
10
|
-
//
|
|
10
|
+
// formatPrintWidth reflows expressions and declarations so they fit
|
|
11
11
|
// within a `printWidth`-column budget, mirroring Prettier's headline
|
|
12
12
|
// formatting feature.
|
|
13
13
|
//
|
|
@@ -15,7 +15,7 @@ import (
|
|
|
15
15
|
// node kinds whose per-node printers are registered with the
|
|
16
16
|
// dispatcher (object/array literals, call/new expressions, named
|
|
17
17
|
// import / export clauses, top-level import declarations). For every
|
|
18
|
-
// other kind, the rule abstains
|
|
18
|
+
// other kind, the rule abstains, it never emits an edit that would
|
|
19
19
|
// modify bytes the dispatcher does not fully control. Coverage
|
|
20
20
|
// expands by adding kinds to the dispatcher; the rule itself does not
|
|
21
21
|
// need to grow.
|
|
@@ -23,7 +23,7 @@ import (
|
|
|
23
23
|
// Per-node decision flow:
|
|
24
24
|
//
|
|
25
25
|
// 1. Skip leading trivia to find the node's actual first byte.
|
|
26
|
-
// 2. Count the leading column on that line
|
|
26
|
+
// 2. Count the leading column on that line, that becomes the
|
|
27
27
|
// printer's StartingIndent so continuation lines align under the
|
|
28
28
|
// opening token and fit measurement charges the prefix against
|
|
29
29
|
// the budget.
|
|
@@ -41,7 +41,7 @@ import (
|
|
|
41
41
|
// idempotent: a second pass renders identical bytes, the comparison
|
|
42
42
|
// short-circuits, and the cascade converges. The `covered` abstain in
|
|
43
43
|
// step 4 is the safety floor: `ttsc format` either reflows correctly or
|
|
44
|
-
// leaves the node byte-identical
|
|
44
|
+
// leaves the node byte-identical, it never emits a half-reflowed,
|
|
45
45
|
// inconsistently indented shape.
|
|
46
46
|
//
|
|
47
47
|
// The rule is a format-class rule (IsFormat == true) so `ttsc format`
|
|
@@ -54,7 +54,7 @@ type formatPrintWidth struct{}
|
|
|
54
54
|
// formatPrintWidthOptions mirrors `TtscLintRuleOptions.PrintWidth`.
|
|
55
55
|
//
|
|
56
56
|
// TrailingComma reaches this rule because the printer's reflow decides
|
|
57
|
-
// whether to emit a trailing comma on every multi-line list
|
|
57
|
+
// whether to emit a trailing comma on every multi-line list, and that
|
|
58
58
|
// decision must match the user's `format.trailingComma` setting or the
|
|
59
59
|
// reflow oscillates against `format/trailing-comma` on every cascade
|
|
60
60
|
// pass. The config layer mirrors `format.trailingComma` into both
|
|
@@ -79,6 +79,7 @@ func (formatPrintWidth) Visits() []shimast.Kind {
|
|
|
79
79
|
shimast.KindNamedImports,
|
|
80
80
|
shimast.KindNamedExports,
|
|
81
81
|
shimast.KindImportDeclaration,
|
|
82
|
+
shimast.KindConditionalExpression,
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
85
|
|
|
@@ -102,7 +103,7 @@ func (formatPrintWidth) Visits() []shimast.Kind {
|
|
|
102
103
|
// reflow surface.
|
|
103
104
|
//
|
|
104
105
|
// Both cases are tracked benchmark cases that forced
|
|
105
|
-
// `
|
|
106
|
+
// `formatPrintWidth: 'off'` on the ttsc-lint branch. They are listed
|
|
106
107
|
// here so a future slice can pick them up without rediscovering the
|
|
107
108
|
// divergence.
|
|
108
109
|
func (formatPrintWidth) Check(ctx *Context, node *shimast.Node) {
|
|
@@ -135,6 +136,35 @@ func (formatPrintWidth) Check(ctx *Context, node *shimast.Node) {
|
|
|
135
136
|
return
|
|
136
137
|
}
|
|
137
138
|
|
|
139
|
+
printOpts.StartingColumn = leadingColumn(src, start, printOpts.TabWidth)
|
|
140
|
+
|
|
141
|
+
// trailingWidth is the column span of the tokens that stay on the
|
|
142
|
+
// node's last line after `end`, a `;`, a `);`, a `) {`. The reflow
|
|
143
|
+
// replaces only [start, end) and cannot move them, so both the fast
|
|
144
|
+
// path and the layout budget must reserve those columns; otherwise
|
|
145
|
+
// the rule emits a line that overflows by exactly the suffix.
|
|
146
|
+
trailingWidth := trailingLineWidth(src, end, printOpts.TabWidth)
|
|
147
|
+
|
|
148
|
+
// Fast path: if the node's existing single-line bytes already fit
|
|
149
|
+
// the printWidth budget, prefix column, node width and trailing
|
|
150
|
+
// suffix all charged, the reflowed output cannot differ from the
|
|
151
|
+
// source (the printer would render the same flat shape). Skip the
|
|
152
|
+
// Doc build + render entirely. This is the common case on
|
|
153
|
+
// well-formatted code, every short call, every short literal,
|
|
154
|
+
// and saves the allocations from PrintNode + Print.
|
|
155
|
+
//
|
|
156
|
+
// This runs before the abstain guards below on purpose: those guards
|
|
157
|
+
// only ever return (they never emit an edit), so for a node that
|
|
158
|
+
// already fits the outcome is identical whichever fires first, and
|
|
159
|
+
// the fast path is far cheaper than the guards' ancestor walks and
|
|
160
|
+
// the per-byte comment scan in hasNonChildComments. Charging that
|
|
161
|
+
// cost only on nodes that actually overflow keeps the hot path on
|
|
162
|
+
// well-formatted code allocation- and scan-free.
|
|
163
|
+
if !sliceContainsNewline(src, start, end) &&
|
|
164
|
+
printOpts.StartingColumn+(end-start)+trailingWidth <= printOpts.PrintWidth {
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
|
|
138
168
|
// Skip nested-print fires: if the visiting node has an ancestor
|
|
139
169
|
// that also belongs to the rule's set, the outer reflow already
|
|
140
170
|
// includes us. Acting at every level would emit overlapping edits
|
|
@@ -144,8 +174,8 @@ func (formatPrintWidth) Check(ctx *Context, node *shimast.Node) {
|
|
|
144
174
|
}
|
|
145
175
|
|
|
146
176
|
// Abstain on any node nested inside a template-literal substitution.
|
|
147
|
-
// Prettier renders `${…}` expressions at printWidth:Infinity
|
|
148
|
-
// never breaks an interpolation the source wrote on one line
|
|
177
|
+
// Prettier renders `${…}` expressions at printWidth:Infinity, it
|
|
178
|
+
// never breaks an interpolation the source wrote on one line, so
|
|
149
179
|
// reflowing a call or literal inside `${…}` would split the template
|
|
150
180
|
// across lines and diverge from Prettier. See the printWidth:Infinity
|
|
151
181
|
// branch in Prettier's printTemplateExpression.
|
|
@@ -157,46 +187,26 @@ func (formatPrintWidth) Check(ctx *Context, node *shimast.Node) {
|
|
|
157
187
|
// children. The per-node printers join child docs with a fresh
|
|
158
188
|
// `, ` separator and have no path for trivia between siblings, so
|
|
159
189
|
// reflowing such a node would silently delete the comment.
|
|
160
|
-
// Conservative
|
|
190
|
+
// Conservative, false positives mean a missed reflow opportunity,
|
|
161
191
|
// not a regression. Coverage of inline comments inside lists is
|
|
162
192
|
// the next slice of work.
|
|
163
193
|
if hasNonChildComments(node, src, start, end) {
|
|
164
194
|
return
|
|
165
195
|
}
|
|
166
196
|
|
|
167
|
-
printOpts.StartingColumn = leadingColumn(src, start, printOpts.TabWidth)
|
|
168
197
|
// A node reflowed on a ternary-arm continuation line (`? expr` or
|
|
169
198
|
// `: expr`) hangs its broken continuation under the arm's expression,
|
|
170
|
-
// two columns past the `?`/`:` marker
|
|
199
|
+
// two columns past the `?`/`:` marker, not under the marker itself.
|
|
171
200
|
printOpts.BaseIndent = lineLeadingIndent(src, start, printOpts.TabWidth) +
|
|
172
201
|
ternaryArmIndentBonus(src, start)
|
|
173
202
|
|
|
174
|
-
// trailingWidth is the column span of the tokens that stay on the
|
|
175
|
-
// node's last line after `end` — a `;`, a `);`, a `) {`. The reflow
|
|
176
|
-
// replaces only [start, end) and cannot move them, so both the fast
|
|
177
|
-
// path and the layout budget must reserve those columns; otherwise
|
|
178
|
-
// the rule emits a line that overflows by exactly the suffix.
|
|
179
|
-
trailingWidth := trailingLineWidth(src, end, printOpts.TabWidth)
|
|
180
|
-
|
|
181
|
-
// Fast path: if the node's existing single-line bytes already fit
|
|
182
|
-
// the printWidth budget — prefix column, node width and trailing
|
|
183
|
-
// suffix all charged — the reflowed output cannot differ from the
|
|
184
|
-
// source (the printer would render the same flat shape). Skip the
|
|
185
|
-
// Doc build + render entirely. This is the common case on
|
|
186
|
-
// well-formatted code — every short call, every short literal —
|
|
187
|
-
// and saves the allocations from PrintNode + Print.
|
|
188
|
-
if !sliceContainsNewline(src, start, end) &&
|
|
189
|
-
printOpts.StartingColumn+(end-start)+trailingWidth <= printOpts.PrintWidth {
|
|
190
|
-
return
|
|
191
|
-
}
|
|
192
|
-
|
|
193
203
|
printCtx := NewPrintContext(ctx.File, printOpts)
|
|
194
204
|
doc, covered := PrintNode(printCtx, node)
|
|
195
205
|
if doc.IsNil() {
|
|
196
206
|
return
|
|
197
207
|
}
|
|
198
208
|
// Safety abstain: the printed subtree contains a multi-line verbatim
|
|
199
|
-
// node
|
|
209
|
+
// node, one the dispatcher has no printer for. Such a node keeps the
|
|
200
210
|
// source columns its lines were written at, while the reflow
|
|
201
211
|
// re-indents everything around it. Emitting the edit would produce
|
|
202
212
|
// inconsistently indented, corrupt output (a callback header at one
|
|
@@ -207,8 +217,8 @@ func (formatPrintWidth) Check(ctx *Context, node *shimast.Node) {
|
|
|
207
217
|
return
|
|
208
218
|
}
|
|
209
219
|
// Render at the full printWidth budget. A reflow that breaks across
|
|
210
|
-
// lines then makes every layout decision
|
|
211
|
-
// where a list explodes
|
|
220
|
+
// lines then makes every layout decision, which call argument hugs,
|
|
221
|
+
// where a list explodes, against the true column budget. The
|
|
212
222
|
// un-movable trailing suffix (`;`, `) {`, ` satisfies T`) lands on a
|
|
213
223
|
// short last line; charging it against the whole budget would
|
|
214
224
|
// wrongly penalize the interior lines and over-break the node.
|
|
@@ -217,7 +227,7 @@ func (formatPrintWidth) Check(ctx *Context, node *shimast.Node) {
|
|
|
217
227
|
// reflow that collapses to a single line. When the flat form plus
|
|
218
228
|
// the suffix would overflow, re-render under a budget shrunk by the
|
|
219
229
|
// suffix so the node breaks instead of spilling the suffix past
|
|
220
|
-
// printWidth
|
|
230
|
+
// printWidth, the regression that keeps a call flat at exactly
|
|
221
231
|
// printWidth while the trailing `;` runs over.
|
|
222
232
|
if trailingWidth > 0 &&
|
|
223
233
|
!strings.Contains(rendered, "\n") &&
|
|
@@ -233,8 +243,8 @@ func (formatPrintWidth) Check(ctx *Context, node *shimast.Node) {
|
|
|
233
243
|
}
|
|
234
244
|
// Safety floor: never emit an edit that makes the widest line wider
|
|
235
245
|
// than it already was. The reflow may be unable to break an
|
|
236
|
-
// un-breakable token run
|
|
237
|
-
// member
|
|
246
|
+
// un-breakable token run, a long string literal, a verbatim object
|
|
247
|
+
// member, but it must never *worsen* the worst line. That is exactly
|
|
238
248
|
// the regression this guards: `ttsc format` collapsing an
|
|
239
249
|
// already-broken, fitting call into one over-wide line. A reflow that
|
|
240
250
|
// only fixes indentation and leaves a pre-existing over-wide line
|
|
@@ -253,19 +263,19 @@ func (formatPrintWidth) Check(ctx *Context, node *shimast.Node) {
|
|
|
253
263
|
}
|
|
254
264
|
|
|
255
265
|
// trailingLineWidth returns the visual column width of src[end:] up to
|
|
256
|
-
// the next newline, with trailing whitespace trimmed. The
|
|
257
|
-
//
|
|
258
|
-
// shares the node's last source line
|
|
259
|
-
// tail, a `, nextArg)` continuation
|
|
266
|
+
// the next newline, with trailing whitespace trimmed. The formatPrintWidth
|
|
267
|
+
// reflow replaces only the node's own byte range, so whatever
|
|
268
|
+
// shares the node's last source line, a statement `;`, a `) {` header
|
|
269
|
+
// tail, a `, nextArg)` continuation, stays put. Charging that width
|
|
260
270
|
// against the budget keeps the rule from emitting a line that overflows
|
|
261
271
|
// by exactly the suffix it could never move.
|
|
262
272
|
//
|
|
263
273
|
// Trailing `//` line comments are excluded from the budget. A line
|
|
264
274
|
// comment runs to the end of the source line by definition, so breaking
|
|
265
|
-
// the reflowed node to make the comment fit cannot help
|
|
275
|
+
// the reflowed node to make the comment fit cannot help, Prettier 3
|
|
266
276
|
// keeps the node inline and lets the comment trail (see typeorm's
|
|
267
277
|
// `comment.replaceAll(...) // Null bytes' shape that pushed
|
|
268
|
-
// `
|
|
278
|
+
// `formatPrintWidth: 'off'` onto the ttsc-lint benchmark branch).
|
|
269
279
|
// Excluding the comment from `trailingLineWidth` matches that
|
|
270
280
|
// behavior: the fast path sees just the un-movable punctuation suffix,
|
|
271
281
|
// and the shrunk-budget re-render does not over-shrink and over-break.
|
|
@@ -302,7 +312,7 @@ func trailingSuffixEnd(src string, end int) int {
|
|
|
302
312
|
if src[lineEnd] == '/' && lineEnd+1 < len(src) {
|
|
303
313
|
next := src[lineEnd+1]
|
|
304
314
|
if next == '/' {
|
|
305
|
-
// `//` line comment
|
|
315
|
+
// `//` line comment, Prettier treats the whole tail as a
|
|
306
316
|
// trailing comment that runs to EOL. Drop it from the suffix
|
|
307
317
|
// budget so the rule does not break the node to chase a
|
|
308
318
|
// comment that cannot be moved or wrapped.
|
|
@@ -322,8 +332,8 @@ func trailingSuffixEnd(src string, end int) int {
|
|
|
322
332
|
}
|
|
323
333
|
|
|
324
334
|
// maxLineWidth returns the widest effective column span among the lines
|
|
325
|
-
// of `text`. The first line is charged `startingColumn
|
|
326
|
-
// already on that source line that the reflow does not re-emit
|
|
335
|
+
// of `text`. The first line is charged `startingColumn`, the prefix
|
|
336
|
+
// already on that source line that the reflow does not re-emit, and
|
|
327
337
|
// the last line is charged `trailingWidth` for the un-movable suffix
|
|
328
338
|
// that follows the node. Tabs count as `tabWidth` columns.
|
|
329
339
|
//
|
|
@@ -389,7 +399,7 @@ func leadingColumn(src string, pos int, tabWidth int) int {
|
|
|
389
399
|
//
|
|
390
400
|
// Continuation lines (Hardline / broken-mode Line) emitted by the
|
|
391
401
|
// reflow doc should align relative to this value, not relative to the
|
|
392
|
-
// node's leading column
|
|
402
|
+
// node's leading column, see PrintOptions.BaseIndent for the contract.
|
|
393
403
|
//
|
|
394
404
|
// When the visited node lives on a *continuation line* (e.g. an RHS
|
|
395
405
|
// expression hanging below a binary operator on the previous line),
|
|
@@ -457,12 +467,12 @@ func lineStartOffset(src string, pos int) int {
|
|
|
457
467
|
|
|
458
468
|
// ternaryArmIndentBonus returns 2 when the line containing `pos` begins,
|
|
459
469
|
// after its leading whitespace, with a `? ` or `: ` ternary-arm marker,
|
|
460
|
-
// and 0 otherwise.
|
|
470
|
+
// and 0 otherwise. formatPrintWidth adds it to BaseIndent so a node
|
|
461
471
|
// reflowed inside a ternary arm indents its broken continuation under
|
|
462
472
|
// the arm's expression rather than under the `?`/`:` token. In practice
|
|
463
473
|
// only a ternary arm opens a reflow target's line with `? ` / `: `; the
|
|
464
474
|
// two-byte prefix is a heuristic, and a rare false positive only shifts
|
|
465
|
-
// a broken continuation by two columns
|
|
475
|
+
// a broken continuation by two columns, it never corrupts bytes.
|
|
466
476
|
func ternaryArmIndentBonus(src string, pos int) int {
|
|
467
477
|
i := lineStartOffset(src, pos)
|
|
468
478
|
for i < len(src) && (src[i] == ' ' || src[i] == '\t') {
|
|
@@ -475,7 +485,7 @@ func ternaryArmIndentBonus(src string, pos int) int {
|
|
|
475
485
|
}
|
|
476
486
|
|
|
477
487
|
// hasReflowAncestor reports whether any ancestor of `node` would also
|
|
478
|
-
// match the
|
|
488
|
+
// match the formatPrintWidth visitor. The rule uses this to suppress
|
|
479
489
|
// nested fires when an enclosing reflow target already covers the
|
|
480
490
|
// child.
|
|
481
491
|
func hasReflowAncestor(node *shimast.Node) bool {
|
|
@@ -491,7 +501,7 @@ func hasReflowAncestor(node *shimast.Node) bool {
|
|
|
491
501
|
}
|
|
492
502
|
|
|
493
503
|
// hasTemplateSubstitutionAncestor reports whether `node` sits inside a
|
|
494
|
-
// template-literal substitution (`${…}`).
|
|
504
|
+
// template-literal substitution (`${…}`). formatPrintWidth abstains
|
|
495
505
|
// on such nodes: Prettier prints template interpolations at infinite
|
|
496
506
|
// printWidth and only keeps a break the source already had, so a reflow
|
|
497
507
|
// of a nested call or literal would split a one-line `${…}` and never
|
|
@@ -509,7 +519,7 @@ func hasTemplateSubstitutionAncestor(node *shimast.Node) bool {
|
|
|
509
519
|
}
|
|
510
520
|
|
|
511
521
|
// isReflowKind reports whether `k` is one of the node kinds the
|
|
512
|
-
//
|
|
522
|
+
// formatPrintWidth rule visits. Kept in sync with Visits() so
|
|
513
523
|
// hasReflowAncestor does not need to call Visits() at runtime.
|
|
514
524
|
func isReflowKind(k shimast.Kind) bool {
|
|
515
525
|
switch k {
|
|
@@ -519,7 +529,8 @@ func isReflowKind(k shimast.Kind) bool {
|
|
|
519
529
|
shimast.KindNewExpression,
|
|
520
530
|
shimast.KindNamedImports,
|
|
521
531
|
shimast.KindNamedExports,
|
|
522
|
-
shimast.KindImportDeclaration
|
|
532
|
+
shimast.KindImportDeclaration,
|
|
533
|
+
shimast.KindConditionalExpression:
|
|
523
534
|
return true
|
|
524
535
|
}
|
|
525
536
|
return false
|
|
@@ -528,7 +539,7 @@ func isReflowKind(k shimast.Kind) bool {
|
|
|
528
539
|
// hasNonChildComments scans the byte range [start, end) and returns true
|
|
529
540
|
// if any `//` or `/*` lives outside the union of `node`'s direct child
|
|
530
541
|
// byte ranges. The rule uses this to abstain from reflows that would
|
|
531
|
-
// drop inter-child comments
|
|
542
|
+
// drop inter-child comments, the v1 list printers join children with
|
|
532
543
|
// a fresh separator that has no slot for trivia between them.
|
|
533
544
|
//
|
|
534
545
|
// The scan is byte-level for simplicity: a TS scanner would also work
|
|
@@ -537,7 +548,7 @@ func isReflowKind(k shimast.Kind) bool {
|
|
|
537
548
|
// are children, so `"//"` inside them never reaches the comment
|
|
538
549
|
// check). The residual conservative case is comment-shaped bytes
|
|
539
550
|
// inside an inter-child gap that the TS grammar would never tokenize
|
|
540
|
-
// as a comment
|
|
551
|
+
// as a comment, effectively nil for valid TypeScript source.
|
|
541
552
|
//
|
|
542
553
|
// `format/sort-imports` chose the opposite path on a similar shape:
|
|
543
554
|
// it actively preserves inter-specifier comments by walking the
|
|
@@ -558,7 +569,7 @@ func hasNonChildComments(node *shimast.Node, src string, start, end int) bool {
|
|
|
558
569
|
// child.Pos() points at the start of leading trivia, which
|
|
559
570
|
// can include comments belonging to the sibling boundary.
|
|
560
571
|
// Trim past trivia so the inChild check only covers the
|
|
561
|
-
// child's actual token bytes
|
|
572
|
+
// child's actual token bytes, comments between siblings
|
|
562
573
|
// then surface to the scanner below.
|
|
563
574
|
children = append(children, span{shimscanner.SkipTrivia(src, child.Pos()), child.End()})
|
|
564
575
|
return false
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
package linthost
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
5
|
+
shimscanner "github.com/microsoft/typescript-go/shim/scanner"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// formatQuoteProps normalizes quoting of object-literal property keys,
|
|
9
|
+
// mirroring Prettier's `quoteProps`:
|
|
10
|
+
//
|
|
11
|
+
// - "as-needed" (default): drop the quotes from a string key that is a
|
|
12
|
+
// valid identifier and not a numeric-looking key. `{ "foo": 1 }` becomes
|
|
13
|
+
// `{ foo: 1 }`; `{ "bar-baz": 1 }` and `{ "123": 1 }` keep their quotes.
|
|
14
|
+
// - "consistent": if ANY key in the object needs quotes, leave the object
|
|
15
|
+
// alone; otherwise unquote every removable key.
|
|
16
|
+
// - "preserve": never change quoting.
|
|
17
|
+
//
|
|
18
|
+
// Only quoted keys the rule can SAFELY unquote are ever touched: a string
|
|
19
|
+
// whose content is a plain ASCII identifier (letters, `_`, `$`, digits after
|
|
20
|
+
// the first) with no escapes. A key with escapes, unicode, a leading digit
|
|
21
|
+
// (numeric-looking), or any non-identifier byte is left quoted in every
|
|
22
|
+
// mode, so the rule can never produce an invalid key. Idempotent.
|
|
23
|
+
type formatQuoteProps struct{}
|
|
24
|
+
|
|
25
|
+
type formatQuotePropsOptions struct {
|
|
26
|
+
Mode string `json:"mode"`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
func (formatQuoteProps) Name() string { return "format/quote-props" }
|
|
30
|
+
func (formatQuoteProps) IsFormat() bool { return true }
|
|
31
|
+
|
|
32
|
+
func (formatQuoteProps) Visits() []shimast.Kind {
|
|
33
|
+
return []shimast.Kind{shimast.KindObjectLiteralExpression}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
func (formatQuoteProps) Check(ctx *Context, node *shimast.Node) {
|
|
37
|
+
if ctx == nil || ctx.File == nil || node == nil {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
obj := node.AsObjectLiteralExpression()
|
|
41
|
+
if obj == nil || obj.Properties == nil {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
var opts formatQuotePropsOptions
|
|
45
|
+
_ = ctx.DecodeOptions(&opts)
|
|
46
|
+
mode := opts.Mode
|
|
47
|
+
switch mode {
|
|
48
|
+
case "consistent", "preserve", "as-needed":
|
|
49
|
+
default:
|
|
50
|
+
mode = "as-needed"
|
|
51
|
+
}
|
|
52
|
+
if mode == "preserve" {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
src := ctx.File.Text()
|
|
57
|
+
|
|
58
|
+
// removable collects each quoted key that is safely unquotable, paired
|
|
59
|
+
// with its bare identifier. anyMustStayQuoted records whether some quoted
|
|
60
|
+
// key cannot be unquoted (drives "consistent").
|
|
61
|
+
type removableKey struct {
|
|
62
|
+
start, end int
|
|
63
|
+
ident string
|
|
64
|
+
}
|
|
65
|
+
var removable []removableKey
|
|
66
|
+
anyMustStayQuoted := false
|
|
67
|
+
|
|
68
|
+
for _, prop := range obj.Properties.Nodes {
|
|
69
|
+
if prop == nil {
|
|
70
|
+
continue
|
|
71
|
+
}
|
|
72
|
+
name := propertyKeyName(prop)
|
|
73
|
+
if name == nil || name.Kind != shimast.KindStringLiteral {
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
ks := shimscanner.SkipTrivia(src, name.Pos())
|
|
77
|
+
ke := name.End()
|
|
78
|
+
if ks < 0 || ke <= ks || ke > len(src) {
|
|
79
|
+
return // give up on the whole object rather than risk a partial edit
|
|
80
|
+
}
|
|
81
|
+
ident := unquotableIdentifier(src[ks:ke])
|
|
82
|
+
if ident == "" {
|
|
83
|
+
anyMustStayQuoted = true
|
|
84
|
+
continue
|
|
85
|
+
}
|
|
86
|
+
removable = append(removable, removableKey{start: ks, end: ke, ident: ident})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if len(removable) == 0 {
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
// In "consistent" mode, if any key must stay quoted, the whole object is
|
|
93
|
+
// kept quoted, so unquote nothing.
|
|
94
|
+
if mode == "consistent" && anyMustStayQuoted {
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
var edits []TextEdit
|
|
99
|
+
for _, k := range removable {
|
|
100
|
+
edits = append(edits, TextEdit{Pos: k.start, End: k.end, Text: k.ident})
|
|
101
|
+
}
|
|
102
|
+
ctx.ReportRangeFix(
|
|
103
|
+
edits[0].Pos,
|
|
104
|
+
edits[0].End,
|
|
105
|
+
"Object property key does not need quotes.",
|
|
106
|
+
edits...,
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// propertyKeyName returns the static name node of an object-literal property
|
|
111
|
+
// (assignment, method, or accessor), or nil when it has no static name.
|
|
112
|
+
func propertyKeyName(prop *shimast.Node) *shimast.Node {
|
|
113
|
+
switch prop.Kind {
|
|
114
|
+
case shimast.KindPropertyAssignment:
|
|
115
|
+
if p := prop.AsPropertyAssignment(); p != nil {
|
|
116
|
+
return p.Name()
|
|
117
|
+
}
|
|
118
|
+
case shimast.KindMethodDeclaration,
|
|
119
|
+
shimast.KindGetAccessor,
|
|
120
|
+
shimast.KindSetAccessor:
|
|
121
|
+
return prop.Name()
|
|
122
|
+
}
|
|
123
|
+
return nil
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// unquotableIdentifier returns the bare identifier a quoted string key can
|
|
127
|
+
// safely become, or "" when the key must stay quoted. `raw` includes the
|
|
128
|
+
// surrounding quotes. A key is unquotable only when its content is a plain
|
|
129
|
+
// ASCII identifier with no escapes, conservative on purpose: a
|
|
130
|
+
// numeric-looking key (`"123"`), a unicode key, an escaped key, or anything
|
|
131
|
+
// with a non-identifier byte stays quoted, matching Prettier's never
|
|
132
|
+
// unquoting `"123"` and guaranteeing the result is a valid bare key.
|
|
133
|
+
func unquotableIdentifier(raw string) string {
|
|
134
|
+
if len(raw) < 2 {
|
|
135
|
+
return ""
|
|
136
|
+
}
|
|
137
|
+
q := raw[0]
|
|
138
|
+
if (q != '"' && q != '\'') || raw[len(raw)-1] != q {
|
|
139
|
+
return ""
|
|
140
|
+
}
|
|
141
|
+
inner := raw[1 : len(raw)-1]
|
|
142
|
+
if len(inner) == 0 {
|
|
143
|
+
return ""
|
|
144
|
+
}
|
|
145
|
+
if inner == "__proto__" {
|
|
146
|
+
// A bare `__proto__:` key in an object literal is the spec-special
|
|
147
|
+
// prototype setter (sets [[Prototype]]), whereas a quoted `"__proto__"`
|
|
148
|
+
// key is an ordinary own data property. Unquoting would change runtime
|
|
149
|
+
// semantics, so keep it quoted (Prettier does the same).
|
|
150
|
+
return ""
|
|
151
|
+
}
|
|
152
|
+
for i := 0; i < len(inner); i++ {
|
|
153
|
+
c := inner[i]
|
|
154
|
+
isLetter := (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$'
|
|
155
|
+
isDigit := c >= '0' && c <= '9'
|
|
156
|
+
if i == 0 {
|
|
157
|
+
if !isLetter {
|
|
158
|
+
return "" // leading digit (numeric-looking) or other byte: keep quoted
|
|
159
|
+
}
|
|
160
|
+
} else if !isLetter && !isDigit {
|
|
161
|
+
return ""
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return inner
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
func init() {
|
|
168
|
+
Register(formatQuoteProps{})
|
|
169
|
+
}
|