@platformos/platformos-check-common 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/AugmentedPlatformOSDocset.d.ts +11 -0
  3. package/dist/AugmentedPlatformOSDocset.js +81 -0
  4. package/dist/AugmentedPlatformOSDocset.js.map +1 -0
  5. package/dist/JSONValidator.js +1 -1
  6. package/dist/JSONValidator.js.map +1 -1
  7. package/dist/checks/deprecated-filter/index.js +4 -41
  8. package/dist/checks/deprecated-filter/index.js.map +1 -1
  9. package/dist/checks/deprecated-tag/index.js +21 -22
  10. package/dist/checks/deprecated-tag/index.js.map +1 -1
  11. package/dist/checks/duplicate-function-arguments/index.js +1 -1
  12. package/dist/checks/duplicate-function-arguments/index.js.map +1 -1
  13. package/dist/checks/duplicate-render-partial-arguments/index.js +1 -1
  14. package/dist/checks/duplicate-render-partial-arguments/index.js.map +1 -1
  15. package/dist/checks/graphql/index.js +1 -1
  16. package/dist/checks/graphql/index.js.map +1 -1
  17. package/dist/checks/img-width-and-height/index.js +1 -1
  18. package/dist/checks/img-width-and-height/index.js.map +1 -1
  19. package/dist/checks/index.d.ts +3 -3
  20. package/dist/checks/index.js +4 -79
  21. package/dist/checks/index.js.map +1 -1
  22. package/dist/checks/json-syntax-error/index.js +1 -1
  23. package/dist/checks/json-syntax-error/index.js.map +1 -1
  24. package/dist/checks/liquid-html-syntax-error/index.js +2 -2
  25. package/dist/checks/liquid-html-syntax-error/index.js.map +1 -1
  26. package/dist/checks/matching-translations/index.d.ts +2 -2
  27. package/dist/checks/matching-translations/index.js +20 -31
  28. package/dist/checks/matching-translations/index.js.map +1 -1
  29. package/dist/checks/metadata-params/index.js +6 -3
  30. package/dist/checks/metadata-params/index.js.map +1 -1
  31. package/dist/checks/missing-asset/index.js +1 -1
  32. package/dist/checks/missing-asset/index.js.map +1 -1
  33. package/dist/checks/missing-partial/index.d.ts +6 -0
  34. package/dist/checks/missing-partial/index.js +70 -0
  35. package/dist/checks/missing-partial/index.js.map +1 -0
  36. package/dist/checks/orphaned-partial/index.js +4 -4
  37. package/dist/checks/orphaned-partial/index.js.map +1 -1
  38. package/dist/checks/parser-blocking-script/index.js +10 -36
  39. package/dist/checks/parser-blocking-script/index.js.map +1 -1
  40. package/dist/checks/parser-blocking-script/suggestions.d.ts +1 -2
  41. package/dist/checks/parser-blocking-script/suggestions.js +1 -11
  42. package/dist/checks/parser-blocking-script/suggestions.js.map +1 -1
  43. package/dist/checks/reserved-doc-param-names/index.js +6 -5
  44. package/dist/checks/reserved-doc-param-names/index.js.map +1 -1
  45. package/dist/checks/translation-key-exists/index.js +1 -1
  46. package/dist/checks/translation-key-exists/index.js.map +1 -1
  47. package/dist/checks/unclosed-html-element/index.js +5 -1
  48. package/dist/checks/unclosed-html-element/index.js.map +1 -1
  49. package/dist/checks/undefined-object/index.js +7 -30
  50. package/dist/checks/undefined-object/index.js.map +1 -1
  51. package/dist/checks/unique-doc-param-names/index.js +1 -1
  52. package/dist/checks/unique-doc-param-names/index.js.map +1 -1
  53. package/dist/checks/unknown-filter/index.js +3 -3
  54. package/dist/checks/unknown-filter/index.js.map +1 -1
  55. package/dist/checks/unknown-property/index.js +1 -1
  56. package/dist/checks/unknown-property/index.js.map +1 -1
  57. package/dist/checks/unrecognized-render-partial-arguments/index.js +2 -2
  58. package/dist/checks/unrecognized-render-partial-arguments/index.js.map +1 -1
  59. package/dist/checks/unused-assign/index.js +1 -1
  60. package/dist/checks/unused-assign/index.js.map +1 -1
  61. package/dist/checks/unused-doc-param/index.js +1 -1
  62. package/dist/checks/unused-doc-param/index.js.map +1 -1
  63. package/dist/checks/utils.js +1 -1
  64. package/dist/checks/utils.js.map +1 -1
  65. package/dist/checks/valid-content-for-arguments/index.js +1 -1
  66. package/dist/checks/valid-content-for-arguments/index.js.map +1 -1
  67. package/dist/checks/valid-doc-param-types/index.js +4 -4
  68. package/dist/checks/valid-doc-param-types/index.js.map +1 -1
  69. package/dist/checks/valid-html-translation/index.d.ts +2 -2
  70. package/dist/checks/valid-html-translation/index.js +4 -4
  71. package/dist/checks/valid-html-translation/index.js.map +1 -1
  72. package/dist/checks/valid-json/index.js +1 -1
  73. package/dist/checks/valid-json/index.js.map +1 -1
  74. package/dist/checks/valid-render-partial-argument-types/index.js +2 -2
  75. package/dist/checks/valid-render-partial-argument-types/index.js.map +1 -1
  76. package/dist/checks/variable-name/index.js +1 -1
  77. package/dist/checks/variable-name/index.js.map +1 -1
  78. package/dist/context-utils.d.ts +2 -7
  79. package/dist/context-utils.js +39 -109
  80. package/dist/context-utils.js.map +1 -1
  81. package/dist/disabled-checks/index.js +4 -2
  82. package/dist/disabled-checks/index.js.map +1 -1
  83. package/dist/find-root.d.ts +7 -10
  84. package/dist/find-root.js +10 -17
  85. package/dist/find-root.js.map +1 -1
  86. package/dist/fixes/autofix.d.ts +4 -4
  87. package/dist/fixes/autofix.js +2 -2
  88. package/dist/fixes/autofix.js.map +1 -1
  89. package/dist/fixes/correctors/index.js +4 -0
  90. package/dist/fixes/correctors/index.js.map +1 -1
  91. package/dist/index.d.ts +4 -5
  92. package/dist/index.js +34 -17
  93. package/dist/index.js.map +1 -1
  94. package/dist/jsonc/parse.d.ts +1 -1
  95. package/dist/jsonc/parse.js +1 -1
  96. package/dist/liquid-doc/arguments.d.ts +7 -8
  97. package/dist/liquid-doc/arguments.js +20 -28
  98. package/dist/liquid-doc/arguments.js.map +1 -1
  99. package/dist/liquid-doc/liquidDoc.d.ts +1 -1
  100. package/dist/liquid-doc/liquidDoc.js.map +1 -1
  101. package/dist/liquid-doc/utils.d.ts +1 -1
  102. package/dist/liquid-doc/utils.js +4 -3
  103. package/dist/liquid-doc/utils.js.map +1 -1
  104. package/dist/path.d.ts +1 -0
  105. package/dist/path.js +5 -1
  106. package/dist/path.js.map +1 -1
  107. package/dist/test/MockApp.d.ts +16 -0
  108. package/dist/test/MockApp.js +16 -0
  109. package/dist/test/MockApp.js.map +1 -0
  110. package/dist/test/MockFileSystem.d.ts +3 -3
  111. package/dist/test/MockFileSystem.js +6 -6
  112. package/dist/test/MockFileSystem.js.map +1 -1
  113. package/dist/test/index.d.ts +1 -1
  114. package/dist/test/index.js +1 -1
  115. package/dist/test/index.js.map +1 -1
  116. package/dist/test/test-helper.d.ts +10 -9
  117. package/dist/test/test-helper.js +15 -106
  118. package/dist/test/test-helper.js.map +1 -1
  119. package/dist/to-source-code.d.ts +4 -3
  120. package/dist/to-source-code.js +20 -0
  121. package/dist/to-source-code.js.map +1 -1
  122. package/dist/tsconfig.tsbuildinfo +1 -1
  123. package/dist/types/platformos-liquid-docs.d.ts +128 -0
  124. package/dist/types/platformos-liquid-docs.js +3 -0
  125. package/dist/types/platformos-liquid-docs.js.map +1 -0
  126. package/dist/types/schemas/index.d.ts +0 -2
  127. package/dist/types/schemas/index.js.map +1 -1
  128. package/dist/types.d.ts +18 -67
  129. package/dist/types.js +3 -5
  130. package/dist/types.js.map +1 -1
  131. package/dist/utils/file-utils.js +1 -2
  132. package/dist/utils/file-utils.js.map +1 -1
  133. package/dist/utils/index.d.ts +0 -1
  134. package/dist/utils/index.js +0 -1
  135. package/dist/utils/index.js.map +1 -1
  136. package/dist/yaml/parse.d.ts +5 -0
  137. package/dist/yaml/parse.js +94 -0
  138. package/dist/yaml/parse.js.map +1 -0
  139. package/package.json +9 -9
  140. package/src/{AugmentedThemeDocset.spec.ts → AugmentedPlatformOSDocset.spec.ts} +47 -34
  141. package/src/AugmentedPlatformOSDocset.ts +89 -0
  142. package/src/JSONValidator.ts +1 -1
  143. package/src/checks/deprecated-filter/index.spec.ts +76 -248
  144. package/src/checks/deprecated-filter/index.ts +5 -53
  145. package/src/checks/deprecated-tag/index.spec.ts +85 -34
  146. package/src/checks/deprecated-tag/index.ts +27 -22
  147. package/src/checks/duplicate-function-arguments/index.ts +1 -1
  148. package/src/checks/duplicate-render-partial-arguments/index.ts +1 -1
  149. package/src/checks/graphql/index.ts +1 -1
  150. package/src/checks/img-width-and-height/index.ts +1 -1
  151. package/src/checks/index.ts +11 -80
  152. package/src/checks/invalid-hash-assign-target/index.spec.ts +14 -14
  153. package/src/checks/json-syntax-error/index.ts +1 -1
  154. package/src/checks/liquid-html-syntax-error/checks/InvalidBooleanExpression.spec.ts +0 -11
  155. package/src/checks/liquid-html-syntax-error/checks/InvalidLoopArguments.spec.ts +1 -2
  156. package/src/checks/liquid-html-syntax-error/index.spec.ts +1 -6
  157. package/src/checks/liquid-html-syntax-error/index.ts +2 -2
  158. package/src/checks/matching-translations/index.spec.ts +89 -346
  159. package/src/checks/matching-translations/index.ts +24 -35
  160. package/src/checks/metadata-params/index.ts +5 -7
  161. package/src/checks/missing-asset/index.ts +1 -1
  162. package/src/checks/{missing-template → missing-partial}/index.spec.ts +6 -6
  163. package/src/checks/{missing-template → missing-partial}/index.ts +6 -20
  164. package/src/checks/orphaned-partial/index.ts +3 -3
  165. package/src/checks/parser-blocking-script/index.spec.ts +0 -118
  166. package/src/checks/parser-blocking-script/index.ts +3 -33
  167. package/src/checks/parser-blocking-script/suggestions.ts +1 -28
  168. package/src/checks/translation-key-exists/index.ts +1 -1
  169. package/src/checks/unclosed-html-element/index.ts +5 -1
  170. package/src/checks/undefined-object/index.spec.ts +3 -109
  171. package/src/checks/undefined-object/index.ts +8 -33
  172. package/src/checks/unique-doc-param-names/index.ts +1 -1
  173. package/src/checks/unknown-filter/index.spec.ts +2 -2
  174. package/src/checks/unknown-filter/index.ts +3 -3
  175. package/src/checks/unknown-property/index.ts +1 -1
  176. package/src/checks/unrecognized-render-partial-arguments/index.spec.ts +5 -5
  177. package/src/checks/unrecognized-render-partial-arguments/index.ts +2 -5
  178. package/src/checks/unused-assign/index.spec.ts +0 -30
  179. package/src/checks/unused-assign/index.ts +1 -1
  180. package/src/checks/unused-doc-param/index.ts +1 -1
  181. package/src/checks/utils.ts +1 -1
  182. package/src/checks/valid-doc-param-types/index.ts +4 -4
  183. package/src/checks/valid-html-translation/index.spec.ts +42 -32
  184. package/src/checks/valid-html-translation/index.ts +7 -7
  185. package/src/checks/valid-json/index.ts +1 -1
  186. package/src/checks/valid-render-partial-argument-types/index.ts +2 -5
  187. package/src/checks/variable-name/index.ts +1 -1
  188. package/src/context-utils.spec.ts +49 -77
  189. package/src/context-utils.ts +39 -128
  190. package/src/disabled-checks/index.spec.ts +35 -0
  191. package/src/disabled-checks/index.ts +4 -2
  192. package/src/find-root.ts +12 -22
  193. package/src/fixes/autofix.spec.ts +2 -2
  194. package/src/fixes/autofix.ts +4 -4
  195. package/src/fixes/correctors/index.ts +4 -0
  196. package/src/ignore.spec.ts +0 -1
  197. package/src/index.ts +33 -21
  198. package/src/jsonc/parse.ts +1 -1
  199. package/src/liquid-doc/arguments.spec.ts +19 -45
  200. package/src/liquid-doc/arguments.ts +26 -39
  201. package/src/liquid-doc/liquidDoc.ts +1 -2
  202. package/src/liquid-doc/utils.ts +4 -3
  203. package/src/path.ts +1 -0
  204. package/src/test/{MockTheme.ts → MockApp.ts} +1 -1
  205. package/src/test/MockFileSystem.ts +9 -6
  206. package/src/test/index.ts +1 -1
  207. package/src/test/test-helper.ts +29 -127
  208. package/src/to-source-code.ts +20 -1
  209. package/src/types/{theme-liquid-docs.ts → platformos-liquid-docs.ts} +8 -13
  210. package/src/types/schemas/index.ts +0 -2
  211. package/src/types.ts +21 -92
  212. package/src/utils/file-utils.ts +0 -1
  213. package/src/utils/index.ts +0 -1
  214. package/src/yaml/parse.ts +111 -0
  215. package/src/AugmentedThemeDocset.ts +0 -137
  216. package/src/checks/app-block-missing-schema/index.spec.ts +0 -121
  217. package/src/checks/app-block-missing-schema/index.ts +0 -46
  218. package/src/checks/app-block-valid-tags/index.spec.ts +0 -96
  219. package/src/checks/app-block-valid-tags/index.ts +0 -54
  220. package/src/checks/asset-preload/index.spec.ts +0 -78
  221. package/src/checks/asset-preload/index.ts +0 -65
  222. package/src/checks/asset-size-app-block-css/index.spec.ts +0 -88
  223. package/src/checks/asset-size-app-block-css/index.ts +0 -78
  224. package/src/checks/asset-size-app-block-javascript/index.spec.ts +0 -66
  225. package/src/checks/asset-size-app-block-javascript/index.ts +0 -78
  226. package/src/checks/asset-size-css/index.spec.ts +0 -166
  227. package/src/checks/asset-size-css/index.ts +0 -160
  228. package/src/checks/asset-size-javascript/index.spec.ts +0 -184
  229. package/src/checks/asset-size-javascript/index.ts +0 -144
  230. package/src/checks/block-id-usage/index.spec.ts +0 -76
  231. package/src/checks/block-id-usage/index.ts +0 -72
  232. package/src/checks/cdn-preconnect/index.spec.ts +0 -40
  233. package/src/checks/cdn-preconnect/index.ts +0 -43
  234. package/src/checks/content-for-header-modification/index.spec.ts +0 -65
  235. package/src/checks/content-for-header-modification/index.ts +0 -72
  236. package/src/checks/deprecate-bgsizes/index.spec.ts +0 -41
  237. package/src/checks/deprecate-bgsizes/index.ts +0 -49
  238. package/src/checks/deprecate-lazysizes/index.spec.ts +0 -26
  239. package/src/checks/deprecate-lazysizes/index.ts +0 -58
  240. package/src/checks/deprecated-filter/fixes.ts +0 -264
  241. package/src/checks/deprecated-fonts-on-sections-and-blocks/deprecated-fonts-data.ts +0 -1343
  242. package/src/checks/deprecated-fonts-on-sections-and-blocks/index.spec.ts +0 -613
  243. package/src/checks/deprecated-fonts-on-sections-and-blocks/index.ts +0 -284
  244. package/src/checks/deprecated-fonts-on-settings-schema/index.spec.ts +0 -102
  245. package/src/checks/deprecated-fonts-on-settings-schema/index.ts +0 -66
  246. package/src/checks/duplicate-content-for-arguments/index.spec.ts +0 -98
  247. package/src/checks/duplicate-content-for-arguments/index.ts +0 -43
  248. package/src/checks/empty-block-content/index.spec.ts +0 -117
  249. package/src/checks/empty-block-content/index.ts +0 -60
  250. package/src/checks/hardcoded-routes/index.spec.ts +0 -58
  251. package/src/checks/hardcoded-routes/index.ts +0 -100
  252. package/src/checks/json-missing-block/index.spec.ts +0 -435
  253. package/src/checks/json-missing-block/index.ts +0 -56
  254. package/src/checks/json-missing-block/missing-block-utils.ts +0 -147
  255. package/src/checks/liquid-free-settings/index.spec.ts +0 -180
  256. package/src/checks/liquid-free-settings/index.ts +0 -79
  257. package/src/checks/missing-content-for-arguments/index.spec.ts +0 -144
  258. package/src/checks/missing-content-for-arguments/index.ts +0 -46
  259. package/src/checks/pagination-size/index.spec.ts +0 -158
  260. package/src/checks/pagination-size/index.ts +0 -104
  261. package/src/checks/remote-asset/index.spec.ts +0 -280
  262. package/src/checks/remote-asset/index.ts +0 -238
  263. package/src/checks/reserved-doc-param-names/index.spec.ts +0 -62
  264. package/src/checks/reserved-doc-param-names/index.ts +0 -57
  265. package/src/checks/schema-presets-block-order/index.spec.ts +0 -344
  266. package/src/checks/schema-presets-block-order/index.ts +0 -154
  267. package/src/checks/schema-presets-static-blocks/index.spec.ts +0 -145
  268. package/src/checks/schema-presets-static-blocks/index.ts +0 -126
  269. package/src/checks/static-stylesheet-and-javascript-tags/index.spec.ts +0 -257
  270. package/src/checks/static-stylesheet-and-javascript-tags/index.ts +0 -48
  271. package/src/checks/unique-settings-id/index.spec.ts +0 -24
  272. package/src/checks/unique-settings-id/index.ts +0 -84
  273. package/src/checks/unique-settings-id/test-data.ts +0 -1191
  274. package/src/checks/unique-static-block-id/index.spec.ts +0 -55
  275. package/src/checks/unique-static-block-id/index.ts +0 -60
  276. package/src/checks/unrecognized-content-for-arguments/index.spec.ts +0 -145
  277. package/src/checks/unrecognized-content-for-arguments/index.ts +0 -55
  278. package/src/checks/valid-block-target/index.spec.ts +0 -1396
  279. package/src/checks/valid-block-target/index.ts +0 -142
  280. package/src/checks/valid-content-for-argument-types/index.spec.ts +0 -382
  281. package/src/checks/valid-content-for-argument-types/index.ts +0 -42
  282. package/src/checks/valid-content-for-arguments/index.spec.ts +0 -107
  283. package/src/checks/valid-content-for-arguments/index.ts +0 -98
  284. package/src/checks/valid-local-blocks/index.spec.ts +0 -286
  285. package/src/checks/valid-local-blocks/index.ts +0 -100
  286. package/src/checks/valid-local-blocks/valid-block-utils.ts +0 -97
  287. package/src/checks/valid-schema/index.spec.ts +0 -174
  288. package/src/checks/valid-schema/index.ts +0 -41
  289. package/src/checks/valid-schema-name/index.spec.ts +0 -112
  290. package/src/checks/valid-schema-name/index.ts +0 -75
  291. package/src/checks/valid-settings-key/index.spec.ts +0 -321
  292. package/src/checks/valid-settings-key/index.ts +0 -144
  293. package/src/checks/valid-static-block-type/index.spec.ts +0 -38
  294. package/src/checks/valid-static-block-type/index.ts +0 -58
  295. package/src/checks/valid-visible-if/index.spec.ts +0 -619
  296. package/src/checks/valid-visible-if/index.ts +0 -184
  297. package/src/checks/valid-visible-if/visible-if-utils.ts +0 -158
  298. package/src/tags/content-for.ts +0 -25
  299. package/src/to-schema.ts +0 -231
  300. package/src/types/schemas/section.ts +0 -86
  301. package/src/types/schemas/theme-block.ts +0 -34
  302. package/src/types/theme-schemas.ts +0 -80
  303. package/src/utils/block.ts +0 -300
  304. package/src/utils/markup.ts +0 -10
@@ -1,65 +0,0 @@
1
- import { NodeTypes, TextNode } from '@platformos/liquid-html-parser';
2
- import { LiquidCheckDefinition, Severity, SourceCodeType } from '../../types';
3
- import { ValuedHtmlAttribute, isAttr, isNodeOfType, isValuedHtmlAttribute } from '../utils';
4
-
5
- function isPreload(attr: ValuedHtmlAttribute): boolean {
6
- return (
7
- isAttr(attr, 'rel') &&
8
- attr.value.some((node) => node.type === NodeTypes.TextNode && node.value === 'preload')
9
- );
10
- }
11
-
12
- export const AssetPreload: LiquidCheckDefinition = {
13
- meta: {
14
- code: 'AssetPreload',
15
- name: 'Prevent Manual Preloading of Assets',
16
- docs: {
17
- description:
18
- 'This check is aimed at discouraging the manual preloading of assets and encourages the use of appropriate Shopify filters.',
19
- url: 'https://shopify.dev/docs/storefronts/themes/tools/theme-check/checks/asset-preload',
20
- recommended: true,
21
- },
22
- type: SourceCodeType.LiquidHtml,
23
- severity: Severity.WARNING,
24
- schema: {},
25
- targets: [],
26
- },
27
-
28
- create(context) {
29
- return {
30
- async HtmlVoidElement(node) {
31
- const preloadLinkAttr = node.attributes.find(
32
- (attr) => isValuedHtmlAttribute(attr) && isPreload(attr),
33
- ) as ValuedHtmlAttribute | undefined;
34
-
35
- if (node.name === 'link' && preloadLinkAttr) {
36
- const asAttr: ValuedHtmlAttribute | undefined = node.attributes
37
- .filter(isValuedHtmlAttribute)
38
- .find((attr) => isAttr(attr, 'as'));
39
-
40
- const assetType = asAttr?.value.find((node): node is TextNode =>
41
- isNodeOfType(NodeTypes.TextNode, node),
42
- )?.value;
43
-
44
- let message = '';
45
-
46
- if (assetType === 'style') {
47
- message =
48
- 'For better performance, prefer using the preload argument of the stylesheet_tag filter';
49
- } else if (assetType === 'image') {
50
- message =
51
- 'For better performance, prefer using the preload argument of the image_tag filter';
52
- } else {
53
- message = 'For better performance, prefer using the preload_tag filter';
54
- }
55
-
56
- context.report({
57
- message,
58
- startIndex: node.position.start,
59
- endIndex: node.position.end,
60
- });
61
- }
62
- },
63
- };
64
- },
65
- };
@@ -1,88 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { AssetSizeAppBlockCSS } from '.';
3
- import { check, MockTheme } from '../../test';
4
-
5
- describe('Module: AssetSizeAppBlockCSS', () => {
6
- const extensionFiles: MockTheme = {
7
- 'assets/app.css': '* { color: green } ',
8
- 'blocks/app.liquid': `
9
- {% schema %}
10
- {
11
- "stylesheet": "app.css"
12
- }
13
- {% endschema %}
14
- `,
15
- };
16
-
17
- it('should not report any offenses if CSS is smaller than threshold', async () => {
18
- const offenses = await check(extensionFiles, [AssetSizeAppBlockCSS]);
19
-
20
- expect(offenses).toHaveLength(0);
21
- });
22
-
23
- it('should report an offense if CSS is larger than threshold', async () => {
24
- const offenses = await check(
25
- extensionFiles,
26
- [AssetSizeAppBlockCSS],
27
- {},
28
- {
29
- AssetSizeAppBlockCSS: {
30
- enabled: true,
31
- thresholdInBytes: 1,
32
- },
33
- },
34
- );
35
-
36
- expect(offenses).toHaveLength(1);
37
- expect(offenses[0]).toMatchObject({
38
- message: `The file size for 'app.css' (19 B) exceeds the configured threshold (1 B)`,
39
- uri: 'file:///blocks/app.liquid',
40
- start: { index: 51 },
41
- end: { index: 58 },
42
- });
43
- });
44
-
45
- it('should report an offense if the CSS file does not exist', async () => {
46
- const extensionFiles: MockTheme = {
47
- 'blocks/app.liquid': `
48
- {% schema %}
49
- {
50
- "stylesheet": "nonexistent.css"
51
- }
52
- {% endschema %}
53
- `,
54
- };
55
-
56
- const offenses = await check(extensionFiles, [AssetSizeAppBlockCSS]);
57
-
58
- expect(offenses).toHaveLength(1);
59
- expect(offenses[0]).toMatchObject({
60
- message: `'nonexistent.css' does not exist.`,
61
- uri: 'file:///blocks/app.liquid',
62
- start: { index: 57 },
63
- end: { index: 72 },
64
- });
65
- });
66
-
67
- it('should reports offense if the CSS file does not exist and the asset has a trailing comma', async () => {
68
- const extensionFiles: MockTheme = {
69
- 'blocks/app.liquid': `
70
- {% schema %}
71
- {
72
- "stylesheet": "nonexistent.css",
73
- }
74
- {% endschema %}
75
- `,
76
- };
77
-
78
- const offenses = await check(extensionFiles, [AssetSizeAppBlockCSS]);
79
-
80
- expect(offenses).toHaveLength(1);
81
- expect(offenses[0]).toMatchObject({
82
- message: `'nonexistent.css' does not exist.`,
83
- uri: 'file:///blocks/app.liquid',
84
- start: { index: 57 },
85
- end: { index: 72 },
86
- });
87
- });
88
- });
@@ -1,78 +0,0 @@
1
- import { parseJSON } from '../../json';
2
- import {
3
- ConfigTarget,
4
- LiquidCheckDefinition,
5
- SchemaProp,
6
- Severity,
7
- SourceCodeType,
8
- } from '../../types';
9
- import { isError } from '../../utils';
10
- import { doesFileExceedThreshold, doesFileExist } from '../../utils/file-utils';
11
-
12
- const schema = {
13
- thresholdInBytes: SchemaProp.number(100000),
14
- };
15
-
16
- export const AssetSizeAppBlockCSS: LiquidCheckDefinition<typeof schema> = {
17
- meta: {
18
- code: 'AssetSizeAppBlockCSS',
19
- name: 'Asset Size App Block CSS',
20
- docs: {
21
- description:
22
- 'This check is aimed at preventing large CSS bundles from being included via Theme App Extensions.',
23
- url: 'https://shopify.dev/docs/storefronts/themes/tools/theme-check/checks/asset-size-app-block-css',
24
- recommended: true,
25
- },
26
- type: SourceCodeType.LiquidHtml,
27
- severity: Severity.ERROR,
28
- schema,
29
- targets: [ConfigTarget.ThemeAppExtension],
30
- },
31
-
32
- create(context) {
33
- if (!context.fileSize) {
34
- return {};
35
- }
36
-
37
- return {
38
- async LiquidRawTag(node) {
39
- if (node.name !== 'schema') return;
40
- const schema = parseJSON(node.body.value);
41
- if (isError(schema)) return;
42
- const stylesheet = schema.stylesheet;
43
- if (!stylesheet) return;
44
-
45
- const relativePath = `assets/${stylesheet}`;
46
- const thresholdInBytes = context.settings.thresholdInBytes;
47
-
48
- const startIndex = node.body.position.start + node.body.value.indexOf(stylesheet);
49
- const endIndex = startIndex + stylesheet.length;
50
-
51
- const fileExists = await doesFileExist(context, relativePath);
52
-
53
- if (!fileExists) {
54
- context.report({
55
- message: `'${stylesheet}' does not exist.`,
56
- startIndex: startIndex,
57
- endIndex: endIndex,
58
- });
59
- return;
60
- }
61
-
62
- const [fileExceedsThreshold, fileSize] = await doesFileExceedThreshold(
63
- context,
64
- relativePath,
65
- thresholdInBytes,
66
- );
67
-
68
- if (fileExceedsThreshold) {
69
- context.report({
70
- message: `The file size for '${stylesheet}' (${fileSize} B) exceeds the configured threshold (${thresholdInBytes} B)`,
71
- startIndex: startIndex,
72
- endIndex: endIndex,
73
- });
74
- }
75
- },
76
- };
77
- },
78
- };
@@ -1,66 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { AssetSizeAppBlockJavaScript } from '.';
3
- import { check, MockTheme } from '../../test';
4
-
5
- describe('Module: AssetSizeAppBlockJavaScript', () => {
6
- const extensionFiles: MockTheme = {
7
- 'assets/app.js': 'console.log("Hello, world!");',
8
- 'blocks/app.liquid': `
9
- {% schema %}
10
- {
11
- "javascript": "app.js"
12
- }
13
- {% endschema %}
14
- `,
15
- };
16
-
17
- it('should not report any offenses if JavaScript is smaller than threshold', async () => {
18
- const offenses = await check(extensionFiles, [AssetSizeAppBlockJavaScript]);
19
-
20
- expect(offenses).toHaveLength(0);
21
- });
22
-
23
- it('should report an offense if JavaScript is larger than threshold', async () => {
24
- const offenses = await check(
25
- extensionFiles,
26
- [AssetSizeAppBlockJavaScript],
27
- {},
28
- {
29
- AssetSizeAppBlockJavaScript: {
30
- enabled: true,
31
- thresholdInBytes: 1,
32
- },
33
- },
34
- );
35
-
36
- expect(offenses).toHaveLength(1);
37
- expect(offenses[0]).toMatchObject({
38
- message: `The file size for 'app.js' (29 B) exceeds the configured threshold (1 B)`,
39
- uri: 'file:///blocks/app.liquid',
40
- start: { index: 51 },
41
- end: { index: 57 },
42
- });
43
- });
44
-
45
- it('should report an offense if the JavaScript file does not exist', async () => {
46
- const extensionFiles: MockTheme = {
47
- 'blocks/app.liquid': `
48
- {% schema %}
49
- {
50
- "javascript": "nonexistent.js"
51
- }
52
- {% endschema %}
53
- `,
54
- };
55
-
56
- const offenses = await check(extensionFiles, [AssetSizeAppBlockJavaScript]);
57
-
58
- expect(offenses).toHaveLength(1);
59
- expect(offenses[0]).toMatchObject({
60
- message: `'nonexistent.js' does not exist.`,
61
- uri: 'file:///blocks/app.liquid',
62
- start: { index: 57 },
63
- end: { index: 71 },
64
- });
65
- });
66
- });
@@ -1,78 +0,0 @@
1
- import { parseJSON } from '../../json';
2
- import {
3
- ConfigTarget,
4
- LiquidCheckDefinition,
5
- SchemaProp,
6
- Severity,
7
- SourceCodeType,
8
- } from '../../types';
9
- import { isError } from '../../utils';
10
- import { doesFileExist, doesFileExceedThreshold } from '../../utils/file-utils';
11
-
12
- const schema = {
13
- thresholdInBytes: SchemaProp.number(10000),
14
- };
15
-
16
- export const AssetSizeAppBlockJavaScript: LiquidCheckDefinition<typeof schema> = {
17
- meta: {
18
- code: 'AssetSizeAppBlockJavaScript',
19
- name: 'Asset Size App Block JavaScript',
20
- docs: {
21
- description:
22
- 'This check is aimed at preventing large JavaScript bundles from being included via Theme App Extensions.',
23
- url: 'https://shopify.dev/docs/storefronts/themes/tools/theme-check/checks/asset-size-app-block-javascript',
24
- recommended: true,
25
- },
26
- type: SourceCodeType.LiquidHtml,
27
- severity: Severity.ERROR,
28
- schema,
29
- targets: [ConfigTarget.ThemeAppExtension],
30
- },
31
-
32
- create(context) {
33
- if (!context.fileSize) {
34
- return {};
35
- }
36
-
37
- return {
38
- async LiquidRawTag(node) {
39
- if (node.name !== 'schema') return;
40
- const schema = parseJSON(node.body.value);
41
- if (isError(schema)) return;
42
- const javascript = schema.javascript;
43
- if (!javascript) return;
44
-
45
- const relativePath = `assets/${javascript}`;
46
- const thresholdInBytes = context.settings.thresholdInBytes;
47
-
48
- const startIndex = node.body.position.start + node.body.value.indexOf(javascript);
49
- const endIndex = startIndex + javascript.length;
50
-
51
- const fileExists = await doesFileExist(context, relativePath);
52
-
53
- if (!fileExists) {
54
- context.report({
55
- message: `'${javascript}' does not exist.`,
56
- startIndex: startIndex,
57
- endIndex: endIndex,
58
- });
59
- return;
60
- }
61
-
62
- const [fileExceedsThreshold, fileSize] = await doesFileExceedThreshold(
63
- context,
64
- relativePath,
65
- thresholdInBytes,
66
- );
67
-
68
- if (fileExceedsThreshold) {
69
- context.report({
70
- message: `The file size for '${javascript}' (${fileSize} B) exceeds the configured threshold (${thresholdInBytes} B)`,
71
- startIndex: startIndex,
72
- endIndex: endIndex,
73
- });
74
- }
75
- },
76
- };
77
- },
78
- };
@@ -1,166 +0,0 @@
1
- import { vi, expect, describe, it, afterEach } from 'vitest';
2
- import { AssetSizeCSS } from '.';
3
- import { check, MockTheme } from '../../test';
4
- import { SchemaProp } from '../../types';
5
- import { hasRemoteAssetSizeExceededThreshold } from '../../utils/file-utils';
6
-
7
- vi.mock('../../utils/file-utils', async (importOriginal) => {
8
- const actual: any = await importOriginal();
9
- return {
10
- ...actual,
11
- hasRemoteAssetSizeExceededThreshold: vi.fn(),
12
- };
13
- });
14
-
15
- describe('Module: AssetSizeCSS', () => {
16
- const extensionFiles: MockTheme = {
17
- 'assets/theme.css': '* { color: green !important; }',
18
- 'templates/index.liquid': `
19
- <html>
20
- <head>
21
- <link href="{{ 'theme.css' | asset_url }}" rel="stylesheet">
22
- </head>
23
- </html>
24
- `,
25
- };
26
-
27
- const httpTest: MockTheme = {
28
- 'templates/index.liquid': `
29
- <html>
30
- <head>
31
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
32
- </head>
33
- </html>
34
- `,
35
- };
36
-
37
- afterEach(() => {
38
- vi.clearAllMocks();
39
- });
40
-
41
- it('should not report any offenses if CSS is smaller than threshold', async () => {
42
- const offenses = await check(extensionFiles, [AssetSizeCSS]);
43
-
44
- expect(offenses).toHaveLength(0);
45
- });
46
-
47
- it('should report an offense if CSS is larger than threshold', async () => {
48
- const offenses = await check(
49
- extensionFiles,
50
- [AssetSizeCSS],
51
- {},
52
- {
53
- AssetSizeCSS: {
54
- enabled: true,
55
- thresholdInBytes: 1,
56
- },
57
- },
58
- );
59
-
60
- expect(offenses).toHaveLength(1);
61
- expect(offenses[0]).toMatchObject({
62
- message: 'The CSS file size exceeds the threshold of 1 bytes',
63
- uri: 'file:///templates/index.liquid',
64
- start: { index: 51 },
65
- end: { index: 80 },
66
- });
67
- });
68
-
69
- it('should report a warning when the CSS file size exceeds the threshold', async () => {
70
- vi.mocked(hasRemoteAssetSizeExceededThreshold).mockReturnValue(Promise.resolve(true));
71
- const offenses = await check(
72
- httpTest,
73
- [AssetSizeCSS],
74
- {},
75
- {
76
- AssetSizeCSS: {
77
- enabled: true,
78
- thresholdInBytes: 1,
79
- },
80
- },
81
- );
82
-
83
- expect(offenses).toHaveLength(1);
84
- expect(offenses[0]).toMatchObject({
85
- message: 'The CSS file size exceeds the threshold of 1 bytes',
86
- uri: 'file:///templates/index.liquid',
87
- start: { index: 51 },
88
- end: { index: 122 },
89
- });
90
- });
91
-
92
- it('should not report any offenses if CSS is smaller than threshold 2', async () => {
93
- vi.mocked(hasRemoteAssetSizeExceededThreshold).mockResolvedValue(false);
94
- const extensionFiles: MockTheme = {
95
- 'assets/theme.css': 'console.log("hello world");',
96
- 'templates/index.liquid': `
97
- <html>
98
- <head>
99
- {{ 'theme.css' | asset_url | stylesheet_tag }}
100
- {{ "https://example.com" | stylesheet_tag }}
101
- </head>
102
- </html>
103
- `,
104
- };
105
-
106
- const offenses = await check(extensionFiles, [AssetSizeCSS]);
107
-
108
- expect(offenses).toHaveLength(0);
109
- });
110
-
111
- it('should report an offense if CSS is larger than threshold 2', async () => {
112
- vi.mocked(hasRemoteAssetSizeExceededThreshold).mockResolvedValue(true);
113
- const extensionFiles: MockTheme = {
114
- 'assets/theme.css': 'console.log("hello world");',
115
- 'templates/index.liquid': `
116
- <html>
117
- <head>
118
- {{ 'theme.css' | asset_url | stylesheet_tag }}
119
- {{ "https://example.com" | stylesheet_tag }}
120
- </head>
121
- </html>
122
- `,
123
- };
124
-
125
- const offenses = await check(
126
- extensionFiles,
127
- [AssetSizeCSS],
128
- {},
129
- {
130
- AssetSizeCSS: {
131
- enabled: true,
132
- thresholdInBytes: 2,
133
- },
134
- },
135
- );
136
-
137
- expect(offenses).toHaveLength(2);
138
- expect(offenses[0]).toMatchObject({
139
- message: 'The CSS file size exceeds the threshold of 2 bytes',
140
- uri: 'file:///templates/index.liquid',
141
- start: { index: 48 },
142
- end: { index: 89 },
143
- });
144
- expect(offenses[1]).toMatchObject({
145
- message: 'The CSS file size exceeds the threshold of 2 bytes',
146
- uri: 'file:///templates/index.liquid',
147
- start: { index: 107 },
148
- end: { index: 128 },
149
- });
150
- });
151
-
152
- it('should not report any offenses if there is no stylesheet', async () => {
153
- const extensionFiles: MockTheme = {
154
- 'templates/index.liquid': `
155
- <html>
156
- <head>
157
- </head>
158
- </html>
159
- `,
160
- };
161
-
162
- const offenses = await check(extensionFiles, [AssetSizeCSS]);
163
-
164
- expect(offenses).toHaveLength(0);
165
- });
166
- });
@@ -1,160 +0,0 @@
1
- import {
2
- LiquidHtmlNode,
3
- LiquidString,
4
- LiquidVariable,
5
- LiquidVariableOutput,
6
- NodeTypes,
7
- TextNode,
8
- } from '@platformos/liquid-html-parser';
9
- import { LiquidCheckDefinition, SchemaProp, Severity, SourceCodeType } from '../../types';
10
- import { last } from '../../utils';
11
- import {
12
- hasRemoteAssetSizeExceededThreshold,
13
- hasLocalAssetSizeExceededThreshold,
14
- } from '../../utils/file-utils';
15
- import {
16
- ValuedHtmlAttribute,
17
- isAttr,
18
- isNodeOfType,
19
- isValuedHtmlAttribute,
20
- valueIncludes,
21
- } from '../utils';
22
-
23
- const schema = {
24
- thresholdInBytes: SchemaProp.number(100000),
25
- };
26
-
27
- function isTextNode(node: LiquidHtmlNode): node is TextNode {
28
- return node.type === NodeTypes.TextNode;
29
- }
30
-
31
- function isLiquidVariableOutput(node: LiquidHtmlNode): node is LiquidVariableOutput {
32
- return node.type === NodeTypes.LiquidVariableOutput;
33
- }
34
-
35
- function isLiquidVariable(node: LiquidHtmlNode | string): node is LiquidVariable {
36
- return typeof node !== 'string' && node.type === NodeTypes.LiquidVariable;
37
- }
38
-
39
- function isString(node: LiquidHtmlNode): node is LiquidString {
40
- return node.type === NodeTypes.String;
41
- }
42
-
43
- export const AssetSizeCSS: LiquidCheckDefinition<typeof schema> = {
44
- meta: {
45
- code: 'AssetSizeCSS',
46
- aliases: ['AssetSizeCSSStylesheetTag'],
47
- name: 'Prevent Large CSS bundles',
48
- docs: {
49
- description: 'This check is aimed at preventing large CSS bundles for speed.',
50
- url: 'https://shopify.dev/docs/storefronts/themes/tools/theme-check/checks/asset-size-css',
51
- recommended: false,
52
- },
53
- type: SourceCodeType.LiquidHtml,
54
- severity: Severity.ERROR,
55
- schema,
56
- targets: [],
57
- },
58
-
59
- create(context) {
60
- if (!context.fileSize) {
61
- return {};
62
- }
63
-
64
- const thresholdInBytes = context.settings.thresholdInBytes;
65
-
66
- async function checkRemoteAssetSize(url: string, position: { start: number; end: number }) {
67
- if (await hasRemoteAssetSizeExceededThreshold(url, thresholdInBytes)) {
68
- context.report({
69
- message: `The CSS file size exceeds the threshold of ${thresholdInBytes} bytes`,
70
- startIndex: position.start,
71
- endIndex: position.end,
72
- });
73
- }
74
- }
75
-
76
- async function checkThemeAssetSize(srcValue: string, position: { start: number; end: number }) {
77
- if (
78
- await hasLocalAssetSizeExceededThreshold(context, `assets/${srcValue}`, thresholdInBytes)
79
- ) {
80
- context.report({
81
- message: `The CSS file size exceeds the threshold of ${thresholdInBytes} bytes`,
82
- startIndex: position.start,
83
- endIndex: position.end,
84
- });
85
- }
86
- }
87
-
88
- return {
89
- async HtmlVoidElement(node) {
90
- if (node.name !== 'link') return;
91
-
92
- const relIsStylesheet = node.attributes
93
- .filter(isValuedHtmlAttribute)
94
- .find((attr) => isAttr(attr, 'rel') && valueIncludes(attr, 'stylesheet'));
95
- if (!relIsStylesheet) return;
96
-
97
- const href: ValuedHtmlAttribute | undefined = node.attributes
98
- .filter(isValuedHtmlAttribute)
99
- .find((attr) => isAttr(attr, 'href'));
100
- if (!href) return;
101
- if (href.value.length !== 1) return;
102
-
103
- /* This ensures that the link entered is a text and not anything else like http//..{}
104
- This also checks if the value starts with 'http://', 'https://' or '//' to ensure its a valid link. */
105
- if (isTextNode(href.value[0]) && /(https?:)?\/\//.test(href.value[0].value)) {
106
- const url = href.value[0].value;
107
- await checkRemoteAssetSize(url, href.attributePosition);
108
- }
109
-
110
- /* This code checks if we have a link with a liquid variable
111
- and that its a string with one filter, `asset_url`. This is done to ensure our .css link is
112
- entered with a 'asset_url' to produce valid output. */
113
- if (
114
- isLiquidVariableOutput(href.value[0]) &&
115
- isLiquidVariable(href.value[0].markup) &&
116
- isString(href.value[0].markup.expression) &&
117
- href.value[0].markup.filters.length === 1 &&
118
- href.value[0].markup.filters[0].name === 'asset_url'
119
- ) {
120
- const assetName = href.value[0].markup.expression.value;
121
- await checkThemeAssetSize(assetName, href.attributePosition);
122
- }
123
- },
124
-
125
- async LiquidFilter(node, ancestors) {
126
- if (node.name !== 'stylesheet_tag') return;
127
-
128
- const liquidVariableParent = last(ancestors);
129
-
130
- if (!liquidVariableParent || !isNodeOfType(NodeTypes.LiquidVariable, liquidVariableParent))
131
- return;
132
-
133
- if (liquidVariableParent.expression.type !== NodeTypes.String) return;
134
-
135
- /* This code ensures we have a liquid variable with 1 expression, 1 filter, and that it is a valid http link.
136
- This is done to ensure a valid http link is entered with 1 filter being the `stylesheet_tag` for valid output. */
137
- if (
138
- liquidVariableParent.expression.value[0].length == 1 &&
139
- liquidVariableParent.filters.length == 1 &&
140
- /(https?:)?\/\//.test(liquidVariableParent.expression.value)
141
- ) {
142
- const url = liquidVariableParent.expression.value;
143
- await checkRemoteAssetSize(url, liquidVariableParent.expression.position);
144
- }
145
-
146
- /* This code ensures we have a liquid variable with 1 expression, 2 filters being asset_url and stylesheet_tag
147
- This is done to ensure a .css file has the 'asset_url' and 'stylesheet_tag' to produce the appropriate output. */
148
- if (
149
- liquidVariableParent.expression.value[0].length == 1 &&
150
- liquidVariableParent.filters.length == 2 &&
151
- liquidVariableParent.filters[0].name === 'asset_url' &&
152
- liquidVariableParent.filters[1].name === 'stylesheet_tag'
153
- ) {
154
- const css = liquidVariableParent.expression.value;
155
- await checkThemeAssetSize(css, liquidVariableParent.position);
156
- }
157
- },
158
- };
159
- },
160
- };