diff --git a/crates/vize/tests/check_server_cli.rs b/crates/vize/tests/check_server_cli.rs index aa8cb7cd1..75ecc089d 100644 --- a/crates/vize/tests/check_server_cli.rs +++ b/crates/vize/tests/check_server_cli.rs @@ -126,7 +126,7 @@ fn check_server_maps_dependency_patch_diagnostics_to_the_parent_sfc() { "message": "Type 'number' is not assignable to type 'string'.", "severity": "error", "line": 7, - "column": 34, + "column": 27, "code": "TS2322" }]) ); diff --git a/crates/vize_canon/src/snapshots/vize_canon__batch__type_checker__tests__batch_type_checker_cross_file_vue_prop_error.snap b/crates/vize_canon/src/snapshots/vize_canon__batch__type_checker__tests__batch_type_checker_cross_file_vue_prop_error.snap index 43a02dcc7..7a5bb1fdd 100644 --- a/crates/vize_canon/src/snapshots/vize_canon__batch__type_checker__tests__batch_type_checker_cross_file_vue_prop_error.snap +++ b/crates/vize_canon/src/snapshots/vize_canon__batch__type_checker__tests__batch_type_checker_cross_file_vue_prop_error.snap @@ -1,5 +1,6 @@ --- source: crates/vize_canon/src/batch/type_checker/tests.rs +assertion_line: 1217 expression: snapshot --- [ @@ -8,6 +9,6 @@ expression: snapshot Some( 2322, ), - "6:18:error Type 'string' is not assignable to type 'number'.", + "6:11:error Type 'string' is not assignable to type 'number'.", ), ] diff --git a/crates/vize_canon/src/virtual_ts/expressions.rs b/crates/vize_canon/src/virtual_ts/expressions.rs index dd9c50867..5eee6a96f 100644 --- a/crates/vize_canon/src/virtual_ts/expressions.rs +++ b/crates/vize_canon/src/virtual_ts/expressions.rs @@ -6,6 +6,7 @@ mod component_props; #[cfg(test)] mod component_props_tests; +mod prop_sources; mod reserved_props; mod statements; mod vif_chain; diff --git a/crates/vize_canon/src/virtual_ts/expressions/component_props.rs b/crates/vize_canon/src/virtual_ts/expressions/component_props.rs index 25f2ff621..0652a2657 100644 --- a/crates/vize_canon/src/virtual_ts/expressions/component_props.rs +++ b/crates/vize_canon/src/virtual_ts/expressions/component_props.rs @@ -7,7 +7,7 @@ use super::super::helpers::{to_camel_case, to_safe_identifier_fragment}; use super::super::types::{VizeMapping, VizeSubSpan}; -use super::reserved_props::rewrite_reserved_template_prop; +use super::prop_sources::{generated_prop_value, prop_name_source_range, prop_value_source_range}; use vize_carton::FxHashMap; use vize_carton::FxHashSet; use vize_carton::String; @@ -15,45 +15,6 @@ use vize_carton::append; use vize_carton::cstr; use vize_carton::profile; use vize_croquis::croquis::{ComponentUsage, PassedProp}; -use vize_croquis::drawer::strip_js_comments; - -fn push_ts_string_literal(out: &mut String, value: &str) { - out.push('"'); - for ch in value.chars() { - match ch { - '\\' => out.push_str("\\\\"), - '"' => out.push_str("\\\""), - '\n' => out.push_str("\\n"), - '\r' => out.push_str("\\r"), - '\t' => out.push_str("\\t"), - _ => out.push(ch), - } - } - out.push('"'); -} - -fn generated_prop_value( - prop: &PassedProp, - template_prop_names: &FxHashSet, -) -> Option { - if !prop.is_dynamic { - let mut value = String::default(); - if let Some(static_value) = prop.value.as_ref() { - push_ts_string_literal(&mut value, static_value.as_str()); - } else { - value.push_str("true"); - } - return Some(value); - } - - let value = strip_js_comments(prop.value.as_ref()?.as_str()); - let trimmed_value = value.as_ref().trim(); - let rewritten_value = rewrite_reserved_template_prop(trimmed_value, template_prop_names); - Some(rewritten_value.as_ref().map_or_else( - || String::from(value.as_ref()), - |s| String::from(s.as_str()), - )) -} fn has_inference_props(usage: &ComponentUsage) -> bool { usage.props.iter().any(is_checkable_prop) @@ -75,20 +36,6 @@ impl<'a> ComponentPropSource<'a> { } } -fn prop_value_source_range( - source_context: ComponentPropSource<'_>, - prop: &PassedProp, -) -> Option> { - let source = source_context.template?; - let value = prop.value.as_ref()?.as_str(); - let prop_start = prop.start as usize; - let prop_end = prop.end as usize; - let raw_prop = source.get(prop_start..prop_end)?; - let relative_start = raw_prop.rfind(value)?; - let source_start = source_context.offset as usize + prop_start + relative_start; - Some(source_start..source_start + value.len()) -} - fn collect_generated_class_bindings<'a>( usage: &'a ComponentUsage, template_prop_names: &FxHashSet, @@ -184,21 +131,37 @@ pub(crate) fn generate_component_prop_checks( let check_name_end = ts.len(); append!( *ts, - ": __{component_type_name}_{idx}_prop_{safe_prop_name} = {};\n", - generated_value.as_str(), + ": __{component_type_name}_{idx}_prop_{safe_prop_name} = ", ); + let value_gen_start = ts.len(); + ts.push_str(generated_value.as_str()); + let value_gen_end = ts.len(); + ts.push_str(";\n"); let gen_stmt_end = ts.len(); append!(*ts, "{expr_indent}void {check_name};\n"); + + // The synthetic identifier receives the child prop-type error + // (TS2322-class), which vue-tsc anchors at the attribute name; + // the initializer keeps the exact authored expression so errors + // inside the value land on the authored bytes. + let name_src_range = prop_name_source_range(source_context, prop); + let mut sub_spans = Vec::new(); + if let Some(src_range) = name_src_range.or_else(|| value_src_range.clone()) { + sub_spans.push(VizeSubSpan { + gen_range: check_name_start..check_name_end, + src_range, + }); + } + if let Some(src_range) = value_src_range { + sub_spans.push(VizeSubSpan { + gen_range: value_gen_start..value_gen_end, + src_range, + }); + } mappings.push(VizeMapping { gen_range: gen_stmt_start..gen_stmt_end, src_range: prop_src_start..prop_src_end, - sub_spans: value_src_range - .map(|src_range| VizeSubSpan { - gen_range: check_name_start..check_name_end, - src_range, - }) - .into_iter() - .collect(), + sub_spans, }); if usage.vif_guard.is_some() { diff --git a/crates/vize_canon/src/virtual_ts/expressions/component_props_tests.rs b/crates/vize_canon/src/virtual_ts/expressions/component_props_tests.rs index a476438f1..e674c4732 100644 --- a/crates/vize_canon/src/virtual_ts/expressions/component_props_tests.rs +++ b/crates/vize_canon/src/virtual_ts/expressions/component_props_tests.rs @@ -39,7 +39,7 @@ const isLoading = false } #[test] -fn component_prop_check_maps_synthetic_name_to_bound_expression() { +fn component_prop_check_anchors_name_and_preserves_bound_expression() { let script = r#"import Child from "./Child.vue" const benchmarkMirror = 1 "#; @@ -53,19 +53,37 @@ const benchmarkMirror = 1 let summary = analyzer.finish(); let output = generate_virtual_ts(&summary, Some(script), Some(&root), 0); + + // The synthetic identifier — where the child prop-type error lands — + // anchors at the attribute name, matching vue-tsc. + let name_start = template.find(":code").expect("attribute present") + 1; + let name_range = name_start..name_start + "code".len(); + let name_span = output + .mappings + .iter() + .flat_map(|mapping| &mapping.sub_spans) + .find(|span| span.src_range == name_range) + .expect("component prop check should anchor at the attribute name"); + assert!( + output.code[name_span.gen_range.clone()].starts_with("__vize_prop_check_"), + "synthetic check identifier should map to the attribute name: {name_span:?}" + ); + + // The initializer keeps the exact authored expression range so errors + // inside the value land on the authored bytes. let expression = "String(benchmarkMirror)"; let source_start = template.find(expression).expect("bound expression present"); let source_range = source_start..source_start + expression.len(); - let sub_span = output + let value_span = output .mappings .iter() .flat_map(|mapping| &mapping.sub_spans) .find(|span| span.src_range == source_range) .expect("component prop check should preserve the exact bound expression range"); - - assert!( - output.code[sub_span.gen_range.clone()].starts_with("__vize_prop_check_"), - "synthetic check identifier should map to the bound expression: {sub_span:?}" + assert_eq!( + &output.code[value_span.gen_range.clone()], + expression, + "initializer sub-span should cover the generated expression" ); } @@ -99,18 +117,30 @@ fn static_attribute_values_are_type_checked_like_dynamic_bindings() { output.code ); - // The synthetic check identifier maps back to the authored attribute value. - let value_start = template.find("You did it!").expect("static value present"); - let value_range = value_start..value_start + "You did it!".len(); - let sub_span = output + // The synthetic check identifier anchors at the attribute name, and the + // initializer keeps the authored value range. + let name_start = template.find("msg=").expect("attribute present"); + let name_range = name_start..name_start + "msg".len(); + let name_span = output .mappings .iter() .flat_map(|mapping| &mapping.sub_spans) - .find(|span| span.src_range == value_range) - .expect("static prop check should map to the authored attribute value"); + .find(|span| span.src_range == name_range) + .expect("static prop check should anchor at the attribute name"); assert!( - output.code[sub_span.gen_range.clone()].starts_with("__vize_prop_check_"), - "synthetic check identifier should map to the static value: {sub_span:?}" + output.code[name_span.gen_range.clone()].starts_with("__vize_prop_check_"), + "synthetic check identifier should map to the attribute name: {name_span:?}" + ); + + let value_start = template.find("You did it!").expect("static value present"); + let value_range = value_start..value_start + "You did it!".len(); + assert!( + output + .mappings + .iter() + .flat_map(|mapping| &mapping.sub_spans) + .any(|span| span.src_range == value_range), + "static prop check should keep the authored value range" ); } @@ -207,3 +237,105 @@ const isLoading = false output.code ); } + +#[test] +fn attribute_name_anchor_survives_prefixes_and_modifiers() { + let script = r#"import Child from "./Child.vue" +const bind = 1 +const sync = 2 +const fooBar = 3 +"#; + let template = r#""#; + + let allocator = vize_carton::Bump::new(); + let (root, _) = vize_armature::parse(&allocator, template); + let mut analyzer = Analyzer::with_options(AnalyzerOptions::full()); + analyzer.analyze_script_setup(script); + analyzer.analyze_template(&root); + let summary = analyzer.finish(); + + let output = generate_virtual_ts(&summary, Some(script), Some(&root), 0); + let sub_spans: Vec<_> = output + .mappings + .iter() + .flat_map(|mapping| &mapping.sub_spans) + .collect(); + + let bind_name = template.find("v-bind:bind").expect("v-bind attr") + "v-bind:".len(); + assert!( + sub_spans.iter().any( + |span| span.src_range == (bind_name..bind_name + "bind".len()) + && output.code[span.gen_range.clone()].starts_with("__vize_prop_check_") + ), + "v-bind: prefixed name should anchor after the prefix" + ); + + let sync_name = template.find(":sync.camel").expect("modifier attr") + 1; + assert!( + sub_spans.iter().any( + |span| span.src_range == (sync_name..sync_name + "sync".len()) + && output.code[span.gen_range.clone()].starts_with("__vize_prop_check_") + ), + "modifier attributes should anchor at the name, not the modifier" + ); + + let kebab_name = template.find(":foo-bar").expect("kebab attr") + 1; + assert!( + sub_spans.iter().any( + |span| span.src_range == (kebab_name..kebab_name + "foo-bar".len()) + && output.code[span.gen_range.clone()].starts_with("__vize_prop_check_") + ), + "kebab-case names should anchor across the whole hyphenated name, not a leading segment" + ); +} + +#[test] +fn attribute_name_anchor_uses_utf8_byte_offsets_after_multibyte_text() { + let script = r#"import Child from "./Child.vue" +const total = 1 +"#; + // The static label holds multibyte characters (😀 is 4 UTF-8 bytes / 2 UTF-16 + // units, ハ is 3 UTF-8 bytes) so a byte/char confusion in the source mapping + // would shift every following range. + let template = r#""#; + + let allocator = vize_carton::Bump::new(); + let (root, _) = vize_armature::parse(&allocator, template); + let mut analyzer = Analyzer::with_options(AnalyzerOptions::full()); + analyzer.analyze_script_setup(script); + analyzer.analyze_template(&root); + let summary = analyzer.finish(); + + let output = generate_virtual_ts(&summary, Some(script), Some(&root), 0); + let sub_spans: Vec<_> = output + .mappings + .iter() + .flat_map(|mapping| &mapping.sub_spans) + .collect(); + + // `str::find` returns UTF-8 byte offsets; the multibyte prefix makes the byte + // offset strictly larger than the char count, so these ranges only match when + // the source mapping is byte-indexed. + let name_start = template.find(":count").expect("attribute present") + 1; + assert!( + name_start > template[..name_start].chars().count(), + "fixture must place the prop after multibyte text so byte and char offsets diverge" + ); + let name_range = name_start..name_start + "count".len(); + let name_span = sub_spans + .iter() + .find(|span| span.src_range == name_range) + .expect("prop check should anchor at the attribute name after multibyte text"); + assert!( + output.code[name_span.gen_range.clone()].starts_with("__vize_prop_check_"), + "synthetic check identifier should map to the attribute name: {name_span:?}" + ); + + // The initializer keeps the exact authored expression bytes. + let value_start = template.find("total").expect("bound value present"); + let value_range = value_start..value_start + "total".len(); + assert!( + sub_spans.iter().any(|span| span.src_range == value_range), + "initializer sub-span should keep the authored value bytes after multibyte text" + ); +} diff --git a/crates/vize_canon/src/virtual_ts/expressions/prop_sources.rs b/crates/vize_canon/src/virtual_ts/expressions/prop_sources.rs new file mode 100644 index 000000000..c0d68a166 --- /dev/null +++ b/crates/vize_canon/src/virtual_ts/expressions/prop_sources.rs @@ -0,0 +1,96 @@ +//! Authored source ranges and generated values for component prop checks. +//! +//! These helpers translate one passed prop into the pieces check emission +//! needs: the escaped or rewritten generated value, the authored +//! attribute-name range that anchors child prop-type errors (matching +//! vue-tsc), and the authored value range that anchors errors inside the +//! bound expression. + +use super::component_props::ComponentPropSource; +use super::reserved_props::rewrite_reserved_template_prop; +use vize_carton::FxHashSet; +use vize_carton::String; +use vize_croquis::croquis::PassedProp; +use vize_croquis::drawer::strip_js_comments; + +fn push_ts_string_literal(out: &mut String, value: &str) { + out.push('"'); + for ch in value.chars() { + match ch { + '\\' => out.push_str("\\\\"), + '"' => out.push_str("\\\""), + '\n' => out.push_str("\\n"), + '\r' => out.push_str("\\r"), + '\t' => out.push_str("\\t"), + _ => out.push(ch), + } + } + out.push('"'); +} + +pub(super) fn generated_prop_value( + prop: &PassedProp, + template_prop_names: &FxHashSet, +) -> Option { + if !prop.is_dynamic { + let mut value = String::default(); + if let Some(static_value) = prop.value.as_ref() { + push_ts_string_literal(&mut value, static_value.as_str()); + } else { + value.push_str("true"); + } + return Some(value); + } + + let value = strip_js_comments(prop.value.as_ref()?.as_str()); + let trimmed_value = value.as_ref().trim(); + let rewritten_value = rewrite_reserved_template_prop(trimmed_value, template_prop_names); + Some(rewritten_value.as_ref().map_or_else( + || String::from(value.as_ref()), + |s| String::from(s.as_str()), + )) +} + +pub(super) fn prop_value_source_range( + source_context: ComponentPropSource<'_>, + prop: &PassedProp, +) -> Option> { + let source = source_context.template?; + let value = prop.value.as_ref()?.as_str(); + let prop_start = prop.start as usize; + let prop_end = prop.end as usize; + let raw_prop = source.get(prop_start..prop_end)?; + let relative_start = raw_prop.rfind(value)?; + let source_start = source_context.offset as usize + prop_start + relative_start; + Some(source_start..source_start + value.len()) +} + +/// Returns the authored range of the attribute name itself — `msg` inside +/// `:msg="expr"`, `v-bind:msg="expr"`, or `msg="text"`. +/// +/// vue-tsc anchors prop-type diagnostics at the attribute name, so the +/// synthetic check identifier maps here for byte-identical positions. +pub(super) fn prop_name_source_range( + source_context: ComponentPropSource<'_>, + prop: &PassedProp, +) -> Option> { + let source = source_context.template?; + let prop_start = prop.start as usize; + let raw_prop = source.get(prop_start..prop.end as usize)?; + let name_region = raw_prop.split('=').next().unwrap_or(raw_prop); + let name = prop.name.as_str(); + // The authored name sits right after the binding prefix; matching there + // (instead of searching) keeps names like `bind` from anchoring inside + // `v-bind:` and modifiers like `.sync` from stealing the match. + let prefix_len = if let Some(rest) = name_region.strip_prefix("v-bind:") { + rest.starts_with(name).then_some("v-bind:".len())? + } else if let Some(rest) = name_region.strip_prefix(':') { + rest.starts_with(name).then_some(1)? + } else if name_region.starts_with(name) { + 0 + } else { + name_region.find(name)? + }; + let source_start = source_context.offset as usize + prop_start + prefix_len; + Some(source_start..source_start + name.len()) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d4b2af4fb..b8de2e623 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -204,6 +204,7 @@ catalogs: overrides: '@azure/msal-node>uuid': 11.1.1 + '@hono/node-server': 2.0.11 '@unhead/vue': 2.1.15 brace-expansion@2: 2.1.2 brace-expansion@5: 5.0.7 @@ -211,8 +212,9 @@ overrides: devalue: 5.8.1 dompurify: 3.4.11 esbuild: 0.28.1 + fast-uri: 3.1.4 h3: 1.15.11 - hono: 4.12.25 + hono: 4.12.31 launch-editor: 2.14.1 nanotar: 0.3.0 nitropack: 2.13.4 @@ -222,7 +224,7 @@ overrides: shell-quote: 1.9.0 simple-git: 3.36.0 srvx: 0.11.15 - svgo: 4.0.1 + svgo: 4.0.2 tar: 7.5.19 vite@>=7.0.0 <7.3.5: 7.3.5 yaml: 2.9.0 @@ -1938,11 +1940,11 @@ packages: peerDependencies: tailwindcss: ^3.0 || ^4.0 - '@hono/node-server@1.19.14': - resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} - engines: {node: '>=18.14.1'} + '@hono/node-server@2.0.11': + resolution: {integrity: sha512-bjD221KPLoJTWUwso1J6fGKiTXEUFedG/s0visavY4zakFPkeGURMRNly+FhBHs7T8Dz4qHaZIMX9ZoJHSJtKA==} + engines: {node: '>=20'} peerDependencies: - hono: 4.12.25 + hono: 4.12.31 '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} @@ -7467,8 +7469,8 @@ packages: fast-string-width@3.0.2: resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} + fast-uri@3.1.4: + resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==} fast-wrap-ansi@0.2.0: resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==} @@ -7730,8 +7732,8 @@ packages: hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - hono@4.12.25: - resolution: {integrity: sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ==} + hono@4.12.31: + resolution: {integrity: sha512-zJIHFrl6bq3RDd2YusFNCDlM8qUprxKswyi/OPzPyzKDdyBXDqWx8bZlZ7R+saTdSTatUmb3O7K4SspGPaEOQg==} engines: {node: '>=16.9.0'} hookable@5.5.3: @@ -9665,8 +9667,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - svgo@4.0.1: - resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==} + svgo@4.0.2: + resolution: {integrity: sha512-ekx94z1rRc5LDi6oSUaeRnYhd0UOJxdtQCL2rF8xpWxD3TPAsISWOrxezqGovqS38GRZOdpDfvQe3ts6F7nsng==} engines: {node: '>=16'} hasBin: true @@ -11574,9 +11576,9 @@ snapshots: dependencies: tailwindcss: 3.4.19(tsx@4.22.4)(yaml@2.9.0) - '@hono/node-server@1.19.14(hono@4.12.25)': + '@hono/node-server@2.0.11(hono@4.12.31)': dependencies: - hono: 4.12.25 + hono: 4.12.31 '@humanfs/core@0.19.2': dependencies: @@ -11898,7 +11900,7 @@ snapshots: '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': dependencies: - '@hono/node-server': 1.19.14(hono@4.12.25) + '@hono/node-server': 2.0.11(hono@4.12.31) ajv: 8.20.0 ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 @@ -11908,7 +11910,7 @@ snapshots: eventsource-parser: 3.0.8 express: 5.2.1 express-rate-limit: 8.5.1(express@5.2.1) - hono: 4.12.25 + hono: 4.12.31 jose: 6.2.3 json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 @@ -15483,7 +15485,7 @@ snapshots: ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 + fast-uri: 3.1.4 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -16755,7 +16757,7 @@ snapshots: dependencies: fast-string-truncated-width: 3.0.3 - fast-uri@3.1.2: {} + fast-uri@3.1.4: {} fast-wrap-ansi@0.2.0: dependencies: @@ -17082,7 +17084,7 @@ snapshots: dependencies: react-is: 16.13.1 - hono@4.12.25: {} + hono@4.12.31: {} hookable@5.5.3: {} @@ -18657,7 +18659,7 @@ snapshots: dependencies: postcss: 8.5.15 postcss-value-parser: 4.2.0 - svgo: 4.0.1 + svgo: 4.0.2 postcss-unique-selectors@8.0.0(postcss@8.5.15): dependencies: @@ -19474,7 +19476,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svgo@4.0.1: + svgo@4.0.2: dependencies: commander: 11.1.0 css-select: 5.2.2 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index cf688fc86..a6637353c 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -20,6 +20,7 @@ packages: overrides: "@azure/msal-node>uuid": "11.1.1" + "@hono/node-server": "2.0.11" "@unhead/vue": "2.1.15" "brace-expansion@2": "2.1.2" "brace-expansion@5": "5.0.7" @@ -27,8 +28,9 @@ overrides: devalue: "5.8.1" dompurify: "3.4.11" esbuild: "0.28.1" + fast-uri: "3.1.4" h3: "1.15.11" - hono: "4.12.25" + hono: "4.12.31" launch-editor: "2.14.1" nanotar: "0.3.0" nitropack: "2.13.4" @@ -38,7 +40,7 @@ overrides: shell-quote: "1.9.0" simple-git: "3.36.0" srvx: "0.11.15" - svgo: "4.0.1" + svgo: "4.0.2" tar: "7.5.19" "vite@>=7.0.0 <7.3.5": "7.3.5" yaml: "2.9.0" diff --git a/tests/performance/misskey-lsp-incremental.test.ts b/tests/performance/misskey-lsp-incremental.test.ts index f0a82b4bb..c4715a751 100644 --- a/tests/performance/misskey-lsp-incremental.test.ts +++ b/tests/performance/misskey-lsp-incremental.test.ts @@ -151,7 +151,12 @@ test( }); return waitForDiagnostics(session, componentUri, 4, true); }); - assertSingleInjectedMismatch(sharedBroken.diagnostics, baseline, cleanSource, "binding"); + assertSingleInjectedMismatch( + sharedBroken.diagnostics, + baseline, + cleanSource, + "attribute-name", + ); const sharedRepaired = await metrics.measure("sharedRepaired", async () => { session.notify("textDocument/didChange", { @@ -254,7 +259,7 @@ function assertSingleInjectedMismatch( diagnostics: LspDiagnostic[], baseline: string[], source: string, - expectedRange: "declaration" | "binding" = "declaration", + expectedRange: "declaration" | "attribute-name" = "declaration", ): void { const injected = diagnostics.filter( (diagnostic) => @@ -273,10 +278,12 @@ function assertSingleInjectedMismatch( assert.deepEqual(diagnostic.range?.start, start); assert.deepEqual(diagnostic.range?.end, end); } else { - const bindingOffset = source.indexOf(`String(${symbol})`); - assert.notEqual(bindingOffset, -1); - const start = offsetToPosition(source, bindingOffset); - const end = { line: start.line, character: start.character + `String(${symbol})`.length }; + // The child prop-type mismatch anchors at the attribute name, exactly + // where vue-tsc reports it. + const attributeOffset = source.indexOf(`:code="String(${symbol})"`); + assert.notEqual(attributeOffset, -1); + const start = offsetToPosition(source, attributeOffset + ":".length); + const end = { line: start.line, character: start.character + "code".length }; assert.deepEqual(diagnostic.range?.start, start); assert.deepEqual(diagnostic.range?.end, end); } diff --git a/tests/snapshots/check/__snapshots__/elk-check.snap b/tests/snapshots/check/__snapshots__/elk-check.snap index 051b817d7..3b0f56ec2 100644 --- a/tests/snapshots/check/__snapshots__/elk-check.snap +++ b/tests/snapshots/check/__snapshots__/elk-check.snap @@ -224,7 +224,7 @@ "error:56:29 [TS2554] Expected 2 arguments, but got 1.", "error:69:39 [TS7006] Parameter 'i' implicitly has an 'any' type.", "error:75:36 [TS7006] Parameter 'i' implicitly has an 'any' type.", - "error:90:23 [TS2322] Type 'string | number | symbol' is not assignable to type 'KeyFieldValue | undefined'.\nType 'number' is not assignable to type 'KeyFieldValue | undefined'." + "error:90:12 [TS2322] Type 'string | number | symbol' is not assignable to type 'KeyFieldValue | undefined'.\nType 'number' is not assignable to type 'KeyFieldValue | undefined'." ] }, { diff --git a/tests/snapshots/check/__snapshots__/misskey-check.snap b/tests/snapshots/check/__snapshots__/misskey-check.snap index edb277974..db4771418 100644 --- a/tests/snapshots/check/__snapshots__/misskey-check.snap +++ b/tests/snapshots/check/__snapshots__/misskey-check.snap @@ -1159,8 +1159,8 @@ { "file": "src/pages/admin-user.vue", "diagnostics": [ - "error:190:35 [TS2322] Type 'string' is not assignable to type '\"active-users\" | \"ap-request\" | \"drive\" | \"drive-files\" | \"federation\" | \"instance-drive-files\" | \"instance-drive-files-total\" | \"instance-drive-usage\" | \"instance-drive-usage-total\" | ... 17 more ... | \"users-total\"'.", - "error:192:35 [TS2322] Type 'string' is not assignable to type '\"active-users\" | \"ap-request\" | \"drive\" | \"drive-files\" | \"federation\" | \"instance-drive-files\" | \"instance-drive-files-total\" | \"instance-drive-usage\" | \"instance-drive-usage-total\" | ... 17 more ... | \"users-total\"'." + "error:190:30 [TS2322] Type 'string' is not assignable to type '\"active-users\" | \"ap-request\" | \"drive\" | \"drive-files\" | \"federation\" | \"instance-drive-files\" | \"instance-drive-files-total\" | \"instance-drive-usage\" | \"instance-drive-usage-total\" | ... 17 more ... | \"users-total\"'.", + "error:192:30 [TS2322] Type 'string' is not assignable to type '\"active-users\" | \"ap-request\" | \"drive\" | \"drive-files\" | \"federation\" | \"instance-drive-files\" | \"instance-drive-files-total\" | \"instance-drive-usage\" | \"instance-drive-usage-total\" | ... 17 more ... | \"users-total\"'." ] }, { @@ -1585,8 +1585,7 @@ "file": "src/pages/follow-requests.vue", "diagnostics": [ "error:9:29 [TS2454] Variable 'paginator' is used before being assigned.", - "error:9:30 [TS2454] Variable 'paginator' is used before being assigned.", - "error:9:39 [TS2454] Variable 'paginator' is used before being assigned." + "error:9:30 [TS2454] Variable 'paginator' is used before being assigned." ] }, { @@ -1766,7 +1765,7 @@ { "file": "src/pages/role.vue", "diagnostics": [ - "error:14:91 [TS7006] Parameter 'item' implicitly has an 'any' type." + "error:14:72 [TS7006] Parameter 'item' implicitly has an 'any' type." ] }, { @@ -2392,7 +2391,7 @@ "diagnostics": [] } ], - "errorCount": 40, + "errorCount": 39, "warningCount": 0, "fileCount": 583 } diff --git a/tests/snapshots/check/__snapshots__/nuxt-ui-check.snap b/tests/snapshots/check/__snapshots__/nuxt-ui-check.snap index 21ce02801..c756e0d76 100644 --- a/tests/snapshots/check/__snapshots__/nuxt-ui-check.snap +++ b/tests/snapshots/check/__snapshots__/nuxt-ui-check.snap @@ -209,8 +209,7 @@ "error:5:19 [TS2307] Cannot find module '#build/ui/checkbox' or its corresponding type declarations.", "error:66:40 [TS2307] Cannot find module '#imports' or its corresponding type declarations.", "error:116:54 [TS2304] Cannot find name 'as'.", - "error:116:55 [TS2304] Cannot find name 'as'.", - "error:116:65 [TS2304] Cannot find name 'as'." + "error:116:55 [TS2304] Cannot find name 'as'." ] }, { @@ -261,8 +260,7 @@ "error:338:28 [TS7006] Parameter 'acc' implicitly has an 'any' type.", "error:338:33 [TS7006] Parameter 'result' implicitly has an 'any' type.", "error:378:48 [TS2345] Argument of type 'unknown' is not assignable to parameter of type '(T & { matches?: any; })[]'.", - "error:585:38 [TS2345] Argument of type 'AcceptableValue' is not assignable to parameter of type 'Record | undefined'.\nType 'null' is not assignable to type 'Record | undefined'.", - "error:585:70 [TS2345] Argument of type 'AcceptableValue' is not assignable to parameter of type 'Record | undefined'.\nType 'null' is not assignable to type 'Record | undefined'." + "error:585:38 [TS2345] Argument of type 'AcceptableValue' is not assignable to parameter of type 'Record | undefined'.\nType 'null' is not assignable to type 'Record | undefined'." ] }, { @@ -800,8 +798,8 @@ "error:5:32 [TS2307] Cannot find module '@nuxt/schema' or its corresponding type declarations.", "error:6:19 [TS2307] Cannot find module '#build/ui/pin-input' or its corresponding type declarations.", "error:56:7 [TS2307] Cannot find module '#imports' or its corresponding type declarations.", - "error:130:19 [TS2322] Type 'PinInputValue' is not assignable to type 'string[] | null | undefined'.\nType 'string[] | number[]' is not assignable to type 'string[] | null | undefined'.\nType 'number[]' is not assignable to type 'string[]'.\nType 'number' is not assignable to type 'string'.\nType 'PinInputValue' is not assignable to type 'string[]'.\nType 'string[] | number[]' is not assignable to type 'string[]'.\nType 'number[]' is not assignable to type 'string[]'.\nType 'number' is not assignable to type 'string'.", - "error:131:21 [TS2322] Type 'PinInputValue' is not assignable to type 'string[] | undefined'.\nType 'string[] | number[]' is not assignable to type 'string[] | undefined'.\nType 'number[]' is not assignable to type 'string[]'.\nType 'number' is not assignable to type 'string'.\nType 'PinInputValue' is not assignable to type 'string[]'.\nType 'string[] | number[]' is not assignable to type 'string[]'.\nType 'number[]' is not assignable to type 'string[]'.\nType 'number' is not assignable to type 'string'." + "error:130:6 [TS2322] Type 'PinInputValue' is not assignable to type 'string[] | null | undefined'.\nType 'string[] | number[]' is not assignable to type 'string[] | null | undefined'.\nType 'number[]' is not assignable to type 'string[]'.\nType 'number' is not assignable to type 'string'.\nType 'PinInputValue' is not assignable to type 'string[]'.\nType 'string[] | number[]' is not assignable to type 'string[]'.\nType 'number[]' is not assignable to type 'string[]'.\nType 'number' is not assignable to type 'string'.", + "error:131:6 [TS2322] Type 'PinInputValue' is not assignable to type 'string[] | undefined'.\nType 'string[] | number[]' is not assignable to type 'string[] | undefined'.\nType 'number[]' is not assignable to type 'string[]'.\nType 'number' is not assignable to type 'string'.\nType 'PinInputValue' is not assignable to type 'string[]'.\nType 'string[] | number[]' is not assignable to type 'string[]'.\nType 'number[]' is not assignable to type 'string[]'.\nType 'number' is not assignable to type 'string'." ] }, { @@ -852,7 +850,7 @@ "error:4:32 [TS2307] Cannot find module '@nuxt/schema' or its corresponding type declarations.", "error:5:19 [TS2307] Cannot find module '#build/ui/radio-group' or its corresponding type declarations.", "error:93:92 [TS2307] Cannot find module '#imports' or its corresponding type declarations.", - "error:181:19 [TS2322] Type 'string | number | symbol' is not assignable to type 'DataOrientation | undefined'.\nType 'string' is not assignable to type 'DataOrientation | undefined'." + "error:181:6 [TS2322] Type 'string | number | symbol' is not assignable to type 'DataOrientation | undefined'.\nType 'string' is not assignable to type 'DataOrientation | undefined'." ] }, { @@ -923,7 +921,7 @@ "error:5:32 [TS2307] Cannot find module '@nuxt/schema' or its corresponding type declarations.", "error:6:19 [TS2307] Cannot find module '#build/ui/stepper' or its corresponding type declarations.", "error:83:8 [TS2307] Cannot find module '#imports' or its corresponding type declarations.", - "error:147:76 [TS2322] Type 'string | number | symbol' is not assignable to type 'DataOrientation | undefined'.\nType 'string' is not assignable to type 'DataOrientation | undefined'." + "error:147:63 [TS2322] Type 'string | number | symbol' is not assignable to type 'DataOrientation | undefined'.\nType 'string' is not assignable to type 'DataOrientation | undefined'." ] }, { @@ -957,7 +955,7 @@ "error:5:32 [TS2307] Cannot find module '@nuxt/schema' or its corresponding type declarations.", "error:6:19 [TS2307] Cannot find module '#build/ui/tabs' or its corresponding type declarations.", "error:96:11 [TS2307] Cannot find module '#imports' or its corresponding type declarations.", - "error:145:19 [TS2322] Type 'string | number | symbol' is not assignable to type 'DataOrientation | undefined'.\nType 'string' is not assignable to type 'DataOrientation | undefined'." + "error:145:6 [TS2322] Type 'string | number | symbol' is not assignable to type 'DataOrientation | undefined'.\nType 'string' is not assignable to type 'DataOrientation | undefined'." ] }, { @@ -978,7 +976,7 @@ "error:4:32 [TS2307] Cannot find module '@nuxt/schema' or its corresponding type declarations.", "error:5:19 [TS2307] Cannot find module '#build/ui/timeline' or its corresponding type declarations.", "error:74:10 [TS2307] Cannot find module '#imports' or its corresponding type declarations.", - "error:156:25 [TS2322] Type 'string | number | symbol' is not assignable to type 'DataOrientation | undefined'.\nType 'string' is not assignable to type 'DataOrientation | undefined'." + "error:156:12 [TS2322] Type 'string | number | symbol' is not assignable to type 'DataOrientation | undefined'.\nType 'string' is not assignable to type 'DataOrientation | undefined'." ] }, { @@ -997,10 +995,8 @@ "error:52:40 [TS2307] Cannot find module '#imports' or its corresponding type declarations.", "error:156:43 [TS2339] Property 'startsWith' does not exist on type 'string | number | symbol'.\nProperty 'startsWith' does not exist on type 'number'.", "error:156:44 [TS2339] Property 'startsWith' does not exist on type 'string | number | symbol'.\nProperty 'startsWith' does not exist on type 'number'.", - "error:157:23 [TS2339] Property 'startsWith' does not exist on type 'string | number | symbol'.\nProperty 'startsWith' does not exist on type 'number'.", "error:157:30 [TS2339] Property 'startsWith' does not exist on type 'string | number | symbol'.\nProperty 'startsWith' does not exist on type 'number'.", - "error:157:31 [TS2339] Property 'startsWith' does not exist on type 'string | number | symbol'.\nProperty 'startsWith' does not exist on type 'number'.", - "error:158:21 [TS2339] Property 'startsWith' does not exist on type 'string | number | symbol'.\nProperty 'startsWith' does not exist on type 'number'." + "error:157:31 [TS2339] Property 'startsWith' does not exist on type 'string | number | symbol'.\nProperty 'startsWith' does not exist on type 'number'." ] }, { @@ -1109,7 +1105,6 @@ "error:57:10 [TS2307] Cannot find module '#imports' or its corresponding type declarations.", "error:86:34 [TS2339] Property 'path' does not exist on type 'ContentSurroundLink'.", "error:86:35 [TS2339] Property 'path' does not exist on type 'ContentSurroundLink'.", - "error:86:39 [TS2339] Property 'path' does not exist on type 'ContentSurroundLink'.", "error:96:21 [TS2339] Property 'title' does not exist on type 'ContentSurroundLink'." ] }, @@ -1545,7 +1540,7 @@ ] } ], - "errorCount": 651, + "errorCount": 646, "warningCount": 0, "fileCount": 180 } diff --git a/tests/snapshots/check/__snapshots__/reka-ui-check.snap b/tests/snapshots/check/__snapshots__/reka-ui-check.snap index e4c697662..19a21a477 100644 --- a/tests/snapshots/check/__snapshots__/reka-ui-check.snap +++ b/tests/snapshots/check/__snapshots__/reka-ui-check.snap @@ -468,8 +468,7 @@ "file": "packages/core/src/Combobox/ComboboxAnchor.vue", "diagnostics": [ "error:24:12 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type '__DefineProps'.\nProperty 'as' does not exist on type '__DefineProps'.", - "error:24:13 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type '__DefineProps'.\nProperty 'as' does not exist on type '__DefineProps'.\nType '\"as\"' is not assignable to type 'never'.\nType '\"as\"' is not assignable to type 'never'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\" | \"height\" | \"width\"> & {}'.\nType '\"as\"' is not assignable to type 'never'.\nProperty 'asChild' does not exist on type 'Omit<__LooseRequired, \"as\" | \"height\" | \"width\"> & {}'.\nProperty 'height' does not exist on type 'Omit<__LooseRequired, \"as\" | \"height\" | \"width\"> & {}'.\nType '\"as\"' is not assignable to type 'never'.\nProperty 'rounded' does not exist on type 'Omit<__LooseRequired, \"as\" | \"height\" | \"width\"> & {}'.\nProperty 'width' does not exist on type 'Omit<__LooseRequired, \"as\" | \"height\" | \"width\"> & {}'.\nType '\"as\"' is not assignable to type 'never'.\nProperty 'align' does not exist on type '__DefineProps'.\nProperty 'alignFlip' does not exist on type '__DefineProps'.\nProperty 'alignOffset' does not exist on type '__DefineProps'.\nProperty 'arrowPadding' does not exist on type '__DefineProps'.\nProperty 'avoidCollisions' does not exist on type '__DefineProps'.\nProperty 'collisionBoundary' does not exist on type '__DefineProps'.\nProperty 'collisionPadding' does not exist on type '__DefineProps'.\nProperty 'disableUpdateOnLayoutShift' does not exist on type '__DefineProps'.\nProperty 'hideShiftedArrow' does not exist on type '__DefineProps'.\nProperty 'hideWhenDetached' does not exist on type '__DefineProps'.\nProperty 'positionStrategy' does not exist on type '__DefineProps'.\nProperty 'prioritizePosition' does not exist on type '__DefineProps'.\nProperty 'reference' does not exist on type '__DefineProps'.\nProperty 'side' does not exist on type '__DefineProps'.\nProperty 'sideFlip' does not exist on type '__DefineProps'.\nProperty 'sideOffset' does not exist on type '__DefineProps'.\nProperty 'sticky' does not exist on type '__DefineProps'.\nProperty 'updatePositionStrategy' does not exist on type '__DefineProps'.\nProperty 'align' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'alignFlip' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'alignOffset' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'arrowPadding' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'avoidCollisions' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'collisionBoundary' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'collisionPadding' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'disableUpdateOnLayoutShift' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'hideShiftedArrow' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'hideWhenDetached' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'positionStrategy' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'prioritizePosition' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'reference' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'side' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'sideFlip' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'sideOffset' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'sticky' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'updatePositionStrategy' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'defer' does not exist on type '__DefineProps'.\nProperty 'disabled' does not exist on type '__DefineProps'.\nProperty 'forceMount' does not exist on type '__DefineProps'.\nProperty 'to' does not exist on type '__DefineProps'.", - "error:24:15 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type '__DefineProps'.\nProperty 'as' does not exist on type '__DefineProps'." + "error:24:13 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type '__DefineProps'.\nProperty 'as' does not exist on type '__DefineProps'.\nType '\"as\"' is not assignable to type 'never'.\nType '\"as\"' is not assignable to type 'never'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\" | \"height\" | \"width\"> & {}'.\nType '\"as\"' is not assignable to type 'never'.\nProperty 'asChild' does not exist on type 'Omit<__LooseRequired, \"as\" | \"height\" | \"width\"> & {}'.\nProperty 'height' does not exist on type 'Omit<__LooseRequired, \"as\" | \"height\" | \"width\"> & {}'.\nType '\"as\"' is not assignable to type 'never'.\nProperty 'rounded' does not exist on type 'Omit<__LooseRequired, \"as\" | \"height\" | \"width\"> & {}'.\nProperty 'width' does not exist on type 'Omit<__LooseRequired, \"as\" | \"height\" | \"width\"> & {}'.\nType '\"as\"' is not assignable to type 'never'.\nProperty 'align' does not exist on type '__DefineProps'.\nProperty 'alignFlip' does not exist on type '__DefineProps'.\nProperty 'alignOffset' does not exist on type '__DefineProps'.\nProperty 'arrowPadding' does not exist on type '__DefineProps'.\nProperty 'avoidCollisions' does not exist on type '__DefineProps'.\nProperty 'collisionBoundary' does not exist on type '__DefineProps'.\nProperty 'collisionPadding' does not exist on type '__DefineProps'.\nProperty 'disableUpdateOnLayoutShift' does not exist on type '__DefineProps'.\nProperty 'hideShiftedArrow' does not exist on type '__DefineProps'.\nProperty 'hideWhenDetached' does not exist on type '__DefineProps'.\nProperty 'positionStrategy' does not exist on type '__DefineProps'.\nProperty 'prioritizePosition' does not exist on type '__DefineProps'.\nProperty 'reference' does not exist on type '__DefineProps'.\nProperty 'side' does not exist on type '__DefineProps'.\nProperty 'sideFlip' does not exist on type '__DefineProps'.\nProperty 'sideOffset' does not exist on type '__DefineProps'.\nProperty 'sticky' does not exist on type '__DefineProps'.\nProperty 'updatePositionStrategy' does not exist on type '__DefineProps'.\nProperty 'align' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'alignFlip' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'alignOffset' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'arrowPadding' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'avoidCollisions' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'collisionBoundary' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'collisionPadding' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'disableUpdateOnLayoutShift' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'hideShiftedArrow' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'hideWhenDetached' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'positionStrategy' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'prioritizePosition' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'reference' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'side' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'sideFlip' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'sideOffset' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'sticky' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'updatePositionStrategy' does not exist on type 'Omit<__LooseRequired, \"position\"> & { position: \"inline\" | \"popper\"; }'.\nProperty 'defer' does not exist on type '__DefineProps'.\nProperty 'disabled' does not exist on type '__DefineProps'.\nProperty 'forceMount' does not exist on type '__DefineProps'.\nProperty 'to' does not exist on type '__DefineProps'." ] }, { @@ -608,7 +607,7 @@ "file": "packages/core/src/Combobox/story/ComboboxVirtual.story.vue", "diagnostics": [ "error:2:22 [TS2307] Cannot find module '@iconify/vue' or its corresponding type declarations.", - "error:50:51 [TS7006] Parameter 'opt' implicitly has an 'any' type.", + "error:50:33 [TS7006] Parameter 'opt' implicitly has an 'any' type.", "error:62:24 [TS18047] 'option' is possibly 'null'.", "error:62:31 [TS2339] Property 'label' does not exist on type 'string | number | bigint | Record'.\nProperty 'label' does not exist on type 'string'." ] @@ -1344,8 +1343,7 @@ "file": "packages/core/src/HoverCard/HoverCardTrigger.vue", "diagnostics": [ "error:38:12 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.", - "error:38:13 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.", - "error:38:15 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'." + "error:38:13 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'." ] }, { @@ -1427,22 +1425,22 @@ { "file": "packages/core/src/Listbox/story/ListboxVirtual.story.vue", "diagnostics": [ - "error:24:47 [TS7006] Parameter 'opt' implicitly has an 'any' type.", + "error:24:29 [TS7006] Parameter 'opt' implicitly has an 'any' type.", "error:30:18 [TS18047] 'option' is possibly 'null'.", "error:30:25 [TS2339] Property 'label' does not exist on type 'string | number | bigint | Record'.\nProperty 'label' does not exist on type 'string'.", - "error:48:55 [TS7006] Parameter 'option' implicitly has an 'any' type.", + "error:48:31 [TS7006] Parameter 'option' implicitly has an 'any' type.", "error:55:20 [TS18047] 'option' is possibly 'null'.", "error:55:27 [TS2339] Property 'label' does not exist on type 'string | number | bigint | Record'.\nProperty 'label' does not exist on type 'string'.", - "error:69:55 [TS7006] Parameter 'option' implicitly has an 'any' type.", + "error:69:31 [TS7006] Parameter 'option' implicitly has an 'any' type.", "error:76:20 [TS18047] 'option' is possibly 'null'.", "error:76:27 [TS2339] Property 'label' does not exist on type 'string | number | bigint | Record'.\nProperty 'label' does not exist on type 'string'.", - "error:90:55 [TS7006] Parameter 'option' implicitly has an 'any' type.", + "error:90:31 [TS7006] Parameter 'option' implicitly has an 'any' type.", "error:97:20 [TS18047] 'option' is possibly 'null'.", "error:97:27 [TS2339] Property 'label' does not exist on type 'string | number | bigint | Record'.\nProperty 'label' does not exist on type 'string'.", - "error:111:55 [TS7006] Parameter 'option' implicitly has an 'any' type.", + "error:111:31 [TS7006] Parameter 'option' implicitly has an 'any' type.", "error:118:20 [TS18047] 'option' is possibly 'null'.", "error:118:27 [TS2339] Property 'label' does not exist on type 'string | number | bigint | Record'.\nProperty 'label' does not exist on type 'string'.", - "error:135:55 [TS7006] Parameter 'option' implicitly has an 'any' type.", + "error:135:31 [TS7006] Parameter 'option' implicitly has an 'any' type.", "error:142:20 [TS18047] 'option' is possibly 'null'.", "error:142:27 [TS2339] Property 'label' does not exist on type 'string | number | bigint | Record'.\nProperty 'label' does not exist on type 'string'." ] @@ -2513,10 +2511,8 @@ "error:20:33 [TS2353] Object literal may only specify known properties, and 'as' does not exist in type '__WithDefaultsArgs'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'asChild' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'reference' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.", "error:60:14 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.", "error:60:15 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.", - "error:60:53 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.", "error:71:12 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.", - "error:71:13 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.", - "error:71:15 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'." + "error:71:13 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'." ] }, { @@ -3104,9 +3100,7 @@ "diagnostics": [ "error:114:12 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.", "error:114:13 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.", - "error:114:15 [TS7053] Element implicitly has an 'any' type because expression of type '\"as\"' can't be used to index type 'Omit<__LooseRequired, \"as\"> & {}'.\nProperty 'as' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.", - "error:115:24 [TS2339] Property 'asChild' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'.", - "error:115:32 [TS2339] Property 'asChild' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'." + "error:115:24 [TS2339] Property 'asChild' does not exist on type 'Omit<__LooseRequired, \"as\"> & {}'." ] }, { @@ -3154,41 +3148,41 @@ "file": "packages/core/src/Tree/story/TreeAsync.story.vue", "diagnostics": [ "error:3:22 [TS2307] Cannot find module '@iconify/vue' or its corresponding type declarations.", - "error:77:42 [TS7006] Parameter 'item' implicitly has an 'any' type." + "error:77:20 [TS7006] Parameter 'item' implicitly has an 'any' type." ] }, { "file": "packages/core/src/Tree/story/TreeBasic.story.vue", "diagnostics": [ "error:2:22 [TS2307] Cannot find module '@iconify/vue' or its corresponding type declarations.", - "error:17:40 [TS7006] Parameter 'item' implicitly has an 'any' type." + "error:17:20 [TS7006] Parameter 'item' implicitly has an 'any' type." ] }, { "file": "packages/core/src/Tree/story/TreeCheckbox.story.vue", "diagnostics": [ "error:2:22 [TS2307] Cannot find module '@iconify/vue' or its corresponding type declarations.", - "error:21:40 [TS7006] Parameter 'item' implicitly has an 'any' type." + "error:21:20 [TS7006] Parameter 'item' implicitly has an 'any' type." ] }, { "file": "packages/core/src/Tree/story/TreeNested.story.vue", "diagnostics": [ - "error:16:40 [TS7006] Parameter 'item' implicitly has an 'any' type." + "error:16:20 [TS7006] Parameter 'item' implicitly has an 'any' type." ] }, { "file": "packages/core/src/Tree/story/TreeVirtual.story.vue", "diagnostics": [ "error:2:22 [TS2307] Cannot find module '@iconify/vue' or its corresponding type declarations.", - "error:30:40 [TS7006] Parameter 'item' implicitly has an 'any' type." + "error:30:20 [TS7006] Parameter 'item' implicitly has an 'any' type." ] }, { "file": "packages/core/src/Tree/story/_Tree.vue", "diagnostics": [ "error:3:22 [TS2307] Cannot find module '@iconify/vue' or its corresponding type declarations.", - "error:75:36 [TS7006] Parameter 'item' implicitly has an 'any' type." + "error:75:16 [TS7006] Parameter 'item' implicitly has an 'any' type." ] }, { @@ -3344,7 +3338,7 @@ "diagnostics": [] } ], - "errorCount": 335, + "errorCount": 329, "warningCount": 0, "fileCount": 700 } diff --git a/tests/tooling/lsp-typecheck-template.test.ts b/tests/tooling/lsp-typecheck-template.test.ts index 37c005df7..e4d11c705 100644 --- a/tests/tooling/lsp-typecheck-template.test.ts +++ b/tests/tooling/lsp-typecheck-template.test.ts @@ -221,7 +221,9 @@ import Child from './Child.vue' isDiagnosticsForUri(params, parentUri) && params.diagnostics.some((diagnostic) => diagnostic.message?.includes("not assignable")), )) as PublishDiagnosticsParams; - const bindingStart = offsetToPosition(parent, parent.indexOf("'one'")); + const bindingOffset = parent.indexOf(":count"); + assert.notEqual(bindingOffset, -1); + const bindingStart = offsetToPosition(parent, bindingOffset + ":".length); assert.equal(changedParent.version, 1); assert.deepEqual(changedParent.diagnostics, [ { @@ -229,7 +231,7 @@ import Child from './Child.vue' message: "Type 'string' is not assignable to type 'number'.", range: { start: bindingStart, - end: { line: bindingStart.line, character: bindingStart.character + "'one'".length }, + end: { line: bindingStart.line, character: bindingStart.character + "count".length }, }, severity: 1, source: "vize/types",