theme-check 1.8.0 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +21 -0
- data/README.md +10 -0
- data/RELEASING.md +13 -0
- data/config/default.yml +5 -0
- data/data/shopify_liquid/deprecated_filters.yml +4 -0
- data/data/shopify_liquid/filters.yml +2 -1
- data/docs/checks/schema_json_format.md +76 -0
- data/docs/language_server/code-action-command-palette.png +0 -0
- data/docs/language_server/code-action-flow.png +0 -0
- data/docs/language_server/code-action-keyboard.png +0 -0
- data/docs/language_server/code-action-light-bulb.png +0 -0
- data/docs/language_server/code-action-problem.png +0 -0
- data/docs/language_server/code-action-quickfix.png +0 -0
- data/docs/language_server/how_to_correct_code_with_code_actions_and_execute_command.md +197 -0
- data/lib/theme_check/checks/asset_size_app_block_css.rb +2 -3
- data/lib/theme_check/checks/asset_size_app_block_javascript.rb +2 -3
- data/lib/theme_check/checks/asset_url_filters.rb +2 -0
- data/lib/theme_check/checks/default_locale.rb +1 -1
- data/lib/theme_check/checks/deprecated_filter.rb +79 -4
- data/lib/theme_check/checks/deprecated_global_app_block_type.rb +2 -3
- data/lib/theme_check/checks/matching_schema_translations.rb +4 -6
- data/lib/theme_check/checks/matching_translations.rb +1 -0
- data/lib/theme_check/checks/missing_required_template_files.rb +3 -3
- data/lib/theme_check/checks/missing_template.rb +1 -1
- data/lib/theme_check/checks/pagination_size.rb +2 -3
- data/lib/theme_check/checks/remote_asset.rb +5 -0
- data/lib/theme_check/checks/required_directories.rb +1 -1
- data/lib/theme_check/checks/schema_json_format.rb +29 -0
- data/lib/theme_check/checks/space_inside_braces.rb +132 -87
- data/lib/theme_check/checks/translation_key_exists.rb +33 -13
- data/lib/theme_check/checks/unused_snippet.rb +1 -1
- data/lib/theme_check/checks/valid_html_translation.rb +1 -1
- data/lib/theme_check/checks/valid_schema.rb +2 -2
- data/lib/theme_check/corrector.rb +28 -54
- data/lib/theme_check/file_system_storage.rb +4 -3
- data/lib/theme_check/html_node.rb +99 -6
- data/lib/theme_check/html_visitor.rb +1 -32
- data/lib/theme_check/in_memory_storage.rb +9 -0
- data/lib/theme_check/json_helpers.rb +14 -0
- data/lib/theme_check/language_server/bridge.rb +1 -1
- data/lib/theme_check/language_server/client_capabilities.rb +27 -0
- data/lib/theme_check/language_server/code_action_engine.rb +32 -0
- data/lib/theme_check/language_server/code_action_provider.rb +42 -0
- data/lib/theme_check/language_server/code_action_providers/quickfix_code_action_provider.rb +83 -0
- data/lib/theme_check/language_server/code_action_providers/source_fix_all_code_action_provider.rb +40 -0
- data/lib/theme_check/language_server/configuration.rb +69 -0
- data/lib/theme_check/language_server/diagnostic.rb +124 -0
- data/lib/theme_check/language_server/diagnostics_engine.rb +15 -60
- data/lib/theme_check/language_server/diagnostics_manager.rb +136 -0
- data/lib/theme_check/language_server/document_change_corrector.rb +267 -0
- data/lib/theme_check/language_server/document_link_provider.rb +6 -6
- data/lib/theme_check/language_server/execute_command_engine.rb +19 -0
- data/lib/theme_check/language_server/execute_command_provider.rb +30 -0
- data/lib/theme_check/language_server/execute_command_providers/correction_execute_command_provider.rb +48 -0
- data/lib/theme_check/language_server/execute_command_providers/run_checks_execute_command_provider.rb +22 -0
- data/lib/theme_check/language_server/handler.rb +79 -28
- data/lib/theme_check/language_server/io_messenger.rb +9 -1
- data/lib/theme_check/language_server/server.rb +8 -7
- data/lib/theme_check/language_server/uri_helper.rb +1 -0
- data/lib/theme_check/language_server/versioned_in_memory_storage.rb +69 -0
- data/lib/theme_check/language_server.rb +23 -5
- data/lib/theme_check/liquid_node.rb +249 -39
- data/lib/theme_check/locale_diff.rb +16 -4
- data/lib/theme_check/node.rb +16 -0
- data/lib/theme_check/offense.rb +27 -23
- data/lib/theme_check/regex_helpers.rb +1 -1
- data/lib/theme_check/schema_helper.rb +70 -0
- data/lib/theme_check/storage.rb +4 -0
- data/lib/theme_check/theme.rb +1 -1
- data/lib/theme_check/theme_file.rb +8 -1
- data/lib/theme_check/theme_file_rewriter.rb +18 -9
- data/lib/theme_check/version.rb +1 -1
- data/lib/theme_check.rb +7 -2
- metadata +26 -3
- data/lib/theme_check/language_server/diagnostics_tracker.rb +0 -66
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8c77dfef7eb85a2d0f29abb2b133af2988b5ecfde756a8a976c704844b522fb
|
4
|
+
data.tar.gz: 4acf2c7d7ec6e36282fee4e5fac6d22b28067566579e82bb14bf32bfc6bdb0d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78f577b16e6759aaa0f9ce1165c7eda732f15b1a4c2d67c4fb383773020614f9062badd8d71c946925152026f73b5655b1060c1460910ec91faeaac18f6c0c51
|
7
|
+
data.tar.gz: 110e8010b5a34cc44365b6c4b231afdb0951c49bf6b22b97b28ac12b51c84eef9b1ce0fb84bb69cf75a49aa4c3fe6a40ad00fd9fdf0ee0403e38db1fe1af2045
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,25 @@
|
|
1
1
|
|
2
|
+
v1.9.0 / 2021-12-01
|
3
|
+
===================
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
* Add Corrections as Code Actions in Language Server (quickfix + source.fixAll) (#471)
|
8
|
+
* Add SchemaJsonFormat check ([#512](https://github.com/shopify/theme-check/issues/512))
|
9
|
+
* Add checkOn{Open,Change,Save} Language Server Configurations ([#511](https://github.com/shopify/theme-check/issues/511))
|
10
|
+
* Add support for new filters `image_tag` + `image_url`
|
11
|
+
* Add autocorrection to `img_url` to ease migration
|
12
|
+
* Deprecate `img_tag`, `img_url`
|
13
|
+
|
14
|
+
## Fixes
|
15
|
+
|
16
|
+
* Fix missing null check in ValidHTMLTranslation ([#517](https://github.com/shopify/theme-check/issues/517))
|
17
|
+
* Fix MatchingTranslations check + corrections ([#515](https://github.com/shopify/theme-check/issues/515))
|
18
|
+
* Fix RemoteAsset false positive from settings variables ([#516](https://github.com/shopify/theme-check/issues/516))
|
19
|
+
* Make SpaceInsideBraces work for missing cases ([#509](https://github.com/shopify/theme-check/issues/509))
|
20
|
+
* Fix Liquid in HTML parsing
|
21
|
+
* Make TranslationKeyExists also check section translations
|
22
|
+
|
2
23
|
v1.8.0 / 2021-11-09
|
3
24
|
===================
|
4
25
|
|
data/README.md
CHANGED
@@ -180,3 +180,13 @@ DeprecateLazysizes:
|
|
180
180
|
enabled: true
|
181
181
|
severity: error
|
182
182
|
```
|
183
|
+
|
184
|
+
## Language Server Configurations
|
185
|
+
|
186
|
+
- `themeCheck.checkOnOpen` (default: `true`) makes it so theme check runs on file open.
|
187
|
+
- `themeCheck.checkOnChange` (default: `true`) makes it so theme check runs on file change.
|
188
|
+
- `themeCheck.checkOnSave` (default: `true`) makes it so theme check runs on file save.
|
189
|
+
|
190
|
+
⚠️ **Note:** Quickfixes only work on a freshly checked file. If any of those configurations are turned off, you will need to rerun theme-check in order to apply quickfixes.
|
191
|
+
|
192
|
+
In VS Code, these can be set directly in your `settings.json`.
|
data/RELEASING.md
CHANGED
@@ -24,6 +24,19 @@
|
|
24
24
|
|
25
25
|
6. On [Shipit](https://shipit.shopify.io/shopify/theme-check/rubygems), deploy your commit.
|
26
26
|
|
27
|
+
7. [Create a GitHub release](https://github.com/Shopify/theme-check/releases/new) for the change.
|
28
|
+
|
29
|
+
```
|
30
|
+
VERSION=v1.X.Y
|
31
|
+
git fetch origin
|
32
|
+
git fetch origin --tags
|
33
|
+
git reset origin $VERSION
|
34
|
+
gh release create -t $VERSION
|
35
|
+
```
|
36
|
+
|
37
|
+
(It's a good idea to copy parts of the CHANGELOG in there)
|
38
|
+
|
39
|
+
|
27
40
|
## Homebrew Release Process
|
28
41
|
|
29
42
|
1. Release `theme-check` on RubyGems by following the steps in the previous section.
|
data/config/default.yml
CHANGED
@@ -0,0 +1,76 @@
|
|
1
|
+
# Prevent unformatted schema tags (`SchemaJsonFormat`)
|
2
|
+
|
3
|
+
_Version 1.9.0+_
|
4
|
+
|
5
|
+
This check exists to ensure the JSON in your schemas is pretty.
|
6
|
+
|
7
|
+
It exists as a facilitator for its auto-correction. This way you can right-click fix the problem.
|
8
|
+
|
9
|
+
## Examples
|
10
|
+
|
11
|
+
The following examples contain code snippets that either fail or pass this check.
|
12
|
+
|
13
|
+
### ✗ Fail
|
14
|
+
|
15
|
+
```liquid
|
16
|
+
{% schema %}
|
17
|
+
{
|
18
|
+
"locales": {
|
19
|
+
"en": {
|
20
|
+
"title": "Welcome", "product": "Product"
|
21
|
+
},
|
22
|
+
"fr": { "title": "Bienvenue", "produit": "Produit" }
|
23
|
+
}
|
24
|
+
}
|
25
|
+
{% endschema %}
|
26
|
+
```
|
27
|
+
|
28
|
+
### ✓ Pass
|
29
|
+
|
30
|
+
```liquid
|
31
|
+
{% schema %}
|
32
|
+
{
|
33
|
+
"locales": {
|
34
|
+
"en": {
|
35
|
+
"title": "Welcome",
|
36
|
+
"missing": "Product"
|
37
|
+
},
|
38
|
+
"fr": {
|
39
|
+
"title": "Bienvenue",
|
40
|
+
"missing": "TODO"
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
{% endschema %}
|
45
|
+
```
|
46
|
+
|
47
|
+
## Options
|
48
|
+
|
49
|
+
The following example contains the default configuration for this check:
|
50
|
+
|
51
|
+
```yaml
|
52
|
+
SchemaJsonFormat:
|
53
|
+
enabled: true
|
54
|
+
severity: style
|
55
|
+
start_level: 0
|
56
|
+
indent: ' '
|
57
|
+
```
|
58
|
+
|
59
|
+
| Parameter | Description |
|
60
|
+
| --- | --- |
|
61
|
+
| enabled | Whether the check is enabled. |
|
62
|
+
| severity | The [severity](https://shopify.developers/themes/tools/theme-check/configuration#check-severity) of the check. |
|
63
|
+
| start_level | The indentation level. If you prefer an indented schema, set this to 1. |
|
64
|
+
| indent | The character(s) used for indentation levels. |
|
65
|
+
|
66
|
+
## Disabling this check
|
67
|
+
|
68
|
+
This check is safe to disable. You might want to disable this check if you do not care about the visual appearance of your schema tags.
|
69
|
+
|
70
|
+
## Resources
|
71
|
+
|
72
|
+
- [Rule source][codesource]
|
73
|
+
- [Documentation source][docsource]
|
74
|
+
|
75
|
+
[codesource]: /lib/theme_check/checks/schema_json_format.rb
|
76
|
+
[docsource]: /docs/checks/schema_json_format.md
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# How to correct code with Code Actions, Commands and Workspace Edits
|
2
|
+
|
3
|
+
The [Language Server Protocol (LSP)][lsp] empowers Language Server developers to offer refactorings, quick fixes and the execution of commands to their users. In Theme Check, we take advantage of this to offer quick fixes and autocorrection to users.
|
4
|
+
|
5
|
+
This document exists to give you an overview of how that works.
|
6
|
+
|
7
|
+
## Overview
|
8
|
+
|
9
|
+
It goes like this:
|
10
|
+
|
11
|
+
1. The Client (VS Code, vim, etc.) asks the Server for [Code Actions](#code-actions) at a character position, and the server responds with available `quickfix` and `source.fixAll` code actions.
|
12
|
+
2. The User _may_ select one of the code actions by interacting with the UI (see [visual examples](#code-actions)). The selection triggers the Client to asks the Server to execute a `correction` [Command](#Commands) for certain [Diagnostics](#diagnostic) on behalf of the user.
|
13
|
+
3. The Server asks the Client to apply a [Workspace Edit](#workspace-edits) to fix the diagnostics.
|
14
|
+
|
15
|
+
## Sequence Diagram
|
16
|
+
|
17
|
+
<img src="code-action-flow.png" width="700">
|
18
|
+
|
19
|
+
<details>
|
20
|
+
<summary>Sequence Diagram Explanation</summary>
|
21
|
+
|
22
|
+
1. The Client asks the Server for [code actions](#code-actions) for the current file and character range.
|
23
|
+
2. The Server responds with a list of code actions that can be applied for this location and character range. (`quickfix` and `source.fixAll`)
|
24
|
+
3. ...Wait for user input...
|
25
|
+
4. The User selects one of the code actions
|
26
|
+
5. The Client sends a `workspace/executeCommand` request to the Server for this code action.
|
27
|
+
6. The Server figures out the [workspace edit](#workspace-edits) for the command and arguments.
|
28
|
+
7. The Server sends a `workspace/applyEdit` request for the file modifications that would fix the diagnostics.
|
29
|
+
8. The Client responds with the status of the `applyEdit`.
|
30
|
+
9. The Server cleans up its internal representation of the diagnostics and updates the client with the latest diagnostics.
|
31
|
+
11. The Server responds to the `workspace/executeCommand` request.
|
32
|
+
|
33
|
+
</details>
|
34
|
+
|
35
|
+
## What it's like in the code
|
36
|
+
|
37
|
+
We handle two Client->Server LSP requests:
|
38
|
+
|
39
|
+
1. On `textDocument/codeAction`, our `CodeActionEngine` returns the results obtained from all `CodeActionProvider`.
|
40
|
+
2. On `workspace/executeCommand`, our `ExecuteCommandEngine` dispatches the command and arguments to appropriate `ExecuteCommandProvider`.
|
41
|
+
|
42
|
+
We define providers:
|
43
|
+
|
44
|
+
- Two `CodeActionProvider`:
|
45
|
+
1. [`QuickFixCodeActionProvider`](/lib/theme_check/language_server/code_action_providers/quickfix_code_action_provider.rb) - This one provides code actions that fix _one_ diagnostic.
|
46
|
+
2. [`SourceFixAllCodeActionProvider`](/lib/theme_check/language_server/code_action_providers/source_fix_all_code_action_provider.rb) - This one provides code actions that fix _all diagnostics in the current file_.
|
47
|
+
- One `ExecuteCommandProvider`:
|
48
|
+
1. [`CorrectionExecuteCommandProvider`](/lib/theme_check/language_server/execute_command_providers/correction_execute_command_provider.rb) - This one takes a list of diagnostics as arguments, turns them into a [WorkspaceEdit](#workspace-edit) and tries to apply them with the server->client `workspace/applyEdit` request.
|
49
|
+
|
50
|
+
We define a [`DocumentChangeCorrector`](/lib/theme_check/language_server/document_change_corrector.rb) (an LSP analog to our [`Corrector`](/lib/theme_check/corrector.rb) class). This class turns corrector calls into document changes supported by the LSP. For more details, see the [LSP reference on resource changes][lspresourcechange].
|
51
|
+
|
52
|
+
## Definitions
|
53
|
+
|
54
|
+
### Code Actions
|
55
|
+
|
56
|
+
A [CodeAction][lspcodeaction] is the Language Server Protocol construct for "stuff you might want to do on the code."
|
57
|
+
|
58
|
+
Think refactoring, running tests, fixing lint errors, etc.
|
59
|
+
|
60
|
+
The client figures out which one it can run by executing the client->server `textDocument/codeAction` request.
|
61
|
+
|
62
|
+
<details>
|
63
|
+
<summary>Visual Examples</summary>
|
64
|
+
|
65
|
+
In VS Code, code actions of different kinds have special meanings and are mapped to multiple places in the UI.
|
66
|
+
|
67
|
+
* `Quick Fix...` button on diagnostic hover
|
68
|
+
|
69
|
+
<img src="code-action-quickfix.png" width=500>
|
70
|
+
|
71
|
+
* Diagnostic right click in the problems tab
|
72
|
+
|
73
|
+
<img src="code-action-problem.png" width=500>
|
74
|
+
|
75
|
+
* Command palette `Quick Fix...` and `Fix All`
|
76
|
+
|
77
|
+
<img src="code-action-command-palette.png" width=500>
|
78
|
+
|
79
|
+
* Keyboard shortcuts
|
80
|
+
|
81
|
+
<img src="code-action-keyboard.png" width=700>
|
82
|
+
</details>
|
83
|
+
|
84
|
+
<details>
|
85
|
+
<summary>TypeScript Interface</summary>
|
86
|
+
|
87
|
+
```ts
|
88
|
+
interface CodeAction {
|
89
|
+
title: string; // UI string, human readable for the action
|
90
|
+
kind?: CodeActionKind; // OPTIONAL, for filtering
|
91
|
+
diagnostics?: Diagnostic[]; // The diagnostics that the action SOLVES.
|
92
|
+
isPreferred?: boolean; // Are used by auto fix and can be targetted by keybindings.
|
93
|
+
// Shown as faded out in the code action menu when the user request a more specific type of code action
|
94
|
+
disabled?: {
|
95
|
+
reason: string;
|
96
|
+
},
|
97
|
+
|
98
|
+
// if both edit and command are present, edit is run first then command.
|
99
|
+
// I think edit is used so the client performs the change, wheras the command
|
100
|
+
// would be done by the server
|
101
|
+
edit?: WorkspaceEdit; // what this action does ??!!
|
102
|
+
command?: Command; // the command that it executes
|
103
|
+
data?: any; // sent from the CodeAction to the codeAction/resolve.
|
104
|
+
}
|
105
|
+
|
106
|
+
interface Command {
|
107
|
+
title: string; // Title of the command, like `save`
|
108
|
+
command: string; // id
|
109
|
+
arguments?: any[]
|
110
|
+
}
|
111
|
+
```
|
112
|
+
</details>
|
113
|
+
|
114
|
+
---
|
115
|
+
|
116
|
+
### Commands
|
117
|
+
|
118
|
+
A [Command][lspcommand] is the Language Server Protocol representation of a command that can be executed by the Server.
|
119
|
+
|
120
|
+
Think of them as data representation of function calls that can be made by the Client.
|
121
|
+
|
122
|
+
Typically, a command is associated with a Code Action. If the Client wants to perform this Code Action, it will make a Client->Server `workspace/executeCommand` request.
|
123
|
+
|
124
|
+
<details>
|
125
|
+
<summary>TypeScript Interface</summary>
|
126
|
+
|
127
|
+
```ts
|
128
|
+
interface Command {
|
129
|
+
title: string; // Title of the command, like `save`
|
130
|
+
command: string; // id
|
131
|
+
arguments?: any[]
|
132
|
+
}
|
133
|
+
```
|
134
|
+
</details>
|
135
|
+
|
136
|
+
---
|
137
|
+
|
138
|
+
### Workspace Edits
|
139
|
+
|
140
|
+
A [WorkspaceEdit][lspworkspaceedit] is the Language Server Protocol construct that abstracts code changes as data.
|
141
|
+
|
142
|
+
Think edit file, create file, delete file but as data.
|
143
|
+
|
144
|
+
<details>
|
145
|
+
<summary>TypeScript Interface</summary>
|
146
|
+
|
147
|
+
```ts
|
148
|
+
interface WorkspaceEdit {
|
149
|
+
changes?: { uri: TextEdit[] ];
|
150
|
+
documentChanges: (TextDocumentEdit | CreateFile | RenameFile | DeleteFile|)[];
|
151
|
+
changeAnnotations?: { [id: string]: ChangeAnnotation }
|
152
|
+
}
|
153
|
+
|
154
|
+
// see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#resourceChanges
|
155
|
+
interface CreateFile {
|
156
|
+
kind: 'create';
|
157
|
+
uri: DocumentUri;
|
158
|
+
options?: CreateFileOptions;
|
159
|
+
annotationId?: ChangeAnnotationIdentifier;
|
160
|
+
}
|
161
|
+
|
162
|
+
interface TextEdit {
|
163
|
+
range: Range;
|
164
|
+
newText: string; // can be empty to delete
|
165
|
+
}
|
166
|
+
|
167
|
+
interface TextDocumentEdit {
|
168
|
+
textDocument: OptionalVersionedTextDocumentIdentifier;
|
169
|
+
edits: (TextEdit | AnnotatedTextEdit)[]
|
170
|
+
}
|
171
|
+
|
172
|
+
interface OptionalVersionedTextDocumentIdentifier {
|
173
|
+
uri: TextDocumentURI;
|
174
|
+
// null is for when the file wasn't open from the client
|
175
|
+
// integer is for when you know what it was.
|
176
|
+
version: integer | null;
|
177
|
+
}
|
178
|
+
```
|
179
|
+
</details>
|
180
|
+
|
181
|
+
---
|
182
|
+
|
183
|
+
### Diagnostic
|
184
|
+
|
185
|
+
A [Diagnostic][lspdiagnostic] is the Language Server Protocol construct for errors, warnings and information bubbles.
|
186
|
+
|
187
|
+
In our case, diagnostics are Theme Check offenses.
|
188
|
+
|
189
|
+
They appear in the Problems tab and in the gutter of the editor.
|
190
|
+
|
191
|
+
[lsp]: https://microsoft.github.io/language-server-protocol/specification
|
192
|
+
[lspcodeaction]: https://microsoft.github.io/language-server-protocol/specification#textDocument_codeAction
|
193
|
+
[lspcommand]: https://microsoft.github.io/language-server-protocol/specification#command
|
194
|
+
[lspexecutecommand]: https://microsoft.github.io/language-server-protocol/specification#workspace_executeCommand
|
195
|
+
[lspworkspaceedit]: https://microsoft.github.io/language-server-protocol/specification#workspaceEdit
|
196
|
+
[lspdiagnostic]: https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#diagnostic
|
197
|
+
[lspresourcechange]: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#resourceChanges
|
@@ -18,7 +18,8 @@ module ThemeCheck
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def on_schema(node)
|
21
|
-
schema =
|
21
|
+
schema = node.inner_json
|
22
|
+
return if schema.nil?
|
22
23
|
|
23
24
|
if (stylesheet = schema["stylesheet"])
|
24
25
|
size = asset_size(stylesheet)
|
@@ -29,8 +30,6 @@ module ThemeCheck
|
|
29
30
|
)
|
30
31
|
end
|
31
32
|
end
|
32
|
-
rescue JSON::ParserError
|
33
|
-
# Ignored, handled in ValidSchema.
|
34
33
|
end
|
35
34
|
|
36
35
|
private
|
@@ -18,7 +18,8 @@ module ThemeCheck
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def on_schema(node)
|
21
|
-
schema =
|
21
|
+
schema = node.inner_json
|
22
|
+
return if schema.nil?
|
22
23
|
|
23
24
|
if (javascript = schema["javascript"])
|
24
25
|
size = asset_size(javascript)
|
@@ -29,8 +30,6 @@ module ThemeCheck
|
|
29
30
|
)
|
30
31
|
end
|
31
32
|
end
|
32
|
-
rescue JSON::ParserError
|
33
|
-
# Ignored, handled in ValidSchema.
|
34
33
|
end
|
35
34
|
|
36
35
|
private
|
@@ -8,6 +8,7 @@ module ThemeCheck
|
|
8
8
|
HTML_FILTERS = [
|
9
9
|
'stylesheet_tag',
|
10
10
|
'script_tag',
|
11
|
+
'image_tag',
|
11
12
|
'img_tag',
|
12
13
|
]
|
13
14
|
ASSET_URL_FILTERS = [
|
@@ -16,6 +17,7 @@ module ThemeCheck
|
|
16
17
|
'file_img_url',
|
17
18
|
'file_url',
|
18
19
|
'global_asset_url',
|
20
|
+
'image_url',
|
19
21
|
'img_url',
|
20
22
|
'payment_type_img_url',
|
21
23
|
'shopify_asset_url',
|
@@ -8,7 +8,7 @@ module ThemeCheck
|
|
8
8
|
def on_end
|
9
9
|
return if @theme.default_locale_json
|
10
10
|
add_offense("Default translation file not found (for example locales/en.default.json)") do |corrector|
|
11
|
-
corrector.
|
11
|
+
corrector.create_file(@theme.storage, "locales/#{theme.default_locale}.default.json", "{}")
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -5,18 +5,93 @@ module ThemeCheck
|
|
5
5
|
category :liquid
|
6
6
|
severity :suggestion
|
7
7
|
|
8
|
+
# The image_url filter does not accept width or height values
|
9
|
+
# greater than this numbr.
|
10
|
+
MAX_SIZE = 5760
|
11
|
+
|
8
12
|
def on_variable(node)
|
9
13
|
used_filters = node.value.filters.map { |name, *_rest| name }
|
10
14
|
used_filters.each do |filter|
|
11
15
|
alternatives = ShopifyLiquid::DeprecatedFilter.alternatives(filter)
|
12
16
|
next unless alternatives
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
+
case filter
|
19
|
+
when 'img_url'
|
20
|
+
add_img_url_offense(node)
|
21
|
+
else
|
22
|
+
add_default_offense(node, filter, alternatives)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_default_offense(node, filter, alternatives)
|
28
|
+
alternatives = alternatives.map { |alt| "`#{alt}`" }
|
29
|
+
add_offense(
|
30
|
+
"Deprecated filter `#{filter}`, consider using an alternative: #{alternatives.join(', ')}",
|
31
|
+
node: node,
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_img_url_offense(node)
|
36
|
+
img_url_filter = node.value.filters.find { |filter| filter[0] == "img_url" }
|
37
|
+
_name, img_url_filter_size, img_url_filter_props = img_url_filter
|
38
|
+
size_spec = img_url_filter_size&.dig(0)
|
39
|
+
scale = img_url_filter_props&.delete("scale")
|
40
|
+
|
41
|
+
# Can't correct those.
|
42
|
+
return add_default_offense(node, 'img_url', ['image_url']) unless
|
43
|
+
(size_spec.nil? || size_spec.is_a?(String)) &&
|
44
|
+
(scale.nil? || scale.is_a?(Numeric)) &&
|
45
|
+
size_spec != 'small'
|
46
|
+
|
47
|
+
node_source = node.markup
|
48
|
+
node_start_index = node.start_index
|
49
|
+
match = node_source.match(/img_url[^|]*/)
|
50
|
+
img_url_character_range =
|
51
|
+
(node_start_index + match.begin(0))...(node_start_index + match.end(0))
|
52
|
+
|
53
|
+
scale = (scale || 1).to_i
|
54
|
+
width, height = (size_spec&.split('x') || [100, 100])
|
55
|
+
.map { |v| v.to_i * scale }
|
56
|
+
|
57
|
+
image_url_filter_params = [
|
58
|
+
width && width > 0 ? "width: #{[width, MAX_SIZE].min}" : nil,
|
59
|
+
height && height > 0 ? "height: #{[height, MAX_SIZE].min}" : nil,
|
60
|
+
]
|
61
|
+
image_url_filter_params += (img_url_filter_props || {})
|
62
|
+
.map do |k, v|
|
63
|
+
case v
|
64
|
+
when Liquid::VariableLookup
|
65
|
+
"#{k}: #{v.name}"
|
66
|
+
else
|
67
|
+
"#{k}: #{v}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
image_url_filter_params = image_url_filter_params
|
71
|
+
.reject(&:nil?)
|
72
|
+
.join(", ")
|
73
|
+
|
74
|
+
trailing_whitespace = match[0].match(/\s*\Z/)[0]
|
75
|
+
|
76
|
+
image_url_filter = "image_url"
|
77
|
+
image_url_filter += ": " + image_url_filter_params unless image_url_filter_params.empty?
|
78
|
+
image_url_filter += trailing_whitespace
|
79
|
+
|
80
|
+
add_offense(
|
81
|
+
"Deprecated filter `img_url`, consider using `image_url`",
|
82
|
+
node: node,
|
83
|
+
markup: match[0]
|
84
|
+
) do |corrector|
|
85
|
+
corrector.replace(
|
86
|
+
node,
|
87
|
+
image_url_filter,
|
88
|
+
img_url_character_range,
|
18
89
|
)
|
19
90
|
end
|
91
|
+
|
92
|
+
# If anything goes wrong, fail gracefully by returning the default offense.
|
93
|
+
rescue
|
94
|
+
add_default_offense(node, 'img_url', ['image_url'])
|
20
95
|
end
|
21
96
|
end
|
22
97
|
end
|
@@ -9,7 +9,8 @@ module ThemeCheck
|
|
9
9
|
VALID_GLOBAL_APP_BLOCK_TYPE = "@app"
|
10
10
|
|
11
11
|
def on_schema(node)
|
12
|
-
schema =
|
12
|
+
schema = node.inner_json
|
13
|
+
return if schema.nil?
|
13
14
|
|
14
15
|
if block_types_from(schema).include?(INVALID_GLOBAL_APP_BLOCK_TYPE)
|
15
16
|
add_offense(
|
@@ -17,8 +18,6 @@ module ThemeCheck
|
|
17
18
|
node: node
|
18
19
|
)
|
19
20
|
end
|
20
|
-
rescue JSON::ParserError
|
21
|
-
# Ignored, handled in ValidSchema.
|
22
21
|
end
|
23
22
|
|
24
23
|
def on_case(node)
|
@@ -6,7 +6,8 @@ module ThemeCheck
|
|
6
6
|
doc docs_url(__FILE__)
|
7
7
|
|
8
8
|
def on_schema(node)
|
9
|
-
schema =
|
9
|
+
schema = node.inner_json
|
10
|
+
return if schema.nil?
|
10
11
|
# Get all locales used in the schema
|
11
12
|
used_locales = Set.new([theme.default_locale])
|
12
13
|
visit_object(schema) do |_, locales|
|
@@ -21,17 +22,14 @@ module ThemeCheck
|
|
21
22
|
add_offense("#{key} missing translations for #{missing.join(', ')}", node: node) do |corrector|
|
22
23
|
key = key.split(".")
|
23
24
|
missing.each do |language|
|
24
|
-
|
25
|
+
SchemaHelper.schema_corrector(schema, key + [language], "TODO")
|
25
26
|
end
|
26
|
-
corrector.
|
27
|
+
corrector.replace_inner_json(node, schema)
|
27
28
|
end
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
31
32
|
check_locales(schema, node: node)
|
32
|
-
|
33
|
-
rescue JSON::ParserError
|
34
|
-
# Ignored, handled in ValidSchema.
|
35
33
|
end
|
36
34
|
|
37
35
|
private
|
@@ -25,15 +25,15 @@ module ThemeCheck
|
|
25
25
|
def on_end
|
26
26
|
(REQUIRED_LIQUID_FILES - theme.liquid.map(&:name)).each do |file|
|
27
27
|
add_offense("'#{file}.liquid' is missing") do |corrector|
|
28
|
-
corrector.
|
28
|
+
corrector.create_file(@theme.storage, "#{file}.liquid", "")
|
29
29
|
end
|
30
30
|
end
|
31
31
|
(REQUIRED_TEMPLATE_FILES - (theme.liquid + theme.json).map(&:name)).each do |file|
|
32
32
|
add_offense("'#{file}.liquid' or '#{file}.json' is missing") do |corrector|
|
33
33
|
if REQUIRED_LIQUID_TEMPLATE_FILES.include?(file)
|
34
|
-
corrector.
|
34
|
+
corrector.create_file(@theme.storage, "#{file}.liquid", "")
|
35
35
|
else
|
36
|
-
corrector.
|
36
|
+
corrector.create_file(@theme.storage, "#{file}.json", "")
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -35,7 +35,7 @@ module ThemeCheck
|
|
35
35
|
path = "#{name}.liquid"
|
36
36
|
unless ignore?(path) || theme[name]
|
37
37
|
add_offense("'#{path}' is not found", node: node) do |corrector|
|
38
|
-
corrector.
|
38
|
+
corrector.create_file(@theme.storage, "#{name}.liquid", "")
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -27,13 +27,12 @@ module ThemeCheck
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def on_schema(node)
|
30
|
-
schema =
|
30
|
+
schema = node.inner_json
|
31
|
+
return if schema.nil?
|
31
32
|
|
32
33
|
if (settings = schema["settings"])
|
33
34
|
@schema_settings = settings
|
34
35
|
end
|
35
|
-
rescue JSON::ParserError
|
36
|
-
# Ignored, handled in ValidSchema.
|
37
36
|
end
|
38
37
|
|
39
38
|
##
|