@shopify/theme-check-common
Advanced tools
Comparing version 1.18.1 to 1.18.2
# @shopify/theme-check-common | ||
## 1.18.2 | ||
### Patch Changes | ||
- fe54680: Fix `MissingAsset` false positives for .css.liquid, .js.liquid and .scss.liquid files | ||
- e00c319: Fix false ParserBlockingScript reports for scripts of type module | ||
## 1.18.1 | ||
@@ -4,0 +11,0 @@ |
@@ -29,9 +29,22 @@ "use strict"; | ||
return; | ||
const expression = node.expression; | ||
const assetPath = `assets/${expression.value}`; | ||
const fileExists = await (0, file_utils_1.assertFileExists)(context, assetPath); | ||
let expression = node.expression; | ||
let originalAssetPath = `assets/${expression.value}`; | ||
let assetPath = originalAssetPath; | ||
let fileExists = await (0, file_utils_1.assertFileExists)(context, assetPath); | ||
if (fileExists) | ||
return; | ||
if (assetPath.endsWith('.scss.css')) { | ||
assetPath = assetPath.replace('.scss.css', '.scss.liquid'); | ||
fileExists = await (0, file_utils_1.assertFileExists)(context, assetPath); | ||
if (fileExists) | ||
return; | ||
} | ||
if (assetPath.endsWith('.js') || assetPath.endsWith('.css')) { | ||
assetPath += '.liquid'; | ||
fileExists = await (0, file_utils_1.assertFileExists)(context, assetPath); | ||
if (fileExists) | ||
return; | ||
} | ||
context.report({ | ||
message: `'${assetPath}' does not exist`, | ||
message: `'${originalAssetPath}' does not exist`, | ||
startIndex: expression.position.start, | ||
@@ -38,0 +51,0 @@ endIndex: expression.position.end, |
@@ -61,3 +61,30 @@ "use strict"; | ||
}); | ||
(0, vitest_1.it)('should not report for compiled .js.liquid files', async () => { | ||
const file = `{{ 'foo.js' | asset_url }} `; | ||
const files = { | ||
'snippets/snippet.liquid': file, | ||
'assets/foo.js.liquid': 'console.log("{{ "hi" }}");', | ||
}; | ||
const offenses = await (0, test_1.check)(files, [_1.MissingAsset]); | ||
(0, vitest_1.expect)(offenses).to.have.length(0); | ||
}); | ||
(0, vitest_1.it)('should not report for compiled .css.liquid files', async () => { | ||
const file = `{{ 'foo.css' | asset_url }} `; | ||
const files = { | ||
'snippets/snippet.liquid': file, | ||
'assets/foo.css.liquid': 'body { color: {{ "blue" }}; }', | ||
}; | ||
const offenses = await (0, test_1.check)(files, [_1.MissingAsset]); | ||
(0, vitest_1.expect)(offenses).to.have.length(0); | ||
}); | ||
(0, vitest_1.it)('should not report for compiled .scss.liquid files', async () => { | ||
const file = `{{ 'foo.scss.css' | asset_url }} `; | ||
const files = { | ||
'snippets/snippet.liquid': file, | ||
'assets/foo.scss.liquid': 'html { & body { color: {{ "blue" }}; } }', | ||
}; | ||
const offenses = await (0, test_1.check)(files, [_1.MissingAsset]); | ||
(0, vitest_1.expect)(offenses).to.have.length(0); | ||
}); | ||
}); | ||
//# sourceMappingURL=index.spec.js.map |
@@ -64,3 +64,7 @@ "use strict"; | ||
.some((attr) => (0, utils_2.isAttr)(attr, 'async') || (0, utils_2.isAttr)(attr, 'defer')); | ||
if (hasDeferOrAsync) { | ||
const isTypeModule = node.attributes | ||
.filter(utils_2.isValuedHtmlAttribute) | ||
.some((attr) => (0, utils_2.isAttr)(attr, 'type') && | ||
((0, utils_2.hasAttributeValueOf)(attr, 'module') || (0, utils_2.hasAttributeValueOf)(attr, 'importmap'))); | ||
if (hasDeferOrAsync || isTypeModule) { | ||
return; | ||
@@ -67,0 +71,0 @@ } |
@@ -157,4 +157,14 @@ "use strict"; | ||
}); | ||
(0, vitest_1.it)('should not report any offense when using scripts of type module', async () => { | ||
const file = ` | ||
<script src="https://foo.bar/baz.js" type="module"></script> | ||
<script src="https://foo.bar/baz.js" type="importmap"></script> | ||
`; | ||
const offenses = await (0, test_1.check)({ | ||
'code.liquid': file, | ||
}, [_1.ParserBlockingScript]); | ||
(0, vitest_1.expect)(offenses).to.have.length(0); | ||
}); | ||
}); | ||
}); | ||
//# sourceMappingURL=index.spec.js.map |
@@ -16,3 +16,4 @@ import { Position, NodeTypes, HtmlElement, AttrEmpty, AttrSingleQuoted, AttrDoubleQuoted, AttrUnquoted, LiquidHtmlNode } from '@shopify/liquid-html-parser'; | ||
export declare function valueIncludes(attr: ValuedHtmlAttribute, word: string): boolean; | ||
export declare function hasAttributeValueOf(attr: ValuedHtmlAttribute, value: string): boolean; | ||
export declare function isLiquidString(node: LiquidHtmlNode): node is NodeOfType<NodeTypes.String>; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isLiquidString = exports.valueIncludes = exports.isValuedHtmlAttribute = exports.isHtmlAttribute = exports.isAttr = exports.isHtmlTag = exports.isNodeOfType = void 0; | ||
exports.isLiquidString = exports.hasAttributeValueOf = exports.valueIncludes = exports.isValuedHtmlAttribute = exports.isHtmlAttribute = exports.isAttr = exports.isHtmlTag = exports.isNodeOfType = void 0; | ||
const liquid_html_parser_1 = require("@shopify/liquid-html-parser"); | ||
@@ -42,2 +42,8 @@ function isNodeOfType(type, node) { | ||
exports.valueIncludes = valueIncludes; | ||
function hasAttributeValueOf(attr, value) { | ||
return (attr.value.length === 1 && | ||
isNodeOfType(liquid_html_parser_1.NodeTypes.TextNode, attr.value[0]) && | ||
attr.value[0].value === value); | ||
} | ||
exports.hasAttributeValueOf = hasAttributeValueOf; | ||
function isLiquidString(node) { | ||
@@ -44,0 +50,0 @@ return node.type === liquid_html_parser_1.NodeTypes.String; |
{ | ||
"name": "@shopify/theme-check-common", | ||
"version": "1.18.1", | ||
"version": "1.18.2", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "homepage": "https://github.com/Shopify/theme-tools/blob/main/packages/theme-check-common/README.md", |
@@ -71,2 +71,38 @@ import { expect, describe, it } from 'vitest'; | ||
}); | ||
it('should not report for compiled .js.liquid files', async () => { | ||
const file = `{{ 'foo.js' | asset_url }} `; | ||
const files = { | ||
'snippets/snippet.liquid': file, | ||
'assets/foo.js.liquid': 'console.log("{{ "hi" }}");', | ||
}; | ||
const offenses = await check(files, [MissingAsset]); | ||
expect(offenses).to.have.length(0); | ||
}); | ||
it('should not report for compiled .css.liquid files', async () => { | ||
const file = `{{ 'foo.css' | asset_url }} `; | ||
const files = { | ||
'snippets/snippet.liquid': file, | ||
'assets/foo.css.liquid': 'body { color: {{ "blue" }}; }', | ||
}; | ||
const offenses = await check(files, [MissingAsset]); | ||
expect(offenses).to.have.length(0); | ||
}); | ||
it('should not report for compiled .scss.liquid files', async () => { | ||
const file = `{{ 'foo.scss.css' | asset_url }} `; | ||
const files = { | ||
'snippets/snippet.liquid': file, | ||
'assets/foo.scss.liquid': 'html { & body { color: {{ "blue" }}; } }', | ||
}; | ||
const offenses = await check(files, [MissingAsset]); | ||
expect(offenses).to.have.length(0); | ||
}); | ||
}); |
@@ -29,9 +29,23 @@ import { LiquidCheckDefinition, Severity, SourceCodeType } from '../../types'; | ||
const expression = node.expression; | ||
const assetPath = `assets/${expression.value}`; | ||
const fileExists = await assertFileExists(context, assetPath); | ||
let expression = node.expression; | ||
let originalAssetPath = `assets/${expression.value}`; | ||
let assetPath = originalAssetPath; | ||
let fileExists = await assertFileExists(context, assetPath); | ||
if (fileExists) return; | ||
if (assetPath.endsWith('.scss.css')) { | ||
assetPath = assetPath.replace('.scss.css', '.scss.liquid'); | ||
fileExists = await assertFileExists(context, assetPath); | ||
if (fileExists) return; | ||
} | ||
if (assetPath.endsWith('.js') || assetPath.endsWith('.css')) { | ||
assetPath += '.liquid'; | ||
fileExists = await assertFileExists(context, assetPath); | ||
if (fileExists) return; | ||
} | ||
context.report({ | ||
message: `'${assetPath}' does not exist`, | ||
message: `'${originalAssetPath}' does not exist`, | ||
startIndex: expression.position.start, | ||
@@ -38,0 +52,0 @@ endIndex: expression.position.end, |
@@ -210,3 +210,17 @@ import { expect, describe, it } from 'vitest'; | ||
}); | ||
it('should not report any offense when using scripts of type module', async () => { | ||
const file = ` | ||
<script src="https://foo.bar/baz.js" type="module"></script> | ||
<script src="https://foo.bar/baz.js" type="importmap"></script> | ||
`; | ||
const offenses = await reportOffenses( | ||
{ | ||
'code.liquid': file, | ||
}, | ||
[ParserBlockingScript], | ||
); | ||
expect(offenses).to.have.length(0); | ||
}); | ||
}); | ||
}); |
import { NodeTypes } from '@shopify/liquid-html-parser'; | ||
import { LiquidCheckDefinition, Severity, SourceCodeType } from '../../types'; | ||
import { last } from '../../utils'; | ||
import { isAttr, isHtmlAttribute, isValuedHtmlAttribute } from '../utils'; | ||
import { hasAttributeValueOf, isAttr, isHtmlAttribute, isValuedHtmlAttribute } from '../utils'; | ||
import { liquidFilterSuggestion, scriptTagSuggestion } from './suggestions'; | ||
@@ -70,4 +70,11 @@ | ||
.some((attr) => isAttr(attr, 'async') || isAttr(attr, 'defer')); | ||
const isTypeModule = node.attributes | ||
.filter(isValuedHtmlAttribute) | ||
.some( | ||
(attr) => | ||
isAttr(attr, 'type') && | ||
(hasAttributeValueOf(attr, 'module') || hasAttributeValueOf(attr, 'importmap')), | ||
); | ||
if (hasDeferOrAsync) { | ||
if (hasDeferOrAsync || isTypeModule) { | ||
return; | ||
@@ -74,0 +81,0 @@ } |
@@ -72,4 +72,12 @@ import { | ||
export function hasAttributeValueOf(attr: ValuedHtmlAttribute, value: string) { | ||
return ( | ||
attr.value.length === 1 && | ||
isNodeOfType(NodeTypes.TextNode, attr.value[0]) && | ||
attr.value[0].value === value | ||
); | ||
} | ||
export function isLiquidString(node: LiquidHtmlNode): node is NodeOfType<NodeTypes.String> { | ||
return node.type === NodeTypes.String; | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1176646
19780