Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: Shopify/theme-tools
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 8af587dd29350cf91a9a7f6effb60eee3c0b05f0
Choose a base ref
...
head repository: Shopify/theme-tools
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 304d9c8e3c7685fb85e8ddb2f79d5b278291d5bc
Choose a head ref

Commits on Feb 7, 2025

  1. Copy the full SHA
    8bee608 View commit details
  2. Copy the full SHA
    2e4613b View commit details
  3. Copy the full SHA
    e3ba41d View commit details
  4. rebase with main

    EvilGenius13 committed Feb 7, 2025
    Copy the full SHA
    d628ec8 View commit details
  5. Merge pull request #763 from Shopify/example-tag-hover-support

    Example tag hover support
    EvilGenius13 authored Feb 7, 2025
    Copy the full SHA
    bffb95b View commit details
  6. Copy the full SHA
    5eaf295 View commit details
  7. Add hover support for named parameters in {% render %} snippet tags (#…

    …766)
    
    ## What are you adding in this PR?
    Closes Shopify/developer-tools-team#510
    
    **Param with description and type. `@param {String} param-name - description`**
    ![image](https://github.com/user-attachments/assets/af1e3000-3c23-4aab-aeed-0a41dae07d38)
    
    **Param with no description `@param {String} param-name`**
    <img width="274" alt="Screenshot 2025-02-06 at 3 28 46 PM" src="https://github.com/user-attachments/assets/ba21e22f-56a9-422e-b71b-7fae157a6d1a" />
    
    **Param with no type. `@param param-name - desc` **
    <img width="195" alt="Screenshot 2025-02-06 at 3 28 50 PM" src="https://github.com/user-attachments/assets/3f273864-9238-4b8b-bdc1-a064a058a654" />
    
    **Param with no description no type `@param param-name`**
    <img width="267" alt="image" src="https://github.com/user-attachments/assets/d67050ca-dc87-478c-942d-471d33b9e30d" />
    
    **Non-Existent Param**
    - This should be caught in the theme check, so we don't hover anything here
    
    ## What's next? Any followup issues?
    
    Shopify/developer-tools-team#550
    
    ## Before you deploy
    - [x] I included a minor bump `changeset`
    - [x] My feature is backward compatible
    jamesmengo authored Feb 7, 2025
    Copy the full SHA
    8765ff6 View commit details
  8. Copy the full SHA
    e897754 View commit details
  9. Merge pull request #771 from Shopify/jm/fix-node-type-errors

    [Fix] Add nodeType to RenderSnippetParameterHoverProvider test fixtures
    jamesmengo authored Feb 7, 2025
    Copy the full SHA
    aa17e98 View commit details

Commits on Feb 10, 2025

  1. Update README.md

    frandiox authored Feb 10, 2025
    Copy the full SHA
    b0c77b6 View commit details
  2. Theme check for settings keys inside presets and default (#742)

    * Move `block-utils` to common `utils` folder
    * Add `ValidSettingsKey` check for schema
    aswamy authored Feb 10, 2025
    Copy the full SHA
    055cef7 View commit details
  3. Add LiquidDoc parsing support for @description annotation

    -----
    
    We can parse multiple descriptions for a given LiquidDoc, though we will only use the first one if multiple are present.
    This logic will come in future PRs.
    We are NOT adding support for implicit descriptions, which are descriptions that are provided before any other annotations are provided - reference: https://jsdoc.app/tags-description
    jamesmengo committed Feb 10, 2025
    Copy the full SHA
    c4bbf3b View commit details
  4. [LiquidDoc] Parser support for @description annotation (#767)

    ## What are you adding in this PR?
    
    Closes Shopify/developer-tools-team#503
    
    This adds parsing for a `@description` annotation.
    - This annotation can span multiple lines, similar to `@example`
    - This annotation can be defined anywhere in the `liquiddoc` body. It will match until end of input or until the next `@`
    - We are NOT supporting implicit descriptions here - [issue](Shopify/developer-tools-team#558)
    
    ## What's next? Any followup issues?
    Prettier support Shopify/developer-tools-team#504
    
    ## What did you learn?
    - Did a little more reading on [Lexical vs Syntactic rules ](https://ohmjs.org/docs/syntax-reference#syntactic-lexical). Still stewing on what this means in practice, though I think this will help us with whitespace handling. It seems like syntactic rules are useful for high-level grammar structure
    
    ## Before you deploy
    - [x] I included a minor bump `changeset`
    - [x] My feature is backward compatible
    jamesmengo authored Feb 10, 2025
    Copy the full SHA
    da56038 View commit details
  5. Copy the full SHA
    b882641 View commit details
  6. [LiquidDoc] Rename exampleContent to content in concrete example …

    …nodes (#772)
    
    ## What are you adding in this PR?
    Just a quick cleanup to make the attribute accessor a little more consistent with the other types.
    
    No functional change at all.
    jamesmengo authored Feb 10, 2025
    Copy the full SHA
    0b3cdbb View commit details

Commits on Feb 11, 2025

  1. Update the document manager on git operations (#775)

    * Update the document manager on git operations
    
    Tricky part was to not invalidate the cache twice for the same change.
    
    Lots of LSP lifecycle messages (onDidCreateFiles, onDidRenameFiles,
    onDidDeleteFiles, onDidSaveTextDocument) were fired before the
    onDidChangeWatchedFile events.
    
    Had to do a little trick to avoid invalidating the cache twice for
    those.
    
    Fixes #692
    
    * Do all cache invalidation in changeWatchedFiles instead
    
    * Defend against out of order operations
    charlespwd authored Feb 11, 2025
    Copy the full SHA
    e3e1dfd View commit details
  2. Copy the full SHA
    43e411c View commit details
  3. Copy the full SHA
    e9c1d98 View commit details
  4. Add completion support for content_for parameters (#745)

    * Add support for parsing incomplete content_for tags
    * Add completion support for content_for parameters
    graygilmore authored Feb 11, 2025
    Copy the full SHA
    d9dbc26 View commit details
  5. Copy the full SHA
    a410fbe View commit details
  6. Move getSnippetDefinition to theme-check-common (#778)

    ## What are you adding in this PR?
    
    Moving the `liquidDoc` module from `theme-language-server-common` to `theme-check-common`.
    
    This is where `visit` lives, and allows us to us `getSnippetDefinition` in both `theme-language-server-common` and `theme-check-common`
    
    ## What's next? Any followup issues?
    Improving type adherence [here](https://app.graphite.dev/github/pr/Shopify/theme-tools/779/Modify-getSnippetDefinition-to-return-undefined-when-liquidDoc-header-is-not-present)
    
    This is all work I'm doing to enable / improve our ability to write theme checks
    
    ## Before you deploy
    - [x] I included a minor bump `changeset`
    - [x] My feature is backward compatible
    jamesmengo authored Feb 11, 2025
    Copy the full SHA
    5c54d85 View commit details

Commits on Feb 12, 2025

  1. Copy the full SHA
    7b02a67 View commit details
  2. Improve type system adherence of getSnippetDefinition

    - Modify getSnippetDefinition to return an empty liquidDoc object when doc header is present but empty
    - Return only the snippet name when no doc header is found
    jamesmengo committed Feb 12, 2025
    Copy the full SHA
    d32afb7 View commit details
  3. Copy the full SHA
    5a5e2c9 View commit details
  4. Merge pull request #773 from Shopify/fd-remove-discussions-link

    Update README.md
    frandiox authored Feb 12, 2025
    Copy the full SHA
    8f4f8b3 View commit details
  5. Copy the full SHA
    87345c3 View commit details
  6. Merge pull request #782 from Shopify/six-shopify-patch-1

    Update PULL_REQUEST_TEMPLATE.md
    six-shopify authored Feb 12, 2025
    Copy the full SHA
    9381f70 View commit details

Commits on Feb 13, 2025

  1. Modify getSnippetDefinition to return undefined when liquidDoc header…

    … is not present (#779)
    
    ## What are you adding in this PR?
    
    Before this PR, we weren't actually adhering to the types properly. **We weren't returning undefined when expected**
    
    ```
    export type SnippetDefinition = {
        name: string;
        liquidDoc?: LiquidDocDefinition;
    };
    type LiquidDocDefinition = {
        parameters?: LiquidDocParameter[];
        examples?: LiquidDocExample[];
    };
    ```
    
    Now, when:
    - `{% doc %}` header **is not present** -> `.liquidDoc` is `undefined`
    - `{% doc %}` header is **empty** -> `.liquidDoc` is `{}`
    - `@param` or `@example` are not provided -> `liquidDoc.param` or `liquidDoc.example` are `undefined` respectively
    
    This provides more granularity for how we handle hover, checks, etc.
    
    ## What's next? Any followup issues?
    This enables us to write better theme checks for LiquidDoc
    
    ## Before you deploy
    - [x] I included a patch bump `changeset`
    jamesmengo authored Feb 13, 2025
    Copy the full SHA
    9a4cfc9 View commit details
  2. Copy the full SHA
    b1c6abe View commit details
  3. Merge pull request #785 from Shopify/test-helper-should-throw

    `check` test helper shouldn't silently swallow errors
    six-shopify authored Feb 13, 2025
    Copy the full SHA
    aa5bd7c View commit details
  4. Merge pull request #780 from Shopify/add-dev-yml

    add dev.yml with tooling versions
    six-shopify authored Feb 13, 2025
    Copy the full SHA
    05bac7e View commit details

Commits on Feb 14, 2025

  1. Copy the full SHA
    2db3047 View commit details

Commits on Feb 15, 2025

  1. Add ValidRenderSnippetParams check for snippet render validation

    - Verify required parameters are provided
    - Detect and report unknown parameters
    - Add configuration for the new check in recommended and all configs
    jamesmengo committed Feb 15, 2025
    Copy the full SHA
    fe84a17 View commit details
  2. Copy the full SHA
    ee40a1e View commit details
  3. Copy the full SHA
    4db48ac View commit details
  4. Improve edge case handling of theme check fix suggestions for unknown…

    … and missing parameters
    
    Update default value for object type parameters to 'empty'
    jamesmengo committed Feb 15, 2025
    Copy the full SHA
    06b96c5 View commit details

Commits on Feb 18, 2025

  1. Copy the full SHA
    261c295 View commit details
  2. [LiquidDoc][Theme Check] Report missing and unrecognized snippet para…

    …meters in render tag (#791)
    
    ## What are you adding in this PR?
    Closes Shopify/developer-tools-team#516
    Closes Shopify/developer-tools-team#517
    
    
    This introduces theme checks inside the `{% render `snippet-name` %}` snippet tag:
    - **Missing parameters** -> Report
    - **Unrecognized parameters** -> report + suggest fix to remove unrecognized parameters (not in liquid doc)
    
    https://github.com/user-attachments/assets/09ff6efa-265a-4e1a-b495-4ab3d0f755f8
    
    Requirements
    - **Will only report missing parameters if** `snippet-name` refers to a `snippet` with a valid `{% doc %}` header is present **and @params** are defined. 
    - Currently, we don't report for alternative syntaxes for render including
      - `using with / for` (_planned_)
      - referencing a `VariableLookup` rather than providing `snippet-name` as a string (_not planned - explanation in code_)
    
    ## What's next? Any followup issues?
    1) [Type support](https://app.graphite.dev/github/pr/Shopify/theme-tools/792/Implement-a-new-Theme-Check-to-validate-parameters-provided-to-snippets-Check-for-missing-required-parameters-Validate-parameter-types-Report-unknown-parameters)
    2) Support for aliases (?)
    
    ## Before you deploy
    - [x] This PR includes a new checks or changes the configuration of a check
      - [x] I included a minor bump `changeset`
      - [x] It's in the `allChecks` array in `src/checks/index.ts`
      - [x] I ran `yarn build` and committed the updated configuration files
        <!-- It might be that a check doesn't make sense in a theme-app-extension context -->
        <!-- When that happens, the check's config should be updated/overridden in the theme-app-extension config -->
        <!-- see packages/node/configs/theme-app-extension.yml -->
        - [x] If applicable, I've updated the `theme-app-extension.yml` config <- I believe I don't need to update this, since `TAE` can use snippets, @charlespwd could you please confirm?
      - [ ] I've made a PR to update the [shopify.dev theme check docs](https://github.com/Shopify/shopify-dev/tree/main/content/storefronts/themes/tools/theme-check/checks) if applicable (link PR here). <- I will create this PR once I also get `type` checks approved (stacked PR for easier review)
    jamesmengo authored Feb 18, 2025
    Copy the full SHA
    9ff3459 View commit details
  3. Theme Rools Release — 2025-02-18 (#770)

    Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
    github-actions[bot] and github-actions[bot] authored Feb 18, 2025
    Copy the full SHA
    304d9c8 View commit details
Showing with 3,055 additions and 372 deletions.
  1. +1 −0 .github/PULL_REQUEST_TEMPLATE.md
  2. +1 −1 README.md
  3. +8 −0 dev.yml
  4. +2 −1 package.json
  5. +19 −0 packages/liquid-html-parser/CHANGELOG.md
  6. +35 −2 packages/liquid-html-parser/grammar/liquid-html.ohm
  7. +1 −1 packages/liquid-html-parser/package.json
  8. +98 −17 packages/liquid-html-parser/src/stage-1-cst.spec.ts
  9. +51 −7 packages/liquid-html-parser/src/stage-1-cst.ts
  10. +73 −12 packages/liquid-html-parser/src/stage-2-ast.spec.ts
  11. +54 −7 packages/liquid-html-parser/src/stage-2-ast.ts
  12. +1 −0 packages/liquid-html-parser/src/types.ts
  13. +11 −0 packages/prettier-plugin-liquid/CHANGELOG.md
  14. +2 −2 packages/prettier-plugin-liquid/package.json
  15. +2 −0 packages/prettier-plugin-liquid/src/printer/preprocess/augment-with-css-properties.ts
  16. +3 −37 packages/prettier-plugin-liquid/src/printer/print/liquid.ts
  17. +4 −0 packages/prettier-plugin-liquid/src/printer/printer-liquid-html.ts
  18. +0 −14 packages/prettier-plugin-liquid/src/test/liquid-doc/fixed.liquid
  19. +0 −15 packages/prettier-plugin-liquid/src/test/liquid-doc/index.liquid
  20. +10 −0 packages/theme-check-browser/CHANGELOG.md
  21. +2 −2 packages/theme-check-browser/package.json
  22. +25 −0 packages/theme-check-common/CHANGELOG.md
  23. +2 −2 packages/theme-check-common/package.json
  24. +4 −0 packages/theme-check-common/src/checks/index.ts
  25. +0 −1 packages/theme-check-common/src/checks/valid-block-target/index.spec.ts
  26. +1 −1 packages/theme-check-common/src/checks/valid-block-target/index.ts
  27. +291 −0 packages/theme-check-common/src/checks/valid-render-snippet-params/index.spec.ts
  28. +179 −0 packages/theme-check-common/src/checks/valid-render-snippet-params/index.ts
  29. +321 −0 packages/theme-check-common/src/checks/valid-settings-key/index.spec.ts
  30. +129 −0 packages/theme-check-common/src/checks/valid-settings-key/index.ts
  31. +1 −0 packages/theme-check-common/src/index.ts
  32. +217 −0 packages/theme-check-common/src/liquid-doc/liquidDoc.spec.ts
  33. +87 −0 packages/theme-check-common/src/liquid-doc/liquidDoc.ts
  34. +24 −0 packages/theme-check-common/src/liquid-doc/utils.ts
  35. +5 −2 packages/theme-check-common/src/test/test-helper.ts
  36. +5 −13 packages/theme-check-common/src/{checks/valid-block-target/block-utils.ts → utils/block.ts}
  37. +1 −0 packages/theme-check-common/src/utils/index.ts
  38. +10 −0 packages/theme-check-docs-updater/CHANGELOG.md
  39. +2 −2 packages/theme-check-docs-updater/package.json
  40. +23 −0 packages/theme-check-node/CHANGELOG.md
  41. +6 −0 packages/theme-check-node/configs/all.yml
  42. +6 −0 packages/theme-check-node/configs/recommended.yml
  43. +3 −3 packages/theme-check-node/package.json
  44. +13 −0 packages/theme-language-server-browser/CHANGELOG.md
  45. +2 −2 packages/theme-language-server-browser/package.json
  46. +45 −0 packages/theme-language-server-common/CHANGELOG.md
  47. +3 −3 packages/theme-language-server-common/package.json
  48. +16 −1 packages/theme-language-server-common/src/completions/CompletionsProvider.ts
  49. +8 −0 packages/theme-language-server-common/src/completions/params/LiquidCompletionParams.spec.ts
  50. +6 −4 packages/theme-language-server-common/src/completions/params/LiquidCompletionParams.ts
  51. +248 −0 ...me-language-server-common/src/completions/providers/ContentForParameterCompletionProvider.spec.ts
  52. +127 −0 ...s/theme-language-server-common/src/completions/providers/ContentForParameterCompletionProvider.ts
  53. +34 −0 ...ges/theme-language-server-common/src/completions/providers/LiquidDocTagCompletionProvider.spec.ts
  54. +51 −0 packages/theme-language-server-common/src/completions/providers/LiquidDocTagCompletionProvider.ts
  55. +11 −1 packages/theme-language-server-common/src/completions/providers/ObjectCompletionProvider.ts
  56. +87 −0 ...language-server-common/src/completions/providers/RenderSnippetParameterCompletionProvider.spec.ts
  57. +72 −0 ...heme-language-server-common/src/completions/providers/RenderSnippetParameterCompletionProvider.ts
  58. +9 −0 ...eme-language-server-common/src/completions/providers/data/contentForParameterCompletionOptions.ts
  59. +1 −0 packages/theme-language-server-common/src/completions/providers/index.ts
  60. +37 −1 packages/theme-language-server-common/src/documents/DocumentManager.ts
  61. +1 −1 packages/theme-language-server-common/src/documents/types.ts
  62. +10 −2 packages/theme-language-server-common/src/hover/HoverProvider.ts
  63. +77 −0 packages/theme-language-server-common/src/hover/providers/LiquidDocTagHoverProvider.spec.ts
  64. +55 −0 packages/theme-language-server-common/src/hover/providers/LiquidDocTagHoverProvider.ts
  65. +19 −2 packages/theme-language-server-common/src/hover/providers/RenderSnippetHoverProvider.spec.ts
  66. +11 −10 packages/theme-language-server-common/src/hover/providers/RenderSnippetHoverProvider.ts
  67. +125 −0 ...ages/theme-language-server-common/src/hover/providers/RenderSnippetParameterHoverProvider.spec.ts
  68. +56 −0 packages/theme-language-server-common/src/hover/providers/RenderSnippetParameterHoverProvider.ts
  69. +1 −0 packages/theme-language-server-common/src/hover/providers/index.ts
  70. +0 −86 packages/theme-language-server-common/src/liquidDoc.spec.ts
  71. +0 −52 packages/theme-language-server-common/src/liquidDoc.ts
  72. +25 −4 packages/theme-language-server-common/src/server/startServer.spec.ts
  73. +84 −50 packages/theme-language-server-common/src/server/startServer.ts
  74. +49 −0 packages/theme-language-server-common/src/utils/liquidDoc.ts
  75. +17 −0 packages/theme-language-server-node/CHANGELOG.md
  76. +4 −4 packages/theme-language-server-node/package.json
  77. +24 −0 packages/vscode-extension/CHANGELOG.md
  78. +7 −7 packages/vscode-extension/package.json
1 change: 1 addition & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
<!-- When that happens, the check's config should be updated/overridden in the theme-app-extension config -->
<!-- see packages/node/configs/theme-app-extension.yml -->
- [ ] If applicable, I've updated the `theme-app-extension.yml` config
- [ ] I've made a PR to update the [shopify.dev theme check docs](https://github.com/Shopify/shopify-dev/tree/main/content/storefronts/themes/tools/theme-check/checks) if applicable (link PR here).

<!-- Public API changes, new features -->
- [ ] I included a minor bump `changeset`
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@

<div align="center">

🗣 [Slack](https://join.slack.com/t/shopifypartners/shared_invite/zt-sdr2quab-mGkzkttZ2hnVm0~8noSyvw) | 💬 [Discussions](https://github.com/Shopify/theme-tools/discussions) | 📝 [Changelog](./CHANGELOG.md)
🗣 [Slack](https://join.slack.com/t/shopifypartners/shared_invite/zt-sdr2quab-mGkzkttZ2hnVm0~8noSyvw) | 📝 [Changelog](https://github.com/Shopify/theme-tools/blob/main/packages/vscode-extension/CHANGELOG.md)

</div>

8 changes: 8 additions & 0 deletions dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: theme-tools

dev.edition: 2024

up:
- node:
version: v22.14.0
yarn: v1.22.22
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -53,5 +53,6 @@
"webpack": "^5.94.0",
"webpack-cli": "^5.0.0",
"webpack-dev-server": "^4.11.1"
}
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
19 changes: 19 additions & 0 deletions packages/liquid-html-parser/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# @shopify/liquid-html-parser

## 2.5.0

### Minor Changes

- c4bbf3b5: [LiquidDoc]: Add parser support for @description annotations. These can be placed anywhere within the header, and can span numerous lines.
- d9dbc265: - Support parsing incomplete content_for tags in completion context
- Support content_for param completion
- 2db3047f: Support `render` param completion based on liquid docs

- If you defined liquid doc parameters on a snippet, they will appear as completion options
for parameters when rendered by a `render` tag.

- 261c2958: Support liquid doc inner tags completion + hover

- `@param`, `@description`, `@example` will support code completion
whenever being typed inside of `doc` tag
- `@param`, `@description`, `@example` can be hovered to show their
help doc

## 2.4.0

### Minor Changes
37 changes: 35 additions & 2 deletions packages/liquid-html-parser/grammar/liquid-html.ohm
Original file line number Diff line number Diff line change
@@ -133,14 +133,18 @@ Liquid <: Helpers {
contentForType (argumentSeparatorOptionalComma contentForTagArgument) (space* ",")? space*

contentForTagArgument = listOf<contentForNamedArgument<delimTag>, argumentSeparatorOptionalComma>
completionModeContentForTagArgument = listOf<contentForNamedArgument<delimTag>, argumentSeparatorOptionalComma> (argumentSeparator? (liquidVariableLookup<delimTag>))?
contentForNamedArgument<delim> = (variableSegment ("." variableSegment)*) space* ":" space* (liquidExpression<delim>)

contentForType = liquidString<delimTag>

liquidTagInclude = liquidTagRule<"include", liquidTagRenderMarkup>
liquidTagRender = liquidTagRule<"render", liquidTagRenderMarkup>
liquidTagRenderMarkup =
snippetExpression renderVariableExpression? renderAliasExpression? (argumentSeparatorOptionalComma tagArguments) (space* ",")? space*
snippetExpression renderVariableExpression? renderAliasExpression? renderArguments

renderArguments = (argumentSeparatorOptionalComma tagArguments) (space* ",")? space*
completionModeRenderArguments = (argumentSeparatorOptionalComma tagArguments) (space* ",")? space* (argumentSeparator? liquidVariableLookup<delimTag> space*)?
snippetExpression = liquidString<delimTag> | variableSegmentAsLookup
renderVariableExpression = space+ ("for" | "with") space+ liquidExpression<delimTag>
renderAliasExpression = space+ "as" space+ variableSegment
@@ -393,13 +397,18 @@ LiquidDoc <: Helpers {
LiquidDocNode =
| paramNode
| exampleNode
| descriptionNode
| fallbackNode

// By default, space matches new lines as well. We override it here to make writing rules easier.
strictSpace = " " | "\t"
// We use this as an escape hatch to stop matching TextNode and try again when one of these characters is encountered
openControl:= "@" | end

descriptionNode = "@description" strictSpace* descriptionContent
descriptionContent = anyExceptStar<endOfDescription>
endOfDescription = strictSpace* openControl

paramNode = "@param" strictSpace* paramType? strictSpace* (optionalParamName | paramName) (strictSpace* "-")? strictSpace* paramDescription
paramType = "{" strictSpace* paramTypeContent strictSpace* "}"
paramTypeContent = anyExceptStar<("}"| strictSpace)>
@@ -546,20 +555,44 @@ StrictLiquidHTML <: LiquidHTML {

WithPlaceholderLiquid <: Liquid {
liquidFilter<delim> := space* "|" space* identifier (space* ":" space* filterArguments<delim> (space* ",")?)?
liquidTagContentForMarkup :=
contentForType (argumentSeparatorOptionalComma completionModeContentForTagArgument) (space* ",")? space*
liquidTagRenderMarkup :=
snippetExpression renderVariableExpression? renderAliasExpression? completionModeRenderArguments
liquidTagName := (letter | "█") (alnum | "_")*
variableSegment := (letter | "_" | "█") (identifierCharacter | "█")*
liquidDoc :=
liquidDocStart
liquidDocBody
liquidDocEnd?
}

WithPlaceholderLiquidStatement <: LiquidStatement {
liquidFilter<delim> := space* "|" space* identifier (space* ":" space* filterArguments<delim> (space* ",")?)?
liquidTagContentForMarkup :=
contentForType (argumentSeparatorOptionalComma completionModeContentForTagArgument) (space* ",")? space*
liquidTagRenderMarkup :=
snippetExpression renderVariableExpression? renderAliasExpression? completionModeRenderArguments
liquidTagName := (letter | "█") (alnum | "_")*
variableSegment := (letter | "_" | "█") (identifierCharacter | "█")*
liquidDoc :=
liquidDocStart
liquidDocBody
liquidDocEnd?
}

WithPlaceholderLiquidHTML <: LiquidHTML {
liquidFilter<delim> := space* "|" space* identifier (space* ":" space* filterArguments<delim> (space* ",")?)?
liquidTagContentForMarkup :=
contentForType (argumentSeparatorOptionalComma completionModeContentForTagArgument) (space* ",")? space*
liquidTagRenderMarkup :=
snippetExpression renderVariableExpression? renderAliasExpression? completionModeRenderArguments
liquidTagName := (letter | "█") (alnum | "_")*
variableSegment := (letter | "_" | "█") (identifierCharacter | "█")*
leadingTagNameTextNode := (letter | "█") (alnum | "-" | ":" | "█")*
trailingTagNameTextNode := (alnum | "-" | ":" | "█")+
liquidDoc :=
liquidDocStart
liquidDocBody
liquidDocEnd?
}
2 changes: 1 addition & 1 deletion packages/liquid-html-parser/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@shopify/liquid-html-parser",
"version": "2.4.0",
"version": "2.5.0",
"description": "Liquid HTML parser by Shopify",
"author": "CP Clermont <cp.clermont@shopify.com>",
"homepage": "https://github.com/Shopify/theme-tools/tree/main/packages/liquid-html-parser#readme",
115 changes: 98 additions & 17 deletions packages/liquid-html-parser/src/stage-1-cst.spec.ts
Original file line number Diff line number Diff line change
@@ -6,8 +6,7 @@ import {
LiquidCST,
ConcreteLiquidTagLiquid,
} from './stage-1-cst';
import { BLOCKS, VOID_ELEMENTS } from './grammar';
import { NamedTags } from './types';
import { VOID_ELEMENTS } from './grammar';
import { deepGet } from './utils';

describe('Unit: Stage 1 (CST)', () => {
@@ -561,11 +560,11 @@ describe('Unit: Stage 1 (CST)', () => {
expectPath(cst, '0.markup.variable').to.equal(null);
}
expectPath(cst, '0.markup.alias').to.equal(alias);
expectPath(cst, '0.markup.args').to.have.lengthOf(namedArguments.length);
expectPath(cst, '0.markup.renderArguments').to.have.lengthOf(namedArguments.length);
namedArguments.forEach(({ name, valueType }, i) => {
expectPath(cst, `0.markup.args.${i}.type`).to.equal('NamedArgument');
expectPath(cst, `0.markup.args.${i}.name`).to.equal(name);
expectPath(cst, `0.markup.args.${i}.value.type`).to.equal(valueType);
expectPath(cst, `0.markup.renderArguments.${i}.type`).to.equal('NamedArgument');
expectPath(cst, `0.markup.renderArguments.${i}.name`).to.equal(name);
expectPath(cst, `0.markup.renderArguments.${i}.value.type`).to.equal(valueType);
});
expectPath(cst, '0.whitespaceStart').to.equal(null);
expectPath(cst, '0.whitespaceEnd').to.equal('-');
@@ -1237,7 +1236,7 @@ describe('Unit: Stage 1 (CST)', () => {
expectPath(cst, '0.type').to.equal('LiquidRawTag');
expectPath(cst, '0.name').to.equal('doc');
expectPath(cst, '0.children.0.type').to.equal('LiquidDocExampleNode');
expectPath(cst, '0.children.0.exampleContent.value').to.equal('');
expectPath(cst, '0.children.0.content.value').to.equal('');
});

it('should parse example tag with content that has leading whitespace', () => {
@@ -1247,11 +1246,9 @@ describe('Unit: Stage 1 (CST)', () => {
expectPath(cst, '0.name').to.equal('doc');
expectPath(cst, '0.children.0.type').to.equal('LiquidDocExampleNode');
expectPath(cst, '0.children.0.name').to.equal('example');
expectPath(cst, '0.children.0.exampleContent.value').to.equal('hello there');
expectPath(cst, '0.children.0.exampleContent.locStart').to.equal(
testStr.indexOf('hello there'),
);
expectPath(cst, '0.children.0.exampleContent.locEnd').to.equal(
expectPath(cst, '0.children.0.content.value').to.equal('hello there');
expectPath(cst, '0.children.0.content.locStart').to.equal(testStr.indexOf('hello there'));
expectPath(cst, '0.children.0.content.locEnd').to.equal(
testStr.indexOf('hello there') + 'hello there'.length,
);
});
@@ -1268,7 +1265,7 @@ describe('Unit: Stage 1 (CST)', () => {
expectPath(cst, '0.name').to.equal('doc');
expectPath(cst, '0.children.0.type').to.equal('LiquidDocExampleNode');
expectPath(cst, '0.children.0.name').to.equal('example');
expectPath(cst, '0.children.0.exampleContent.value').to.equal(
expectPath(cst, '0.children.0.content.value').to.equal(
'\n This is an example\n It supports multiple lines\n',
);
});
@@ -1282,7 +1279,7 @@ describe('Unit: Stage 1 (CST)', () => {
cst = toCST(testStr);
expectPath(cst, '0.children.0.type').to.equal('LiquidDocExampleNode');
expectPath(cst, '0.children.0.name').to.equal('example');
expectPath(cst, '0.children.0.exampleContent.value').to.equal(
expectPath(cst, '0.children.0.content.value').to.equal(
'\n This is an example\n',
);
expectPath(cst, '0.children.1.type').to.equal('LiquidDocParamNode');
@@ -1300,7 +1297,7 @@ describe('Unit: Stage 1 (CST)', () => {
expectPath(cst, '0.name').to.equal('doc');
expectPath(cst, '0.children.0.type').to.equal('LiquidDocExampleNode');
expectPath(cst, '0.children.0.name').to.equal('example');
expectPath(cst, '0.children.0.exampleContent.value').to.equal(
expectPath(cst, '0.children.0.content.value').to.equal(
'hello there my friend\n This is an example\n It supports multiple lines\n',
);
});
@@ -1312,9 +1309,73 @@ describe('Unit: Stage 1 (CST)', () => {
{% enddoc %}`;
cst = toCST(testStr);
expectPath(cst, '0.children.0.type').to.equal('LiquidDocExampleNode');
expectPath(cst, '0.children.0.exampleContent.value').to.equal('hello there\n');
expectPath(cst, '0.children.0.content.value').to.equal('hello there\n');
expectPath(cst, '0.children.1.type').to.equal('LiquidDocExampleNode');
expectPath(cst, '0.children.1.exampleContent.value').to.equal('second example\n');
expectPath(cst, '0.children.1.content.value').to.equal('second example\n');
});

it('should parse @description node', () => {
const testStr = `{% doc %} @description {%- enddoc %}`;
cst = toCST(testStr);
expectPath(cst, '0.type').to.equal('LiquidRawTag');
expectPath(cst, '0.name').to.equal('doc');
expectPath(cst, '0.children.0.type').to.equal('LiquidDocDescriptionNode');
expectPath(cst, '0.children.0.content.value').to.equal('');
});

it('should parse @description node', () => {
const testStr = `{% doc %}
@description This is a description
@description This is a second description
{% enddoc %}`;
cst = toCST(testStr);
expectPath(cst, '0.children.0.type').to.equal('LiquidDocDescriptionNode');
expectPath(cst, '0.children.0.content.value').to.equal('This is a description\n');

expectPath(cst, '0.children.1.type').to.equal('LiquidDocDescriptionNode');
expectPath(cst, '0.children.1.content.value').to.equal('This is a second description\n');
});

it('should parse and strip whitespace from description tag with content that has leading whitespace', () => {
const testStr = `{% doc %} @description hello there {%- enddoc %}`;
cst = toCST(testStr);
expectPath(cst, '0.type').to.equal('LiquidRawTag');
expectPath(cst, '0.name').to.equal('doc');
expectPath(cst, '0.children.0.type').to.equal('LiquidDocDescriptionNode');
expectPath(cst, '0.children.0.name').to.equal('description');
expectPath(cst, '0.children.0.content.value').to.equal('hello there');
expectPath(cst, '0.children.0.content.locStart').to.equal(testStr.indexOf('hello there'));
expectPath(cst, '0.children.0.content.locEnd').to.equal(
testStr.indexOf('hello there') + 'hello there'.length,
);
});

it('should parse description node with whitespace and new lines', () => {
const testStr = `{% doc %}
@description hello there my friend
This is a description
It supports multiple lines
{% enddoc %}`;
cst = toCST(testStr);
expectPath(cst, '0.type').to.equal('LiquidRawTag');
expectPath(cst, '0.name').to.equal('doc');
expectPath(cst, '0.children.0.type').to.equal('LiquidDocDescriptionNode');
expectPath(cst, '0.children.0.name').to.equal('description');
expectPath(cst, '0.children.0.content.value').to.equal(
'hello there my friend\n This is a description\n It supports multiple lines\n',
);
});

it('should parse multiple description nodes', () => {
const testStr = `{% doc %}
@description hello there
@description second description
{% enddoc %}`;
cst = toCST(testStr);
expectPath(cst, '0.children.0.type').to.equal('LiquidDocDescriptionNode');
expectPath(cst, '0.children.0.content.value').to.equal('hello there\n');
expectPath(cst, '0.children.1.type').to.equal('LiquidDocDescriptionNode');
expectPath(cst, '0.children.1.content.value').to.equal('second description\n');
});
}
});
@@ -1714,6 +1775,26 @@ describe('Unit: Stage 1 (CST)', () => {
expectPath(cst, '0.markup.filters.0.args.1.type').to.equal('NamedArgument');
expectPath(cst, '0.markup.filters.0.args.2.type').to.equal('VariableLookup');
});

it('should parse incomplete parameters for content_for tags', () => {
const toCST = (source: string) => toLiquidHtmlCST(source, { mode: 'completion' });

cst = toCST(`{% content_for "blocks", id: 1, cl█ %}`);

expectPath(cst, '0.markup.type').to.equal('ContentForMarkup');
expectPath(cst, '0.markup.args.0.type').to.equal('NamedArgument');
expectPath(cst, '0.markup.args.1.type').to.equal('VariableLookup');
});

it('should parse incomplete parameters for render tags', () => {
const toCST = (source: string) => toLiquidHtmlCST(source, { mode: 'completion' });

cst = toCST(`{% render "example-snippet", id: 2, foo█ %}`);

expectPath(cst, '0.markup.type').to.equal('RenderMarkup');
expectPath(cst, '0.markup.renderArguments.0.type').to.equal('NamedArgument');
expectPath(cst, '0.markup.renderArguments.1.type').to.equal('VariableLookup');
});
});

function makeExpectPath(message: string) {
Loading