@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,435 +0,0 @@
1
- import { expect, describe, it } from 'vitest';
2
- import { JSONMissingBlock } from './index';
3
- import { check, MockTheme } from '../../test';
4
-
5
- describe('Module: JsonMissingBlock', () => {
6
- describe('File existence validation', () => {
7
- it('should report an offense when a block does not exist', async () => {
8
- const theme: MockTheme = {
9
- 'templates/product.failing.json': `{
10
- "sections": {
11
- "custom-section": {
12
- "type": "custom-section",
13
- "blocks": {
14
- "text_tqQTNE": {
15
- "type": "missing_block"
16
- }
17
- },
18
- "block_order": ["text_tqQTNE"]
19
- }
20
- },
21
- "order": ["custom-section"]
22
- }`,
23
- 'sections/custom-section.liquid': `
24
- {% schema %}
25
- {
26
- "name": "Custom Section",
27
- "blocks": [
28
- {
29
- "type": "missing_block"
30
- }
31
- ]
32
- }
33
- {% endschema %}
34
- `,
35
- };
36
-
37
- const offenses = await check(theme, [JSONMissingBlock]);
38
- expect(offenses).to.have.length(1);
39
- expect(offenses[0].message).to.equal(
40
- "Theme block 'blocks/missing_block.liquid' does not exist.",
41
- );
42
-
43
- const content = theme['templates/product.failing.json'];
44
- const erroredContent = content.slice(offenses[0].start.index, offenses[0].end.index);
45
- expect(erroredContent).to.equal('"missing_block"');
46
- });
47
-
48
- it('should not report an offense when block exists', async () => {
49
- const theme: MockTheme = {
50
- 'templates/product.valid.json': `{
51
- "sections": {
52
- "custom-section": {
53
- "type": "custom-section",
54
- "blocks": {
55
- "text_block": {
56
- "type": "text"
57
- }
58
- },
59
- "block_order": ["text_block"]
60
- }
61
- },
62
- "order": ["custom-section"]
63
- }`,
64
- 'sections/custom-section.liquid': `
65
- {% schema %}
66
- {
67
- "name": "Custom Section",
68
- "blocks": [
69
- {
70
- "type": "text"
71
- }
72
- ]
73
- }
74
- {% endschema %}
75
- `,
76
- 'blocks/text.liquid': '',
77
- };
78
-
79
- const offenses = await check(theme, [JSONMissingBlock]);
80
- expect(offenses).to.be.empty;
81
- });
82
-
83
- it('should report an offense when a nested block does not exist', async () => {
84
- const theme: MockTheme = {
85
- 'templates/product.nested.json': `{
86
- "sections": {
87
- "custom-section": {
88
- "type": "custom-section",
89
- "blocks": {
90
- "parent_block": {
91
- "type": "text",
92
- "blocks": {
93
- "child_block": {
94
- "type": "missing_nested"
95
- }
96
- }
97
- }
98
- },
99
- "block_order": ["parent_block"]
100
- }
101
- },
102
- "order": ["custom-section"]
103
- }`,
104
- 'sections/custom-section.liquid': `
105
- {% schema %}
106
- {
107
- "name": "Custom Section",
108
- "blocks": [
109
- {
110
- "type": "text"
111
- }
112
- ]
113
- }
114
- {% endschema %}
115
- `,
116
- 'blocks/text.liquid': `
117
- {% schema %}
118
- {
119
- "name": "Text Block",
120
- "blocks": [
121
- {
122
- "type": "missing_nested"
123
- }
124
- ]
125
- }
126
- {% endschema %}
127
- `,
128
- };
129
-
130
- const offenses = await check(theme, [JSONMissingBlock]);
131
- expect(offenses).to.have.length(1);
132
- expect(offenses[0].message).to.equal(
133
- "Theme block 'blocks/missing_nested.liquid' does not exist.",
134
- );
135
-
136
- const content = theme['templates/product.nested.json'];
137
- const erroredContent = content.slice(offenses[0].start.index, offenses[0].end.index);
138
- expect(erroredContent).to.equal('"missing_nested"');
139
- });
140
- });
141
-
142
- describe('Allowed block type validation', () => {
143
- it('should report an offense when block exists but is not in the section liquid schema', async () => {
144
- const theme: MockTheme = {
145
- 'templates/product.valid.json': `{
146
- "sections": {
147
- "custom-section": {
148
- "type": "custom-section",
149
- "blocks": {
150
- "text_block": {
151
- "type": "text"
152
- }
153
- },
154
- "block_order": ["text_block"]
155
- }
156
- },
157
- "order": ["custom-section"]
158
- }`,
159
- 'sections/custom-section.liquid': `
160
- {% schema %}
161
- {
162
- "name": "Custom Section",
163
- "blocks": [
164
- {
165
- "type": "image"
166
- }
167
- ]
168
- }
169
- {% endschema %}
170
- `,
171
- 'blocks/text.liquid': '',
172
- 'blocks/image.liquid': '',
173
- };
174
-
175
- const offenses = await check(theme, [JSONMissingBlock]);
176
- expect(offenses).to.have.length(1);
177
- expect(offenses[0].message).to.equal(
178
- "Block type 'text' is not allowed in 'sections/custom-section.liquid'.",
179
- );
180
-
181
- const content = theme['templates/product.valid.json'];
182
- const erroredContent = content.slice(offenses[0].start.index, offenses[0].end.index);
183
- expect(erroredContent).to.equal('"text"');
184
- });
185
-
186
- it('should report an offense when a nested block exists but is not in the block liquid schema', async () => {
187
- const theme: MockTheme = {
188
- 'templates/product.nested.json': `{
189
- "sections": {
190
- "custom-section": {
191
- "type": "custom-section",
192
- "blocks": {
193
- "parent_block": {
194
- "type": "text",
195
- "blocks": {
196
- "child_block": {
197
- "type": "missing_nested"
198
- }
199
- }
200
- }
201
- },
202
- "block_order": ["parent_block"]
203
- }
204
- },
205
- "order": ["custom-section"]
206
- }`,
207
- 'sections/custom-section.liquid': `
208
- {% schema %}
209
- {
210
- "name": "Custom Section",
211
- "blocks": [
212
- {
213
- "type": "text"
214
- }
215
- ]
216
- }
217
- {% endschema %}
218
- `,
219
- 'blocks/text.liquid': `
220
- {% schema %}
221
- {
222
- "name": "Text Block",
223
- "blocks": [
224
- {
225
- "type": "image"
226
- }
227
- ]
228
- }
229
- {% endschema %}
230
- `,
231
- 'blocks/image.liquid': '',
232
- 'blocks/missing_nested.liquid': '',
233
- };
234
-
235
- const offenses = await check(theme, [JSONMissingBlock]);
236
- expect(offenses).to.have.length(1);
237
- expect(offenses[0].message).to.equal(
238
- "Block type 'missing_nested' is not allowed in 'blocks/text.liquid'.",
239
- );
240
-
241
- const content = theme['templates/product.nested.json'];
242
- const erroredContent = content.slice(offenses[0].start.index, offenses[0].end.index);
243
- expect(erroredContent).to.equal('"missing_nested"');
244
- });
245
-
246
- it('should report an offense when a nested private block exists but is not in the block liquid schema', async () => {
247
- const theme: MockTheme = {
248
- 'templates/product.nested.json': `{
249
- "sections": {
250
- "custom-section": {
251
- "type": "custom-section",
252
- "blocks": {
253
- "parent_block": {
254
- "type": "text",
255
- "blocks": {
256
- "child_block": {
257
- "type": "_private_block"
258
- }
259
- }
260
- }
261
- },
262
- "block_order": ["parent_block"]
263
- }
264
- },
265
- "order": ["custom-section"]
266
- }`,
267
- 'sections/custom-section.liquid': `
268
- {% schema %}
269
- {
270
- "name": "Custom Section",
271
- "blocks": [
272
- {
273
- "type": "text"
274
- }
275
- ]
276
- }
277
- {% endschema %}
278
- `,
279
- 'blocks/text.liquid': `
280
- {% schema %}
281
- {
282
- "name": "Text Block",
283
- "blocks": [
284
- {
285
- "type": "@theme"
286
- }
287
- ]
288
- }
289
- {% endschema %}
290
- `,
291
- 'blocks/image.liquid': '',
292
- 'blocks/_private_block.liquid': '',
293
- };
294
-
295
- const offenses = await check(theme, [JSONMissingBlock]);
296
- expect(offenses).to.have.length(1);
297
- expect(offenses[0].message).to.equal(
298
- "Block type '_private_block' is not allowed in 'blocks/text.liquid'.",
299
- );
300
-
301
- const content = theme['templates/product.nested.json'];
302
- const erroredContent = content.slice(offenses[0].start.index, offenses[0].end.index);
303
- expect(erroredContent).to.equal('"_private_block"');
304
- });
305
-
306
- it('should not report an offense when a static block exists and is not in the block liquid schema', async () => {
307
- const theme: MockTheme = {
308
- 'templates/product.static.json': `{
309
- "sections": {
310
- "custom-section": {
311
- "type": "custom-section",
312
- "blocks": {
313
- "child_block": {
314
- "type": "text"
315
- },
316
- "static_block": {
317
- "type": "static_block",
318
- "static": true
319
- }
320
- },
321
- "block_order": ["child_block"]
322
- }
323
- },
324
- "order": ["custom-section"]
325
- }`,
326
- 'sections/custom-section.liquid': `
327
- {% schema %}
328
- {
329
- "name": "Custom Section",
330
- "blocks": [
331
- {
332
- "type": "text"
333
- }
334
- ]
335
- }
336
- {% endschema %}
337
- `,
338
- 'blocks/text.liquid': `
339
- {% schema %}
340
- {
341
- "name": "Text Block",
342
- "blocks": [
343
- {
344
- "type": "@theme"
345
- }
346
- ]
347
- }
348
- {% endschema %}
349
- `,
350
- 'blocks/static_block.liquid': `
351
- {% schema %}
352
- {
353
- "name": "Static Block",
354
- }
355
- {% endschema %}
356
- `,
357
- };
358
-
359
- const offenses = await check(theme, [JSONMissingBlock]);
360
- expect(offenses).to.have.length(0);
361
- });
362
- });
363
-
364
- describe('Edge case validation', () => {
365
- it('should ignore non-template JSON files', async () => {
366
- const theme: MockTheme = {
367
- 'config/index.json': `{
368
- "blocks": {
369
- "text_block": {
370
- "type": "nonexistent"
371
- }
372
- }
373
- }`,
374
- };
375
-
376
- const offenses = await check(theme, [JSONMissingBlock]);
377
- expect(offenses).to.be.empty;
378
- });
379
-
380
- it('should ignore templates with local blocks', async () => {
381
- const theme: MockTheme = {
382
- 'templates/product.nested.json': `{
383
- "sections": {
384
- "custom-section": {
385
- "type": "custom-section",
386
- "blocks": {
387
- "parent_block": {
388
- "type": "text",
389
- "blocks": {
390
- "child_block": {
391
- "type": "_private_block"
392
- }
393
- }
394
- }
395
- },
396
- "block_order": ["parent_block"]
397
- }
398
- },
399
- "order": ["custom-section"]
400
- }`,
401
- 'sections/custom-section.liquid': `
402
- {% schema %}
403
- {
404
- "name": "Custom Section",
405
- "blocks": [
406
- {
407
- "type": "text",
408
- "name": "Text Block"
409
- }
410
- ]
411
- }
412
- {% endschema %}
413
- `,
414
- 'blocks/text.liquid': `
415
- {% schema %}
416
- {
417
- "name": "Text Block",
418
- "blocks": [
419
- {
420
- "type": "image",
421
- "name": "Image Block"
422
- }
423
- ]
424
- }
425
- {% endschema %}
426
- `,
427
- 'blocks/image.liquid': '',
428
- 'blocks/_private_block.liquid': '',
429
- };
430
-
431
- const offenses = await check(theme, [JSONMissingBlock]);
432
- expect(offenses).to.be.empty;
433
- });
434
- });
435
- });
@@ -1,56 +0,0 @@
1
- import { getSchemaFromJSON } from '../../to-schema';
2
- import { JSONCheckDefinition, Severity, SourceCodeType } from '../../types';
3
- import { getAllBlocks, isPropertyNode } from './missing-block-utils';
4
-
5
- export const JSONMissingBlock: JSONCheckDefinition = {
6
- meta: {
7
- code: 'JSONMissingBlock',
8
- name: 'Check for missing blocks types in JSON templates',
9
- docs: {
10
- description: 'This check ensures that JSON templates contain valid block types.',
11
- recommended: true,
12
- url: 'https://shopify.dev/docs/storefronts/themes/tools/theme-check/checks/json-missing-block',
13
- },
14
- type: SourceCodeType.JSON,
15
- severity: Severity.ERROR,
16
- schema: {},
17
- targets: [],
18
- },
19
-
20
- create(context) {
21
- const relativePath = context.toRelativePath(context.file.uri);
22
- if (!relativePath.startsWith('templates/')) return {};
23
-
24
- return {
25
- async onCodePathEnd() {
26
- const schema = await getSchemaFromJSON(context);
27
- const { ast } = schema ?? {};
28
- if (!ast || ast instanceof Error) return;
29
- if (!schema) return;
30
-
31
- const sections = schema.parsed.sections;
32
- if (!sections) return;
33
-
34
- await Promise.all(
35
- Object.entries(sections).map(async ([sectionKey, section]) => {
36
- if (
37
- isPropertyNode(section) &&
38
- 'blocks' in section &&
39
- isPropertyNode(section.blocks) &&
40
- 'type' in section
41
- ) {
42
- await getAllBlocks(
43
- ast,
44
- 0,
45
- section.type,
46
- section.blocks,
47
- ['sections', sectionKey, 'blocks'],
48
- context,
49
- );
50
- }
51
- }),
52
- );
53
- },
54
- };
55
- },
56
- };
@@ -1,147 +0,0 @@
1
- import { Context, SourceCodeType, JSONNode } from '../../types';
2
- import { PropertyNode } from '../../jsonc/types';
3
- import { getLocEnd, getLocStart, nodeAtPath } from '../../json';
4
- import { doesFileExist } from '../../utils/file-utils';
5
-
6
- export function isPropertyNode(node: unknown): node is PropertyNode {
7
- return typeof node === 'object' && node !== null;
8
- }
9
-
10
- function isNestedBlock(currentPath: string[]): boolean {
11
- return currentPath.filter((segment) => segment === 'blocks').length > 1;
12
- }
13
-
14
- function reportWarning(
15
- message: string,
16
- offset: number,
17
- astNode: JSONNode,
18
- context: Context<SourceCodeType.JSON>,
19
- ) {
20
- context.report({
21
- message,
22
- startIndex: offset + getLocStart(astNode),
23
- endIndex: offset + getLocEnd(astNode),
24
- });
25
- }
26
-
27
- async function validateBlockFileExistence(
28
- blockType: string,
29
- context: Context<SourceCodeType.JSON>,
30
- ): Promise<boolean> {
31
- if (blockType === '@theme' || blockType === '@app') {
32
- return true;
33
- }
34
- const blockPath = `blocks/${blockType}.liquid`;
35
- return await doesFileExist(context, blockPath);
36
- }
37
-
38
- async function getThemeBlocks(
39
- sectionType: string,
40
- currentPath: string[],
41
- context: Context<SourceCodeType.JSON>,
42
- ): Promise<string[]> {
43
- const themeBlocks: string[] = [];
44
- if (!sectionType) return themeBlocks;
45
-
46
- const schema = isNestedBlock(currentPath)
47
- ? await context.getBlockSchema?.(sectionType)
48
- : await context.getSectionSchema?.(sectionType);
49
- if (!schema || schema instanceof Error) return themeBlocks;
50
-
51
- const { validSchema } = schema;
52
- if (!validSchema || validSchema instanceof Error) return themeBlocks;
53
-
54
- if (Array.isArray(validSchema.blocks)) {
55
- validSchema.blocks.forEach((block) => {
56
- if (!('name' in block) && block.type !== '@app') {
57
- themeBlocks.push(block.type);
58
- }
59
- });
60
- }
61
- return themeBlocks;
62
- }
63
-
64
- async function validateBlock(
65
- blockType: string,
66
- blockStatic: boolean,
67
- blockPath: JSONNode,
68
- ancestorType: string,
69
- currentPath: string[],
70
- offset: number,
71
- context: Context<SourceCodeType.JSON>,
72
- ) {
73
- const themeBlocks = await getThemeBlocks(ancestorType, currentPath, context);
74
- if (themeBlocks.length === 0) return;
75
-
76
- const exists = await validateBlockFileExistence(blockType, context);
77
- if (!exists) {
78
- reportWarning(
79
- `Theme block 'blocks/${blockType}.liquid' does not exist.`,
80
- offset,
81
- blockPath,
82
- context,
83
- );
84
- } else if (blockStatic) {
85
- // Static blocks are not required to be in the schema blocks array
86
- return;
87
- } else {
88
- const isPrivateBlock = blockType.startsWith('_');
89
- const schemaIncludesAtTheme = themeBlocks.includes('@theme');
90
- const schemaIncludesBlockType = themeBlocks.includes(blockType);
91
-
92
- if (
93
- !isPrivateBlock ? schemaIncludesBlockType || schemaIncludesAtTheme : schemaIncludesBlockType
94
- ) {
95
- return;
96
- } else {
97
- const location = isNestedBlock(currentPath) ? 'blocks' : 'sections';
98
- reportWarning(
99
- `Block type '${blockType}' is not allowed in '${location}/${ancestorType}.liquid'.`,
100
- offset,
101
- blockPath,
102
- context,
103
- );
104
- }
105
- }
106
- }
107
-
108
- export async function getAllBlocks(
109
- ast: JSONNode,
110
- offset: number,
111
- ancestorType: string,
112
- blocks: PropertyNode,
113
- currentPath: string[],
114
- context: Context<SourceCodeType.JSON>,
115
- ): Promise<void> {
116
- await Promise.all(
117
- Object.entries(blocks).map(async ([blockKey, block]) => {
118
- if (block.type) {
119
- const typePath = currentPath.concat(blockKey, 'type');
120
- const blockPath = nodeAtPath(ast, typePath)! as JSONNode;
121
-
122
- if (blockPath) {
123
- await validateBlock(
124
- block.type,
125
- block.static,
126
- blockPath,
127
- ancestorType,
128
- currentPath,
129
- offset,
130
- context,
131
- );
132
- }
133
- }
134
-
135
- if ('blocks' in block) {
136
- await getAllBlocks(
137
- ast,
138
- offset,
139
- block.type,
140
- block.blocks,
141
- currentPath.concat(blockKey, 'blocks'),
142
- context,
143
- );
144
- }
145
- }),
146
- );
147
- }