Skip to content
This repository has been archived by the owner on Jul 27, 2024. It is now read-only.

Introduce support to range iterations and SFR tags #685

Merged
merged 2 commits into from
Dec 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ def completions(context)

finder = VariableLookupFinder::AssignmentsFinder.new(content)
finder.find!

finder.assignments.map do |label, potential_lookup|
object, _property = VariableLookupTraverser.lookup_object_and_property(potential_lookup)
object_to_completion(label, object.name)
end
finder
.assignments
.map { |label, potential_lookup| object_to_completion(label, object_name(potential_lookup)) }
.compact
end

private
Expand All @@ -31,6 +30,11 @@ def object_to_completion(label, object)
**doc_hash(content),
}
end

def object_name(potential_lookup)
object, _property = VariableLookupTraverser.lookup_object_and_property(potential_lookup)
object&.name
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,36 @@ def <<(node)
case tag
when Liquid::Assign
variable_name = tag.to
variables[variable_name] = assign_tag_as_potential_lookup(tag)
variables[variable_name] = as_potential_lookup(tag.from.name)
when Liquid::For, Liquid::TableRow
variable_name = tag.variable_name
variables[variable_name] = iteration_tag_as_potential_lookup(tag)
variables[variable_name] = as_potential_lookup(tag.collection_name, ['first'])
end
end

private

def assign_tag_as_potential_lookup(tag)
variable_lookup = tag.from.name

unless variable_lookup.is_a?(Liquid::VariableLookup)
return PotentialLookup.new(input_type_of(variable_lookup), [], variables)
def as_potential_lookup(variable_lookup, default_lookups = [])
case variable_lookup
when Liquid::VariableLookup
potential_lookup(variable_lookup, default_lookups)
when Liquid::RangeLookup
as_potential_lookup(variable_lookup.start_obj)
when Enumerable
as_potential_lookup(variable_lookup.first)
else
literal_lookup(variable_lookup)
end

name = variable_lookup.name
lookups = variable_lookup.lookups

PotentialLookup.new(name, lookups, variables)
end

def iteration_tag_as_potential_lookup(tag)
variable_lookup = tag.collection_name
def literal_lookup(variable_lookup)
name = input_type_of(variable_lookup)
PotentialLookup.new(name, [], variables)
end

def potential_lookup(variable_lookup, default_lookups)
name = variable_lookup.name
lookups = [*variable_lookup.lookups, 'first']
lookups = variable_lookup.lookups.concat(default_lookups)

PotentialLookup.new(name, lookups, variables)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ module LanguageServer
module VariableLookupFinder
class AssignmentsFinder
class ScopeVisitor
SCOPE_UNAWARE_NODES = %i(range range_lookup variable variable_lookup)

attr_reader :global_scope, :current_scope

def initialize
Expand All @@ -22,7 +24,7 @@ def visit_template(template)
private

def visit(node, scope)
return if node.type_name == :variable_lookup
return if SCOPE_UNAWARE_NODES.include?(node.type_name)

method = :"on_#{node.type_name}"
scope = @node_handler.send(method, node, scope) if @node_handler.respond_to?(method)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,32 @@ class Unless < Liquid::Unless
include TolerantBlockBody
end

class Paginate < Liquid::Tag
include TolerantBlockBody
end

class Form < Liquid::Tag
include TolerantBlockBody
end

class Style < Liquid::Tag
include TolerantBlockBody
end

class Stylesheet < Liquid::Tag
include TolerantBlockBody
end

def initialize(standard_tags)
@standard_tags = standard_tags
@tolerant_tags = {
'case' => Case,
'for' => For,
'form' => Form,
'if' => If,
'paginate' => Paginate,
'style' => Style,
'stylesheet' => Stylesheet,
'tablerow' => TableRow,
'unless' => Unless,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,23 @@ def setup
{%- liquid
assign target = cart
assign product_2 = product
assign columns_mobile_int = section.settings.columns_mobile_int
assign show_mobile_slider = false
%}
{{
LIQUID
end

def test_suggests_assigned_variables
ShopifyLiquid::Documentation.expects(:object_doc).with("cart")
ShopifyLiquid::Documentation.expects(:object_doc).with("product")
ShopifyLiquid::Documentation.stubs(:object_doc).with("cart")
ShopifyLiquid::Documentation.stubs(:object_doc).with("boolean")
ShopifyLiquid::Documentation.stubs(:object_doc).with("product")
ShopifyLiquid::Documentation.stubs(:object_doc).with(nil)

assert_can_complete_with(@provider, @token, 'target')
assert_can_complete_with(@provider, @token, 'product_2')
assert_can_complete_with(@provider, @token, 'columns_mobile_int')
assert_can_complete_with(@provider, @token, 'show_mobile_slider')
end

def test_does_not_suggest_global_objects
Expand Down
101 changes: 101 additions & 0 deletions test/language_server/variable_lookup_finder/assignments_finder_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,107 @@ def test_assignments_finder_with_for_statements
})
end

def test_assignments_finder_with_for_statements_and_ranges
template = <<~LIQUID
{%- liquid
assign var1 = product
-%}
{%- for var2 in (1..4) -%}
{% echo█
LIQUID

assert_assignments_finder(template, {
'var1' => 'product',
'var2' => 'number',
})
end

def test_assignments_finder_with_for_statements_and_variable_based_ranges
template = <<~LIQUID
{%- liquid
assign var1 = product
-%}
{% assign var2 = 1 %}
{% assign var3 = 4 %}
{%- for var4 in (var2..var3) -%}
{% echo█
LIQUID

assert_assignments_finder(template, {
'var1' => 'product',
'var2' => 'number',
'var3' => 'number',
'var4' => 'var2',
})
end

def test_assignments_finder_with_for_statements_and_variable_and_literal_ranges
template = <<~LIQUID
{%- liquid
assign var1 = product
-%}
{% assign var2 = 1 %}
{%- for var3 in (1..var2) -%}
{% echo█
LIQUID

assert_assignments_finder(template, {
'var1' => 'product',
'var2' => 'number',
'var3' => 'number',
})
end

def test_assignments_finder_with_form_tag
template = <<~LIQUID
{%- form 'localization', id: 'FooterLanguageFormNoScript', class: 'localization-form' -%}
{%- for language in localization.available_languages -%}
<option value="{{ language.█
LIQUID

assert_assignments_finder(template, {
'language' => 'localization',
})
end

def test_assignments_finder_with_paginate_tag
template = <<~LIQUID
{% paginate collection.products by 5 %}
{% for var1 in collection.products -%}
{% echo █
LIQUID

assert_assignments_finder(template, {
'var1' => 'collection',
})
end

def test_assignments_finder_with_style_tag
template = <<~LIQUID
{% style %}
.h1 {
{%- for language in localization.available_languages -%}
<option value="{{ language.█
LIQUID

assert_assignments_finder(template, {
'language' => 'localization',
})
end

def test_assignments_finder_with_stylesheet_tag
template = <<~LIQUID
{% stylesheet %}
.h1 {
{%- for language in localization.available_languages -%}
<option value="{{ language.█
LIQUID

assert_assignments_finder(template, {
'language' => 'localization',
})
end

def test_assignments_finder_with_for_and_else_statements
template = <<~LIQUID
{%- liquid
Expand Down