Skip to content
This repository was archived by the owner on Mar 5, 2026. It is now read-only.
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ packaging/builds

# Theme Liquid docs live at git@github.com:Shopify/theme-liquid-docs.git,
/data/shopify_liquid/documentation/
.claude
91 changes: 91 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

platformOS Check is a linter and language server (LSP) for platformOS applications. It analyzes Liquid templates, JSON, YAML, and GraphQL files to enforce best practices, identify performance issues, and catch errors. Written in Ruby 3.2+.

## Common Commands

```bash
# Run all tests (runs against both InMemory and FileSystem storage)
bundle exec rake test

# Run tests with specific storage (faster for development)
bundle exec rake tests:in_memory
bundle exec rake tests:file_system

# Run a single test file
bundle exec ruby -Itest test/checks/unused_assign_test.rb

# Run linter
bundle exec rubocop

# Run CLI on a platformOS app
bin/platformos-check /path/to/app

# Create a new check (generates check, test, and docs files)
bundle exec rake "new_check[MyCheckName]"

# Update platformOS Liquid documentation
bundle exec rake download_theme_liquid_docs
```

## Architecture

### Entry Points
- `bin/platformos-check` - CLI tool
- `bin/platformos-check-language-server` - LSP server for IDE integration

### Core Components

**Analyzer** (`lib/platformos_check/analyzer.rb`): Central orchestrator that runs checks. Manages check lifecycle: `analyze_platformos_app()` → `analyze_files()` → `finish()`.

**App** (`lib/platformos_check/app.rb`): Represents a platformOS application as a collection of typed files (LiquidFile, YamlFile, GraphqlFile, etc.). Uses regex patterns to categorize files into pages, partials, forms, layouts, etc.

**Check System** (`lib/platformos_check/check.rb`): Base class for all checks. Checks inherit from `LiquidCheck`, `YamlCheck`, or `HtmlCheck` and implement visitor methods like `on_document`, `on_assign`, `on_variable_lookup`, `on_end`.

**Storage Layer**: Abstract interface with two implementations:
- `FileSystemStorage` - Reads from disk (production)
- `InMemoryStorage` - For language server and tests

**Language Server** (`lib/platformos_check/language_server/`): LSP implementation with completion providers, hover providers, code action providers, and diagnostics engine.

### Visitor Pattern
Checks use a visitor pattern for AST traversal. The `LiquidVisitor` walks Liquid AST and calls check methods (`on_assign`, `on_graphql`, etc.).

### Reporting Offenses
```ruby
add_offense(message, node:) do |corrector|
corrector.replace(node.range, "fixed code")
end
```

## Creating a New Check

1. Run `bundle exec rake "new_check[CheckName]"`
2. Implement the check in `lib/platformos_check/checks/check_name.rb`
3. Add configuration to `config/default.yml`
4. Write tests in `test/checks/check_name_test.rb`

## Debugging

```bash
# Enable debug mode (disables timeouts, enables --profile flag)
export PLATFORMOS_CHECK_DEBUG=true

# Language server logging
export PLATFORMOS_CHECK_DEBUG_LOG_FILE=/tmp/platformos-check-debug.log
```

## Configuration

Project configuration is in `.platformos-check.yml`. Default check settings are in `config/default.yml`.

Checks can be disabled in code:
```liquid
{% # platformos-check-disable CheckName %}
...
{% # platformos-check-enable CheckName %}
```
3 changes: 2 additions & 1 deletion data/platformos_liquid/documentation/filters.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion data/platformos_liquid/documentation/latest.json
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@

{"revision":"fdd40db2e085f4472f7adad7966d9b760d82ac79"}
{"revision":"be109cad315451c536817c95f81a5824dd77f9fe"}
2 changes: 1 addition & 1 deletion data/platformos_liquid/documentation/objects.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion data/platformos_liquid/documentation/tags.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/platformos_check.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
require_relative "platformos_check/tags/background"
require_relative "platformos_check/tags/cache"
require_relative "platformos_check/tags/context"
require_relative "platformos_check/tags/doc"
require_relative "platformos_check/tags/export"
require_relative "platformos_check/tags/form"
require_relative "platformos_check/tags/function"
Expand Down
1 change: 1 addition & 0 deletions lib/platformos_check/tags.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def register_tags!
register_tag('content_for', ContentFor)
register_tag('context', Context)
register_tag('context_rc', Context)
register_tag('doc', Doc)
register_tag('export', Export)
register_tag('form', Form)
register_tag('function', Function)
Expand Down
12 changes: 12 additions & 0 deletions lib/platformos_check/tags/doc.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

module PlatformosCheck
module Tags
class Doc < Liquid::Block
def initialize(tag_name, markup, options)
super
raise Liquid::SyntaxError, "Syntax Error in 'doc' - doc tag does not accept any parameters" unless markup.strip.empty?
end
end
end
end
52 changes: 52 additions & 0 deletions test/tags/doc_tag_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# frozen_string_literal: true

require "test_helper"

module PlatformosCheck
module Tags
class DocTagTest < Minitest::Test
def test_doc_tag_without_parameters
offenses = analyze_platformos_app(
"app/views/pages/index.liquid" => <<~END
{% doc %}
This is a documentation block.
It can contain notes about the code.
{% enddoc %}
END
)

assert_offenses("", offenses)
end

def test_doc_tag_with_parameters_fails
offenses = analyze_platformos_app_without_raise(
PlatformosCheck::SyntaxError.new,
"app/views/pages/index.liquid" => <<~END
{% doc arg: 1 %}
Documentation
{% enddoc %}
END
)

assert_equal(1, offenses.size)
assert_match(/syntax error/i, offenses.first.message.downcase)
end

def test_doc_tag_with_content
offenses = analyze_platformos_app(
"app/views/pages/index.liquid" => <<~END
{% doc %}
# API Documentation
This function handles user authentication
Parameters:
- email: String
- password: String
{% enddoc %}
END
)

assert_offenses("", offenses)
end
end
end
end