@platformos/platformos-check-common 0.0.7 → 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 (309) hide show
  1. package/CHANGELOG.md +8 -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/doc-generator/DocBlockGenerator.d.ts +16 -0
  84. package/dist/doc-generator/DocBlockGenerator.js +464 -0
  85. package/dist/doc-generator/DocBlockGenerator.js.map +1 -0
  86. package/dist/doc-generator/index.d.ts +1 -0
  87. package/dist/doc-generator/index.js +6 -0
  88. package/dist/doc-generator/index.js.map +1 -0
  89. package/dist/find-root.d.ts +7 -10
  90. package/dist/find-root.js +10 -17
  91. package/dist/find-root.js.map +1 -1
  92. package/dist/fixes/autofix.d.ts +4 -4
  93. package/dist/fixes/autofix.js +2 -2
  94. package/dist/fixes/autofix.js.map +1 -1
  95. package/dist/fixes/correctors/index.js +4 -0
  96. package/dist/fixes/correctors/index.js.map +1 -1
  97. package/dist/index.d.ts +4 -5
  98. package/dist/index.js +34 -17
  99. package/dist/index.js.map +1 -1
  100. package/dist/jsonc/parse.d.ts +1 -1
  101. package/dist/jsonc/parse.js +1 -1
  102. package/dist/liquid-doc/arguments.d.ts +7 -8
  103. package/dist/liquid-doc/arguments.js +20 -28
  104. package/dist/liquid-doc/arguments.js.map +1 -1
  105. package/dist/liquid-doc/liquidDoc.d.ts +1 -1
  106. package/dist/liquid-doc/liquidDoc.js.map +1 -1
  107. package/dist/liquid-doc/utils.d.ts +1 -1
  108. package/dist/liquid-doc/utils.js +4 -3
  109. package/dist/liquid-doc/utils.js.map +1 -1
  110. package/dist/path.d.ts +1 -0
  111. package/dist/path.js +5 -1
  112. package/dist/path.js.map +1 -1
  113. package/dist/test/MockApp.d.ts +16 -0
  114. package/dist/test/MockApp.js +16 -0
  115. package/dist/test/MockApp.js.map +1 -0
  116. package/dist/test/MockFileSystem.d.ts +3 -3
  117. package/dist/test/MockFileSystem.js +6 -6
  118. package/dist/test/MockFileSystem.js.map +1 -1
  119. package/dist/test/index.d.ts +1 -1
  120. package/dist/test/index.js +1 -1
  121. package/dist/test/index.js.map +1 -1
  122. package/dist/test/test-helper.d.ts +10 -9
  123. package/dist/test/test-helper.js +15 -106
  124. package/dist/test/test-helper.js.map +1 -1
  125. package/dist/to-schema.d.ts +1 -1
  126. package/dist/to-source-code.d.ts +3 -2
  127. package/dist/to-source-code.js +20 -0
  128. package/dist/to-source-code.js.map +1 -1
  129. package/dist/tsconfig.tsbuildinfo +1 -1
  130. package/dist/types/platformos-liquid-docs.d.ts +128 -0
  131. package/dist/types/platformos-liquid-docs.js +3 -0
  132. package/dist/types/platformos-liquid-docs.js.map +1 -0
  133. package/dist/types/schemas/index.d.ts +0 -2
  134. package/dist/types/schemas/index.js.map +1 -1
  135. package/dist/types.d.ts +18 -67
  136. package/dist/types.js +3 -5
  137. package/dist/types.js.map +1 -1
  138. package/dist/utils/block.js.map +1 -1
  139. package/dist/utils/index.d.ts +0 -1
  140. package/dist/utils/index.js +0 -1
  141. package/dist/utils/index.js.map +1 -1
  142. package/dist/yaml/parse.d.ts +5 -0
  143. package/dist/yaml/parse.js +94 -0
  144. package/dist/yaml/parse.js.map +1 -0
  145. package/package.json +4 -3
  146. package/src/{AugmentedThemeDocset.spec.ts → AugmentedPlatformOSDocset.spec.ts} +47 -34
  147. package/src/AugmentedPlatformOSDocset.ts +89 -0
  148. package/src/JSONValidator.ts +1 -1
  149. package/src/checks/deprecated-filter/index.spec.ts +76 -248
  150. package/src/checks/deprecated-filter/index.ts +5 -53
  151. package/src/checks/deprecated-tag/index.spec.ts +85 -34
  152. package/src/checks/deprecated-tag/index.ts +27 -22
  153. package/src/checks/duplicate-function-arguments/index.ts +1 -1
  154. package/src/checks/duplicate-render-partial-arguments/index.ts +1 -1
  155. package/src/checks/graphql/index.ts +1 -1
  156. package/src/checks/img-width-and-height/index.ts +1 -1
  157. package/src/checks/index.ts +11 -80
  158. package/src/checks/invalid-hash-assign-target/index.spec.ts +14 -14
  159. package/src/checks/json-syntax-error/index.ts +1 -1
  160. package/src/checks/liquid-html-syntax-error/checks/InvalidBooleanExpression.spec.ts +0 -11
  161. package/src/checks/liquid-html-syntax-error/checks/InvalidLoopArguments.spec.ts +1 -2
  162. package/src/checks/liquid-html-syntax-error/index.spec.ts +1 -6
  163. package/src/checks/liquid-html-syntax-error/index.ts +2 -2
  164. package/src/checks/matching-translations/index.spec.ts +89 -346
  165. package/src/checks/matching-translations/index.ts +24 -35
  166. package/src/checks/metadata-params/index.ts +5 -7
  167. package/src/checks/missing-asset/index.ts +1 -1
  168. package/src/checks/{missing-template → missing-partial}/index.spec.ts +6 -6
  169. package/src/checks/{missing-template → missing-partial}/index.ts +6 -20
  170. package/src/checks/orphaned-partial/index.ts +3 -3
  171. package/src/checks/parser-blocking-script/index.spec.ts +0 -118
  172. package/src/checks/parser-blocking-script/index.ts +3 -33
  173. package/src/checks/parser-blocking-script/suggestions.ts +1 -28
  174. package/src/checks/translation-key-exists/index.ts +1 -1
  175. package/src/checks/unclosed-html-element/index.ts +5 -1
  176. package/src/checks/undefined-object/index.spec.ts +3 -109
  177. package/src/checks/undefined-object/index.ts +8 -33
  178. package/src/checks/unique-doc-param-names/index.ts +1 -1
  179. package/src/checks/unknown-filter/index.spec.ts +2 -2
  180. package/src/checks/unknown-filter/index.ts +3 -3
  181. package/src/checks/unknown-property/index.ts +1 -1
  182. package/src/checks/unrecognized-render-partial-arguments/index.spec.ts +5 -5
  183. package/src/checks/unrecognized-render-partial-arguments/index.ts +2 -5
  184. package/src/checks/unused-assign/index.spec.ts +0 -30
  185. package/src/checks/unused-assign/index.ts +1 -1
  186. package/src/checks/unused-doc-param/index.ts +1 -1
  187. package/src/checks/utils.ts +1 -1
  188. package/src/checks/valid-doc-param-types/index.ts +4 -4
  189. package/src/checks/valid-html-translation/index.spec.ts +42 -32
  190. package/src/checks/valid-html-translation/index.ts +7 -7
  191. package/src/checks/valid-json/index.ts +1 -1
  192. package/src/checks/valid-render-partial-argument-types/index.ts +2 -5
  193. package/src/checks/variable-name/index.ts +1 -1
  194. package/src/context-utils.spec.ts +49 -77
  195. package/src/context-utils.ts +39 -128
  196. package/src/disabled-checks/index.spec.ts +35 -0
  197. package/src/disabled-checks/index.ts +4 -2
  198. package/src/find-root.ts +12 -22
  199. package/src/fixes/autofix.spec.ts +2 -2
  200. package/src/fixes/autofix.ts +4 -4
  201. package/src/fixes/correctors/index.ts +4 -0
  202. package/src/ignore.spec.ts +0 -1
  203. package/src/index.ts +33 -21
  204. package/src/jsonc/parse.ts +1 -1
  205. package/src/liquid-doc/arguments.spec.ts +19 -45
  206. package/src/liquid-doc/arguments.ts +26 -39
  207. package/src/liquid-doc/liquidDoc.ts +1 -2
  208. package/src/liquid-doc/utils.ts +4 -3
  209. package/src/path.ts +1 -0
  210. package/src/test/{MockTheme.ts → MockApp.ts} +1 -1
  211. package/src/test/MockFileSystem.ts +6 -6
  212. package/src/test/index.ts +1 -1
  213. package/src/test/test-helper.ts +29 -127
  214. package/src/to-source-code.ts +20 -1
  215. package/src/types/{theme-liquid-docs.ts → platformos-liquid-docs.ts} +8 -13
  216. package/src/types/schemas/index.ts +0 -2
  217. package/src/types.ts +21 -92
  218. package/src/utils/index.ts +0 -1
  219. package/src/yaml/parse.ts +111 -0
  220. package/src/AugmentedThemeDocset.ts +0 -137
  221. package/src/checks/app-block-missing-schema/index.spec.ts +0 -121
  222. package/src/checks/app-block-missing-schema/index.ts +0 -46
  223. package/src/checks/app-block-valid-tags/index.spec.ts +0 -96
  224. package/src/checks/app-block-valid-tags/index.ts +0 -54
  225. package/src/checks/asset-preload/index.spec.ts +0 -78
  226. package/src/checks/asset-preload/index.ts +0 -65
  227. package/src/checks/asset-size-app-block-css/index.spec.ts +0 -88
  228. package/src/checks/asset-size-app-block-css/index.ts +0 -78
  229. package/src/checks/asset-size-app-block-javascript/index.spec.ts +0 -66
  230. package/src/checks/asset-size-app-block-javascript/index.ts +0 -78
  231. package/src/checks/asset-size-css/index.spec.ts +0 -166
  232. package/src/checks/asset-size-css/index.ts +0 -160
  233. package/src/checks/asset-size-javascript/index.spec.ts +0 -184
  234. package/src/checks/asset-size-javascript/index.ts +0 -144
  235. package/src/checks/block-id-usage/index.spec.ts +0 -76
  236. package/src/checks/block-id-usage/index.ts +0 -72
  237. package/src/checks/cdn-preconnect/index.spec.ts +0 -40
  238. package/src/checks/cdn-preconnect/index.ts +0 -43
  239. package/src/checks/content-for-header-modification/index.spec.ts +0 -65
  240. package/src/checks/content-for-header-modification/index.ts +0 -72
  241. package/src/checks/deprecate-bgsizes/index.spec.ts +0 -41
  242. package/src/checks/deprecate-bgsizes/index.ts +0 -49
  243. package/src/checks/deprecate-lazysizes/index.spec.ts +0 -26
  244. package/src/checks/deprecate-lazysizes/index.ts +0 -58
  245. package/src/checks/deprecated-filter/fixes.ts +0 -264
  246. package/src/checks/deprecated-fonts-on-sections-and-blocks/deprecated-fonts-data.ts +0 -1343
  247. package/src/checks/deprecated-fonts-on-sections-and-blocks/index.spec.ts +0 -613
  248. package/src/checks/deprecated-fonts-on-sections-and-blocks/index.ts +0 -284
  249. package/src/checks/deprecated-fonts-on-settings-schema/index.spec.ts +0 -102
  250. package/src/checks/deprecated-fonts-on-settings-schema/index.ts +0 -66
  251. package/src/checks/duplicate-content-for-arguments/index.spec.ts +0 -98
  252. package/src/checks/duplicate-content-for-arguments/index.ts +0 -43
  253. package/src/checks/empty-block-content/index.spec.ts +0 -117
  254. package/src/checks/empty-block-content/index.ts +0 -60
  255. package/src/checks/hardcoded-routes/index.spec.ts +0 -58
  256. package/src/checks/hardcoded-routes/index.ts +0 -100
  257. package/src/checks/json-missing-block/index.spec.ts +0 -435
  258. package/src/checks/json-missing-block/index.ts +0 -56
  259. package/src/checks/json-missing-block/missing-block-utils.ts +0 -147
  260. package/src/checks/liquid-free-settings/index.spec.ts +0 -180
  261. package/src/checks/liquid-free-settings/index.ts +0 -79
  262. package/src/checks/missing-content-for-arguments/index.spec.ts +0 -144
  263. package/src/checks/missing-content-for-arguments/index.ts +0 -46
  264. package/src/checks/pagination-size/index.spec.ts +0 -158
  265. package/src/checks/pagination-size/index.ts +0 -104
  266. package/src/checks/remote-asset/index.spec.ts +0 -280
  267. package/src/checks/remote-asset/index.ts +0 -238
  268. package/src/checks/reserved-doc-param-names/index.spec.ts +0 -62
  269. package/src/checks/reserved-doc-param-names/index.ts +0 -57
  270. package/src/checks/schema-presets-block-order/index.spec.ts +0 -344
  271. package/src/checks/schema-presets-block-order/index.ts +0 -154
  272. package/src/checks/schema-presets-static-blocks/index.spec.ts +0 -145
  273. package/src/checks/schema-presets-static-blocks/index.ts +0 -126
  274. package/src/checks/static-stylesheet-and-javascript-tags/index.spec.ts +0 -257
  275. package/src/checks/static-stylesheet-and-javascript-tags/index.ts +0 -48
  276. package/src/checks/unique-settings-id/index.spec.ts +0 -24
  277. package/src/checks/unique-settings-id/index.ts +0 -84
  278. package/src/checks/unique-settings-id/test-data.ts +0 -1191
  279. package/src/checks/unique-static-block-id/index.spec.ts +0 -55
  280. package/src/checks/unique-static-block-id/index.ts +0 -60
  281. package/src/checks/unrecognized-content-for-arguments/index.spec.ts +0 -145
  282. package/src/checks/unrecognized-content-for-arguments/index.ts +0 -55
  283. package/src/checks/valid-block-target/index.spec.ts +0 -1396
  284. package/src/checks/valid-block-target/index.ts +0 -142
  285. package/src/checks/valid-content-for-argument-types/index.spec.ts +0 -382
  286. package/src/checks/valid-content-for-argument-types/index.ts +0 -42
  287. package/src/checks/valid-content-for-arguments/index.spec.ts +0 -107
  288. package/src/checks/valid-content-for-arguments/index.ts +0 -98
  289. package/src/checks/valid-local-blocks/index.spec.ts +0 -286
  290. package/src/checks/valid-local-blocks/index.ts +0 -100
  291. package/src/checks/valid-local-blocks/valid-block-utils.ts +0 -97
  292. package/src/checks/valid-schema/index.spec.ts +0 -174
  293. package/src/checks/valid-schema/index.ts +0 -41
  294. package/src/checks/valid-schema-name/index.spec.ts +0 -112
  295. package/src/checks/valid-schema-name/index.ts +0 -75
  296. package/src/checks/valid-settings-key/index.spec.ts +0 -321
  297. package/src/checks/valid-settings-key/index.ts +0 -144
  298. package/src/checks/valid-static-block-type/index.spec.ts +0 -38
  299. package/src/checks/valid-static-block-type/index.ts +0 -58
  300. package/src/checks/valid-visible-if/index.spec.ts +0 -619
  301. package/src/checks/valid-visible-if/index.ts +0 -184
  302. package/src/checks/valid-visible-if/visible-if-utils.ts +0 -158
  303. package/src/tags/content-for.ts +0 -25
  304. package/src/to-schema.ts +0 -231
  305. package/src/types/schemas/section.ts +0 -86
  306. package/src/types/schemas/theme-block.ts +0 -34
  307. package/src/types/theme-schemas.ts +0 -80
  308. package/src/utils/block.ts +0 -300
  309. 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
- };