platformOS Check - Development Tool
platformOS Check
platformOS Check is a Node.js-based linter and language server for platformOS Liquid templates. It is part of the platformos-tools monorepo and is bundled with pos-cli.
Installation
Install pos-cli globally via npm — platformOS Check and the Language Server are included:
npm install -g @platformos/pos-cli
You can also install the linter as a standalone package for use in build pipelines:
npm install --save-dev @platformos/platformos-check-node
IDE Integration
Install the platformOS Check extension for VS Code to get inline diagnostics, hover documentation, and code actions directly in your editor. The extension uses the same Language Server bundled with pos-cli.
CLI Usage
Run the linter on your project:
pos-cli check run [path]
Available options:
| Flag | Description |
|---|---|
-a |
Enable automatic fixing of offenses |
-f <format> |
Output format: text (default) or json |
-s, --silent |
Only show errors, no success messages |
Initialize a .platformos-check.yml configuration file with all available settings:
pos-cli check init
Download the latest platformOS Liquid documentation used by the linter:
pos-cli check update-docs
Start the Language Server Protocol (LSP) server for IDE integration:
pos-cli lsp
Configuration
You can configure platformOS Check to override default check options, enable or disable specific checks. You can make these changes using a config file, disable checks using comments, or selectively run checks using command line flags.
Config file
Add a .platformos-check.yml file to the root of your project to override check defaults. The easiest way to create one is by running pos-cli check init, which generates a config file with all available settings commented out for reference.
The config file supports the following top-level settings:
| Setting | Description |
|---|---|
| extends | Base configuration to extend. Available presets: platformos-check:recommended (default), platformos-check:all, platformos-check:nothing. You can also extend another YAML config file or an npm package. |
| root | If your app/modules aren't in the root directory, you can provide a relative root path for finding the platformOS app files. |
| ignore | Exclude directories from platformOS Check. Useful if you use private modules and do not have access to the files. |
| require | Paths to custom check modules (JS files or npm packages). See Writing custom checks. |
| check settings | For each check, set enabled to true or false, set the check severity, set specific ignore files and paths, and configure any other check-specific options. |
Example config file
# Extend the recommended preset (this is the default if omitted)
extends:
- platformos-check:recommended
# Ignore directories
ignore:
- node_modules/**
- modules/third-party-private-module/**
# Paths to custom check modules
require:
- ./my-custom-checks/index.js
# Disable a check
MissingPartial:
enabled: false
# Change severity and configure options for a check
UnusedAssign:
enabled: true
severity: error
# Configure a check with custom options
MissingPartial:
enabled: true
severity: warning
ignore:
- modules/legacy/**
ignore_missing:
- shared/deprecated-*
Check severity
The check severity indicates the relative importance of a check. Severity levels are:
| Severity | Description |
|---|---|
error |
Critical issues that indicate bugs or broken functionality |
warning |
Issues that should be addressed but don't break functionality |
info |
Style and best practice suggestions |
For backwards compatibility, suggestion (maps to warning) and style (maps to info) are also accepted in configuration files.
When running pos-cli check run, the process exits with code 1 if any offenses are found.
Disable checks using Liquid comments
You can disable all checks or specific checks using comments. You can disable checks for a specific section of your app code, or for an entire file.
Disable all checks for a section of your file:
{% # platformos-check-disable %}
{% assign x = 1 %}
{% # platformos-check-enable %}
Disable a specific check by including it in the comment:
{% # platformos-check-disable UnusedAssign %}
{% assign x = 1 %}
{% # platformos-check-enable UnusedAssign %}
Disable multiple checks by including them as a comma-separated list:
{% # platformos-check-disable UnusedAssign,UndefinedObject %}
{% assign x = 1 %}
{% # platformos-check-enable UnusedAssign,UndefinedObject %}
Disable checks for the entire document by placing the comment on the first line:
{% # platformos-check-disable MissingPartial %}
{% render 'legacy-partial' %}
Available checks
The following checks are available in the platformos-check:recommended preset:
| Check | Default Severity | Description |
|---|---|---|
| ConflictingSchemaPropertyType | warning | Reports a property name declared with two different types across schemas, which the platform resolves as one ambiguous name |
| DeprecatedFilter | warning | Reports usage of deprecated Liquid filters |
| DeprecatedTag | warning | Reports usage of deprecated Liquid tags |
| DuplicateFunctionArguments | warning | Reports duplicate arguments in function calls |
| DuplicateRenderPartialArguments | warning | Reports duplicate arguments in render tags |
| GraphQLCheck | error | Validates GraphQL syntax |
| GraphQLVariablesCheck | error | Validates GraphQL variables |
| ImgWidthAndHeight | error | Requires width and height on img tags |
| ImplicitIncludeArguments | warning | Reports a variable an include'd partial reads that the call does not pass, inheriting it from the caller scope |
| InvalidWriteTarget | error | Reports a subscript write or << against a target the runtime rejects |
| JsonLiteralQuoteStyle | error | Enforces double quotes inside inline object/array literals |
| LiquidHTMLSyntaxError | error | Reports Liquid/HTML syntax errors |
| MatchingTranslations | error | Validates translation keys match across locales |
| MissingAsset | error | Reports references to missing assets |
| MissingContentForLayout | error | Reports layouts that never output content_for_layout |
| MissingDocParam | error | Reports a variable a partial reads without declaring it in its doc tag |
| MissingPage | warning | Reports links pointing to routes with no matching page |
| MissingPartial | error | Reports references to missing partials |
| MissingRenderPartialArguments | error | Reports missing required arguments declared in doc tags (partials WITH a doc tag) |
| NestedGraphQLQuery | warning | Detects GraphQL queries inside loops (N+1 pattern) |
| ParserBlockingScript | error | Reports scripts that block HTML parsing |
| PartialCallArguments | error | Validates arguments at render/function call sites for partials with NO doc tag (formerly MetadataParamsCheck) |
| RequiredDocParamWithDefault | warning | Reports a required doc parameter the partial reads through the default filter |
| ReservedVariableName | error | Reports reserved Liquid literals used as variable names |
| RollbackOutsideTransaction | error | Reports a rollback reached outside a transaction block, including through render/function/background calls |
| TranslationKeyExists | error | Reports usage of non-existent translation keys |
| UnclosedHTMLElement | warning | Reports unclosed HTML elements |
| UndefinedObject | warning | Reports usage of undefined variables |
| UniqueDocParamNames | error | Reports duplicate @param names in LiquidDoc |
| UnknownFilter | error | Reports usage of unknown Liquid filters |
| UnknownProperty | error | Reports usage of unknown properties |
| UnrecognizedRenderPartialArguments | warning | Reports unrecognized arguments in render/function tags (partials WITH a doc tag) |
| UnusedAssign | warning | Reports assigned but unused variables |
| UnusedDocParam | warning | Reports @param tags for unused parameters |
| ValidDocParamTypes | error | Validates @param type annotations |
| ValidFrontmatter | warning | Validates YAML frontmatter for known platformOS file types |
| ValidHTMLTranslation | warning | Validates HTML in translations |
| ValidRenderPartialArgumentTypes | warning | Validates argument types passed to partials |
| ValidFilterArgumentTypes | warning | Validates argument types passed to Liquid filters, the piped value included |
| ValidTagArgumentTypes | warning | Validates argument types passed to Liquid tags |
| VariableName | warning | Enforces variable naming conventions (default: snake_case) |
| YAMLSyntaxError | error | Reports what the YAML parser could not read, including duplicated keys |
Writing custom checks
You can extend platformOS Check with custom checks written in JavaScript. Custom checks are loaded via the require field in your .platformos-check.yml config file, or auto-discovered from npm packages named platformos-check-* or @your-org/platformos-check-* in your node_modules.
Custom check structure
A custom check module must export a checks array containing check definitions. Each check definition has a meta object describing the check and a create function that returns visitor methods.
Create a file, e.g. my-custom-checks/index.js:
const NoHardcodedStrings = {
meta: {
code: 'NoHardcodedStrings',
name: 'No hardcoded strings in HTML',
docs: {
description: 'Encourages use of translations instead of hardcoded strings.',
recommended: false,
},
// SourceCodeType: 'LiquidHtml' for Liquid files, 'JSON' for JSON, 'GraphQL' for GraphQL
type: 'LiquidHtml',
// Severity: 0 = error, 1 = warning, 2 = info
severity: 1,
schema: {},
targets: [],
},
create(context) {
return {
async TextNode(node) {
const text = node.value.trim();
if (text.length > 0 && /[a-zA-Z]{3,}/.test(text)) {
context.report({
message: `Consider using a translation key instead of hardcoded text: "${text.substring(0, 50)}"`,
startIndex: node.position.start,
endIndex: node.position.end,
});
}
},
};
},
};
module.exports = {
checks: [NoHardcodedStrings],
};
Then reference it in your .platformos-check.yml:
require:
- ./my-custom-checks/index.js
# Enable and configure your custom check
NoHardcodedStrings:
enabled: true
severity: warning
Visitor methods
The create function receives a context object and returns an object with visitor methods. The available visitor methods depend on the source code type:
For Liquid files (type: 'LiquidHtml'):
- Node type methods like
LiquidTag,LiquidVariable,HtmlElement,HtmlRawNode,TextNode,VariableLookup,AssignMarkup, etc. - Exit methods: append
:exitto any node type (e.g."LiquidTag:exit") onCodePathStart(file)— called before traversing a fileonCodePathEnd(file)— called after traversing a file
The context object provides:
context.report({ message, startIndex, endIndex, fix?, suggest? })— report an offensecontext.file— the current source code filecontext.settings— check-specific settings from the configcontext.toRelativePath(uri)/context.toUri(relativePath)— path utilitiescontext.fileExists(uri)— check if a file existscontext.getDefaultTranslations()— access translation data
Publishing custom checks as npm packages
If you name your npm package following the convention platformos-check-* or @your-org/platformos-check-*, it will be auto-discovered when installed in the project's node_modules — no require entry needed in the config.