shopify / theme-tools Goto Github PK
View Code? Open in Web Editor NEWEverything developer experience for Shopify themes
Home Page: https://shopify.dev/docs/themes
License: MIT License
Everything developer experience for Shopify themes
Home Page: https://shopify.dev/docs/themes
License: MIT License
I'm using Webpack to build my theme so I have the liquid files inside a /src/static
directory. I keep these static files in the same directory structure as they will be built as.
{% comment %} Inside theme.liquid {% endcomment %}
{% section 'header' %}
So theme-check
extension checks my code automatically and gives me a MissingTemplate
.
Since this file is located at src/static/layout
I would like theme check to look in src/static/sections/header.liquid
If that is not possible maybe a base url setting for the extension for which theme check will be ran in.
This issue focuses on implementing a provider that lists available snippets.
LiquidTagsCompletionProvider
.RenderSnippetCompletionProvider
in Theme Check (TC) Ruby.Something observed in the theme code editor is that the loadResource functionality is triggered on each keystroke because the checks are loading the data from our docsets and schema validators. This will not be great on performance going forward. We should wrap this within the liquid-language-server level to memoize all this data so that we are not triggering potentially expensive functions on every keystroke.
This feature is related to this PR. As per comments left here we need to add some bonus functionality for our ConvertIncludeToRender
check included under DeprecatedTags
. This bonus functionality includes the following requirements:
Some additional notes to help add these bonus requirements is:
Describe the bug
<script>
tag in liquid is adding additional new lines after opening tag and before closing tag on each run of the formatter. In other words, if the formatter runs on the file 5 times, there will be 5 blank lines before and after the contents of the script tag.
Unformatted source
<script>
if (condition) {
...
}
</script>
Expected output
<script>
if (condition) {
...
}
</script>
Actual output
<script>
if (condition) {
...
}
</script>
# then on the next format run
<script>
if (condition) {
...
}
</script>
# and on and on
Debugging information
Additional context
I've only seen this on this script tag. Perhaps the condition block being the only JS within it is the issue?
By default the extension expects .theme-check at root path, it could be useful a configuration editor variable for overriding the default path.
A subset of our remaining checks to migrate will need to know the file size. We need to make sure that all our theme-check usecases will support these checks.
This is supplemental work necessary to unblock the following checks:
Migrate asset_size_app_block_css
Migrate asset_size_css
Migrate asset_size_app_block_javascript
Migrate asset_size_javascript
While doing the first release of the plugin, I've had to backtrack on my approach for formatting HTML attributes.
The prettier rules need to depend on the attribute type. Consider the following
Input:
<img href="https://{{ something.uri }}"
class="image {% if something.border %}image--border{% else %}image--no-border{% endif %}"
srcset="{%- if media.preview_image.width >= 550 -%}{{ media.preview_image | image_url: width: 550 }} 550w,{%- endif -%}
{%- if media.preview_image.width >= 1100 -%}{{ media.preview_image | image_url: width: 1100 }} 1100w,{%- endif -%}
{%- if media.preview_image.width >= 1445 -%}{{ media.preview_image | image_url: width: 1445 }} 1445w,{%- endif -%}
{%- if media.preview_image.width >= 1680 -%}{{ media.preview_image | image_url: width: 1680 }} 1680w,{%- endif -%}
{%- if media.preview_image.width >= 2048 -%}{{ media.preview_image | image_url: width: 2048 }} 2048w,{%- endif -%}
{%- if media.preview_image.width >= 2200 -%}{{ media.preview_image | image_url: width: 2200 }} 2200w,{%- endif -%}
{%- if media.preview_image.width >= 2890 -%}{{ media.preview_image | image_url: width: 2890 }} 2890w,{%- endif -%}
{%- if media.preview_image.width >= 4096 -%}{{ media.preview_image | image_url: width: 4096 }} 4096w,{%- endif -%}
{{ media.preview_image | image_url }} {{ media.preview_image.width }}w"
>
Potential prettier output:
<img
href="https://{{ something.uri }}"
class="
image
{% if something.border %}
image--border
{% else %}
image--no-border
{% endif %}
"
srcset="
{%- if media.preview_image.width >= 550 -%}{{ media.preview_image | image_url: width: 550 }} 550w,{%- endif -%}
{%- if media.preview_image.width >= 1100 -%}{{ media.preview_image | image_url: width: 1100 }} 1100w,{%- endif -%}
{%- if media.preview_image.width >= 1445 -%}{{ media.preview_image | image_url: width: 1445 }} 1445w,{%- endif -%}
{%- if media.preview_image.width >= 1680 -%}{{ media.preview_image | image_url: width: 1680 }} 1680w,{%- endif -%}
{%- if media.preview_image.width >= 2048 -%}{{ media.preview_image | image_url: width: 2048 }} 2048w,{%- endif -%}
{%- if media.preview_image.width >= 2200 -%}{{ media.preview_image | image_url: width: 2200 }} 2200w,{%- endif -%}
{%- if media.preview_image.width >= 2890 -%}{{ media.preview_image | image_url: width: 2890 }} 2890w,{%- endif -%}
{%- if media.preview_image.width >= 4096 -%}{{ media.preview_image | image_url: width: 4096 }} 4096w,{%- endif -%}
{{ media.preview_image | image_url }} {{ media.preview_image.width }}w
"
>
If we put aside the fact that this might be controversial, we have a couple of problems:
href
, we don't want to break at allclass
, we might want to break if statementssrcset
, we're not whitespace sensitive, but we probably want 1 srcset per line by breaking on the line with a commasizes
, similar as aboveThe solution thus needs to handle each case separately.
(What we're doing now) Don't format them at all and paste the attributes as is.
As part of rolling out these features to the world, we have intentions to make all of these code changes publicly available. As part of that, we need to do the following
Describe the bug
If you hover over anything inside the first branch of an {% if %}
statement, then you'll see if
as the result when it should be something else.
During a bughunt for theme-tools, a bug was encountered with the "AssetSizeCSS" check. This check notifies about code issues with 'warning' level severity.
theme.scss.css | asset_url | stylesheet_tag
should not throw a problem
throws a problem.
The file is theme.scss.liquid
(not .css) but gets compiled by the platform as theme.scss.css
.
When users are offline and initiate the language server, the update fails and overwrites files with the default content, which is undesirable.
While downloading files, it is advisable to persist them in a temporary file and only replace the outdated file with the new one if the download is successful:
https://github.com/Shopify/liquid-language-server/blob/5796c5f14c063513f38586f1be7e9fd93f65c26e/packages/node/src/theme-liquid-docs-manager.ts#L65
--
This task is related to https://github.com/Shopify/liquid-language-server/issues/60
Describe the bug
Turns out VS Code caches the result of the completion requests, so if the result only appear if you type end*, then the end* result isn't shown.
We should instead add end
to the list when it makes sense.
Source
<a {% if cond %}attr{% en[] %}>
Expected behaviour
I'd expect endif
to be suggested
Actual behaviour
endif
isn't suggested.
Debugging information
Additional context
Add any other context about the problem here.
This is what we want:
{% case foo %}
{% when bar %}
OK
{% else %}
BAZ
{% endcase %}
Describe the solution you'd like
For HTML attributes that have ValueSets, I'd like to complete the HTML attribute value with one of the values from the value set.
e.g.
<img loading="lazy|eager|auto">
<link rel="...">
Is it possible to add a setting to run theme check on specific files only? Including ways to include files or exclude files would be great.
I have some other liquid (non-Shopify) projects and Theme Check keeps running on all of them.
During a bughunt for theme-tools, a bug was encountered with the "AssetSizeAppBlockCSS" check. This check notifies about code issues with 'warning' level severity.
Getting a cannot access length of undefined
error in AssetSizeAppBlockCSS because the stylesheet
attribute is assumed to exist. It can be undefined.
This crashes the linter.
No errors thrown.
With the move to a new theme-tools repo, we need to come up with a new release strategy now that all our different packages have been brought together.
During a bughunt for theme-tools, a bug was encountered with the "CdnPreconnect" check. This check notifies about code issues with 'warning' level severity.
The documentation for this check does not exist. It has been written in the theme-check
repo, but hasn't been migrated to shopify-dev
.
Working link with completed docs.
Broken link since doc was not migrated.
Input:
<a data-{%if condition%}enabled{%else%}disabled{%endif%}></a>
<a data-{%case number%}{%when 1%}enabled{%else%}disabled{%endcase%}></a>
Actual Output:
<a
data-
{% if condition %}
enabled
{% else %}
disabled
{% endif %}
></a>
<a
data-
{% case number %}
{% when 1 %}
enabled
{% else %}
disabled
{% endcase %}
></a>
Expected
Throw LiquidHTMLError
Is your feature request related to a problem? Please describe.
See #17 for context on what can go wrong.
TL;DR the Vitest VS Code extension does not support it.each nor tests that have the same name. We should write an ESLint/TSLint rule that prevents folks from committing tests that break the Vitest VS Code extension.
Describe the solution you'd like
I would want a rule that warns users against it statements that are taking variables as argument.
e.g.
// bad
const testCases = [...]
for (const testCase of testCases) {
it(`does something for ${testCase.foo}`, () => {
//...
});
}
// also bad
it.each(['a', 'b', 'c'])(async (letter) => {
// ...
});
I would want a rule that warns users against tests that have the same name (OK if in different describe blocks, not ok if it's in the same)
e.g.
describe('Parent1:', () => {
// ok
it('unique', () => {});
// bad, same name at same level
it('not-unique', () => {});
it('not-unique', () => {});
});
describe('Parent2:', () => {
// ok (since in different describe block)
it('unique', () => {});
})
This happens right now:
<form>
<input
type="number"
name="quantity"
>
this text is indented but it shouldn't. And the </form> is not decreased enough as a result.
</form>
The workaround is to use a self closing tag for the void element:
<form>
<input
type="number"
name="quantity"
/>
this works as indented but the void element does not really need to be closed.
</form>
It works fine for non-void elements though:
<form>
<textarea
type="number"
name="quantity"
>
this works as indented.
</textarea>
</form>
This issue is about implementing the provider that lists available theme filters for theme developers.
It's important to ensure that this provider has parity with FilterCompletionProviderTest
, so it's a good idea to import those test cases to TS.
Notice that filters are suggested to compatible types, so a filter that works with strings should be suggested only for string types. For that reason, this task depends on:
LiquidTagsCompletionProvider
is implemented as an example of TS providerFilterCompletionProvider
in TC Ruby as an example of how this provider should workthemeDocset.filters()
During a bughunt for theme-tools, a bug was encountered with the "LiquidHTMLSyntaxError" check. This check notifies about code issues with 'error' level severity.
We need to create documentation for this. This check is essentially a remake of SyntaxError
check in theme-check
but supports HTML
+ Liquid
as well. By updating the SyntaxError
docs we can then simply migrate it to shopify-dev
to fix this issue.
Working link with completed docs.
Non-existant link since doc was not migrated.
Is your feature request related to a problem? Please describe.
We are using liquid templates within text templates that are not HTML (ie, for text email content). When we use the prettier plugin, multiple whitespace and linebreaks get removed.
Describe the solution you'd like
I would love to be able to pass a config option like "textTemplate: true" to make prettier just format the liquid tags and not the text between them.
Describe alternatives you've considered
Have tried looking for other prettier plugins that support liquid but this seems to be the standard one.
Checklist
I believe the extra whitespace is meaningful in text templates. I've read through this link as well: https://github.com/Shopify/prettier-plugin-liquid/blob/main/docs/whitespace-handling.md
I'm not sure if this prettier module is supposed to be specialized for HTML?
Additional context
Here is an example before/after for a template that I'm looking for:
Before:
{% if foo=="bar" %}FOO SPACE{%endif%}
After (current):
{% if foo == "bar" %}FOO SPACE{% endif %}
Desired Output (no removal of the spaces in between FOO
and SPACE
but the spacing within a liquid tag are correct):
{% if foo == "bar" %}FOO SPACE{% endif %}
Describe the bug
Can't seem to change the single quote formatting.
This is my settings.json:
"[liquid]": { "singleQuote": false, "liquidSingleQuote": false, "editor.defaultFormatter": "Shopify.theme-check-vscode" }
and in our prettierrc file we have:
{ "singleQuote": true, "liquidSingleQuote": false, "trailingComma": "all", "semi": true, "printWidth": 100, "overrides": [ { "files": "*.scss", "options": { "singleQuote": false, "printWidth": 120 } }, { "files": "*.liquid", "options": { "singleQuote": false } } ] }
Unformatted source
Expected output
Actual output
Debugging information
Additional context
Add any other context about the problem here.
Something like this might be cool/useful:
{{ 'product.█' }}
I'd like to show the possible translation keys under this namespace:
[
{ label: 'product.cart' },
{ label: 'product.checkout' },
{ ... }
]
Notes:
' | t
as well. But not sure how that will play out.'footer.subscribe'
would have completion docs of "Subscribe to our newsletter"Introduce support for textEdit
Completion Items for Liquid tags.
A CompletionItem incorporates support for the textEdit
field.
The objective of this task is to assess (and implement if feasible) the possibility of using textEdit
to enhance code completion for Liquid tags. For instance, the language server could provide code completion for a for
tag and automatically close it.
textEdit
as well.
Describe the bug
The plugin breaks the line between consequent variables if there is nothing in between.
Unformatted source
Hello {{ FirstName }} and {{ LastName }}
Hello {{ FirstName }} {{ LastName }}
Expected output
Hello {{ FirstName }} and {{ LastName }}
Hello {{ FirstName }} {{ LastName }}
Actual output
Hello {{ FirstName }} and {{ LastName }}
Hello {{ FirstName }}
{{ LastName }}
Debugging information
Performance
theme-check-vscode
1.5.0
Darwin x64 21.6.0
1.70.2
file:///var/folders/lq/znhljk3s2tq3n0sjntmmslyh0000gn/T/Shopify.theme-check-vscode-unresponsive.cpuprofile.txt
Find more details here: https://github.com/microsoft/vscode/wiki/Explain-extension-causes-high-cpu-loa
Shopify.theme-check-vscode-unresponsive.cpuprofile.txt
d
Video explanation: https://videobin.shopify.io/v/LNEwPb
Services must have their ownership defined and service type and subtype configured under the Service Details section in Services DB. See What is a Service? section in our documentation for more context.
Please verify that all the requirements below are met:
An owner is defined
You can assign ownership by visiting the Services DB overview page of your service. It's preferable to assign the ownership to your direct team, but you can also assign to individuals if it makes more sense.
The service type and subtype are set
This guide can help determine a service type. In order to change the service type, click the Edit button beside Classification
in the Service Details section. Avoid Other
and Unknown
as much as you can. If none of the subtypes fit your service, check if there is a tag that better categorizes your service or propose a new tag.
If you select Other
as your service type, this action item will not be considered complete unless you have at least one tag applied to your service.
A slack channel is set
If your service has production platform support enabled, you are required to have a Slack channel set for your service.
Slack is where communication happens. Making sure we can ping you when there's a problem is essential. You can configure your Slack channel on the service overview page.
Exceptions
logistics
tag. There is no requirement for a Slack channel for services in the Logistics org.infra-central
, then it must have an infra-central
tag. There is no requirement for an owner to be set for infra-central
repositories - in the future ownership will be read from infra-central.Services are the Services DB domain concept for any business activity backed by a repository. This includes web apps, libraries, documentation sites or even repositories used for GitHub issue tracking.
Every repository must have an owner tracked via the corresponding service for its business activity.
This action item does apply to you
Defining ownership is important so we can reach out to service owners when there is a problem with their services. It also helps us understand the reason why that service exists.
Service categorization (type, subtype, tags, etc) will help us identify groups of services more easily when defining new action items/health check, for example. It also helps SME teams to find services of their interest when defining policies across Shopify.
There is a risk that your service will be discontinued if we cannot identify the ownership and categorize it properly. This is necessary to mitigate security risks and reduce the operational cost.
At the latest, this should be done before 2023-08-28.
Criteria 1
The following issues were found with this service:
This action item is mandatory for all services. If you still think it does not apply to your service, please reach out to #help-eng-infrastructure.
Please contact the Production Excellence team using #help-eng-infrastructure.
Your service: theme-tools
Action Item: https://services.shopify.io/action-items/instances/47325?editStatus=false
Describe the bug
The VS Code extension hangs if you start it with Wifi down (happened to me during storms last week). It hangs because theme-docs-updater attempts to download latest.json from theme-liquid-docs and it doesn't timeout (or the timeout is long).
We should do something more along the lines of "wait at most 5s and otherwise go with what is on disk".
Something like this:
const timeout = (ms: number) => new Promise((_, reject) => setTimeout(reject, ms));
/**
* The setup method checks that the latest revision matches the one from
* Shopify/theme-liquid-docs. If there's a diff in revision, it means
* that the documentations that you have locally are out of date.
*
* The setup method then downloads the other files.
*/
setup = memo(async (): Promise<void> => {
if (!(await exists(root))) {
await fs.mkdir(root, { recursive: true });
}
const local = await this.latestRevision();
try {
await Promise.race([download('latest'), timeout(2000)]);
const remote = await this.latestRevision();
if (local !== remote) {
await Promise.all(Resources.map((resource) => download(resource)));
}
} catch (_) {
// we're offline...
}
});
During a bughunt for theme-tools, a bug was encountered with the "AssetUrlFilters" check. This check notifies about code issues with 'warning' level severity.
Better error message. We should add something like "for better performance".
Use one of the asset_url filters to serve assets
I'm using LiquidJS which provides a custom block
tag, this plugin doesn't indent the content within this tag correctly, treating anything inside as being on the same level.
Is this intended?
Unformatted source
{% block "popups" %}
{% capture content %}
<div>Hi</div>
{% endcapture %}
{% render "popup", id: "hi", content: content %}
{% endblock %}
Expected output
Unchanged.
Actual output
{% block "popups" %}
{% capture content %}
<div>Hi</div>
{% endcapture %}
{% render "popup", id: "hi", content: content %}
{% endblock %}
Debugging information
During a bughunt for theme-tools, a bug was encountered with the "AssetSizeCSS" check. This check notifies about code issues with 'warning' level severity.
No error shown
Redundant error with MissingAsset (file does not exist)
It would be great to also have it on open-vsx.org, as it is an open platform.
It would make it available to people using VSCodium, Gitpod, etc. It would make for a better experience for more developers, and it would also support open platforms.
Some of the features are harder to discover and wordy to explain.
We could help with that by making bite-sized videos for many of them.
Is your feature request related to a problem? Please describe.
filters.json gives us the expected types of arguments and named parameters.
Describe the solution you'd like
The ObjectCompletionProvider should list variables of the appropriate type when it makes sense.
Describe the bug
Indentation inference bug
Unformatted source
<details
class="group/level-2"
x-trap="getIsMobileNavItemActive('{{ link_forloop.index }}-{{ link_link_forloop.index }}')"
@header-mobile-nav-items-active-change.window="
() => mobileNavItemsActiveChangeEvent($event, '{{ link_forloop.index }}-{{ link_link_forloop.index }}')
"
>
</details>
Expected output
<details
class="group/level-2"
x-trap="getIsMobileNavItemActive('{{ link_forloop.index }}-{{ link_link_forloop.index }}')"
@header-mobile-nav-items-active-change.window="
() => mobileNavItemsActiveChangeEvent($event, '{{ link_forloop.index }}-{{ link_link_forloop.index }}')
"
>
</details>
Actual output
<details
class="group/level-2"
x-trap="getIsMobileNavItemActive('{{ link_forloop.index }}-{{ link_link_forloop.index }}')"
@header-mobile-nav-items-active-change.window="
() => mobileNavItemsActiveChangeEvent($event, '{{ link_forloop.index }}-{{ link_link_forloop.index }}')
"
></details>
Describe the bug
Formatting the document causes quotation marks to be added around output markup that contains | json
, which is not a safe formatting operation if the value being piped to the json
filter is a string.
Unformatted source
No quotes around the tag:
<div
data-something={{ someStringVar | json }}
></div>
Expected output
(no change)
<div
data-something={{ someStringVar | json }}
></div>
Actual output
Adds quotes around tag:
<div
data-something='{{ someStringVar | json }}'
></div>
Which gets evaluated as:
<div
data-something=""someValue""
></div>
(Or maybe that's just the way Chrome renders it on the 'Elements' tab. When I copy the outerHTML to a clipboard it looks like ""someValue""
)
And then the element's dataset
gets changed from:
{
something: 'someValue'
}
to:
{
something: '\"someValue\"'
}
Debugging information
https://github.com/Shopify/liquid-language-server/blob/main/packages/node/src/index.ts#L67-L92
Even though the body and parsed JSON is cached, we're re-reading the file contents on every call to runChecks.
A smarter approach would be to start a file watcher (presumably with chokidar to avoid weird node.js macos/windows file watch issues) and invalidate the cached value on file system file change.
I would expect .html files with the Liquid language associated with them to continue to have the .html icon. Instead, they revert to having the default "text" icon.
This issue focuses on implementing a provider similar to the LiquidTagCompletionProvider
, but for suggesting HTML tags instead of Liquid tags. This will reinforce the LiquidHTML nature of our tooling.
This task requires an additional dependency, html-tags.json
, which is analogous to the tags.json
file we download from Shopify/theme-liquid-docs
. However, the html-tags.json
file will reside in Shopify/liquid-language-server
as a static asset, since it is not a Liquid resource and does not require frequent updates. It can even be placed in the same directory as HTMLTagCompletionProvider
.
Please consider the #28 task, so this provider can automatically close HTML tags, just as we do with Liquid tags.
There are no parity requirements for this feature, as TC Ruby does not have a similar functionality.
LiquidTagsCompletionProvider
.Describe the bug
The minus sign should stick with the percentage sign.
Unformatted source
{%-if customer.name==some_name-%}{%-endif-%}
Expected output
{%- if customer.name == some_name -%}{%- endif -%}
Actual output
{%- if customer.name == some_name- %}{%- endif -%}
Debugging information
Is your feature request related to a problem? Please describe.
Yes, I have *.css.liquid
files that I don't want to be formatted by Shopify VSCODE plugin. Tried using the .prettierignore
file with proper pattern, but this doesn't work.
Describe the solution you'd like
Full support for .prettierignore file.
"Toggle Line Comment" aka comment-out selected text, doesn't work as expected.
Invoking "Toggle Line Comment" twice should comment-out and comment-in the same code
Pressing "Toggle Line Comment" twice more often than not adds comment-endcomment pair twice rather than adding the pair and removing the pair.
Example:
<div class="here be css classes">
</div>
"Toggle Line Comment":
{% comment %} <div class="here be css classes">
</div> {% endcomment %}
All good.
However, if the text selection is slightly different, the commenting functionality becomes buggy:
"Toggle Line Comment":
I believe there are two bugs here:
{% comment %}
or {% endcomment %}
code is selected, the behavior changesFor example:
This correctly uncomments the code:
This fails to uncomment the code and adds another pair of comment tags:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.