Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/theme/src/cli/services/package.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ describe('packageTheme', () => {
const inputDirectory = joinPath(tmpDir, 'theme')
await mkdir(inputDirectory)
const themeRelativePaths = [
'AGENTS.md',
Comment thread
karreiro marked this conversation as resolved.
'assets/base.css',
'layout/theme.liquid',
'config/settings_schema.json',
'config/styles.css',
'listings/canine-gourmand/sections/header-group.json',
'listings/dawn/templates/index.json',
'release-notes.md',
Expand Down
1 change: 1 addition & 0 deletions packages/theme/src/cli/services/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {resolvePath, relativizePath} from '@shopify/cli-kit/node/path'
import {parseJSON} from '@shopify/theme-check-node'

const themeFilesPattern = [
'AGENTS.md',
'assets/**',
'blocks/**',
'config/**',
Expand Down
3 changes: 3 additions & 0 deletions packages/theme/src/cli/utilities/fixtures/theme/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Theme instructions

Keep the theme accessible.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:root {
--color-primary: #000;
}
19 changes: 16 additions & 3 deletions packages/theme/src/cli/utilities/theme-fs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,18 @@ describe('theme-fs', () => {

// Then
expect(themeFileSystem.root).toBe(root)
expect(themeFileSystem.files.size).toBe(10)
expect(themeFileSystem.files.size).toBe(12)
expect(themeFileSystem.unsyncedFileKeys).toEqual(new Set())
expect(themeFileSystem.uploadErrors).toEqual(new Map())

// Check that all expected files are present with correct checksums
const expectedFiles = [
{checksum: '6e3520cc5a5c4cdb1267f36406c732a1', key: 'AGENTS.md'},
{checksum: 'b7fbe0ecff2a6c1d6e697a13096e2b17', key: 'assets/base.css'},
{checksum: '7adcd48a3cc215a81fabd9dafb919507', key: 'assets/sparkle.gif'},
{checksum: '22e69af13b7953914563c60035a831bc', key: 'config/settings_data.json'},
{checksum: 'cbe979d3fd3b7cdf2041ada9fdb3af57', key: 'config/settings_schema.json'},
{checksum: '98fb75d10c4dbf239997ae494581fd7d', key: 'config/styles.css'},
{checksum: '7a92d18f1f58b2396c46f98f9e502c6a', key: 'layout/password.liquid'},
{checksum: '2374357fdadd3b4636405e80e21e87fc', key: 'layout/theme.liquid'},
{checksum: '0b2f0aa705a4eb2b4740e2ed68bc043f', key: 'locales/en.default.json'},
Expand Down Expand Up @@ -137,7 +139,7 @@ describe('theme-fs', () => {
// Given
const root = tmpDir
await copyDirectoryContents(joinPath(locationOfThisFile, 'fixtures/theme'), root)
const watchSpy = vi.spyOn(chokidar, 'watch')
const watchSpy = vi.spyOn(chokidar, 'watch').mockReturnValue(new EventEmitter() as any)

// When
const themeFileSystem = mountThemeFileSystem(root, {listing: 'modern'})
Expand All @@ -157,7 +159,7 @@ describe('theme-fs', () => {
// Given
const root = tmpDir
await copyDirectoryContents(joinPath(locationOfThisFile, 'fixtures/theme'), root)
const watchSpy = vi.spyOn(chokidar, 'watch')
const watchSpy = vi.spyOn(chokidar, 'watch').mockReturnValue(new EventEmitter() as any)

// When
const themeFileSystem = mountThemeFileSystem(root)
Expand Down Expand Up @@ -511,11 +513,13 @@ describe('theme-fs', () => {
{key: 'templates/404.json', checksum: '7'},
{key: 'config/settings_schema.json', checksum: '8'},
{key: 'config/settings_data.json', checksum: '9'},
{key: 'config/styles.css', checksum: '16'},
{key: 'sections/announcement-bar.liquid', checksum: '10'},
{key: 'snippets/language-localization.liquid', checksum: '11'},
{key: 'templates/404.context.uk.json', checksum: '12'},
{key: 'templates/404.liquid', checksum: '13'},
{key: 'blocks/block.liquid', checksum: '14'},
{key: 'AGENTS.md', checksum: '17'},
]
// When
const {
Expand All @@ -525,10 +529,12 @@ describe('theme-fs', () => {
otherJsonFiles,
configSchemaFile,
configDataFile,
configStylesheetFiles,
staticAssetFiles,
contextualizedJsonFiles,
blockLiquidFiles,
layoutFiles,
agentInstructionFiles,
} = partitionThemeFiles(files)

// Then
Expand All @@ -542,6 +548,7 @@ describe('theme-fs', () => {
expect(templateJsonFiles).toEqual([{key: 'templates/404.json', checksum: '7'}])
expect(configSchemaFile).toEqual([{key: 'config/settings_schema.json', checksum: '8'}])
expect(configDataFile).toEqual([{key: 'config/settings_data.json', checksum: '9'}])
expect(configStylesheetFiles).toEqual([{key: 'config/styles.css', checksum: '16'}])
expect(staticAssetFiles).toEqual([
{key: 'assets/base.css', checksum: '1'},
{key: 'assets/sparkle.gif', checksum: '3'},
Expand All @@ -553,6 +560,7 @@ describe('theme-fs', () => {
{key: 'layout/theme.liquid', checksum: '5'},
{key: 'layout/custom.liquid', checksum: '15'},
])
expect(agentInstructionFiles).toEqual([{key: 'AGENTS.md', checksum: '17'}])
})

test('should handle empty file array', () => {
Expand All @@ -567,7 +575,9 @@ describe('theme-fs', () => {
otherJsonFiles,
configSchemaFile,
configDataFile,
configStylesheetFiles,
staticAssetFiles,
agentInstructionFiles,
} = partitionThemeFiles(files)

// Then
Expand All @@ -577,7 +587,9 @@ describe('theme-fs', () => {
expect(otherJsonFiles).toEqual([])
expect(configSchemaFile).toEqual([])
expect(configDataFile).toEqual([])
expect(configStylesheetFiles).toEqual([])
expect(staticAssetFiles).toEqual([])
expect(agentInstructionFiles).toEqual([])
})
})

Expand All @@ -590,6 +602,7 @@ describe('theme-fs', () => {
expect(isTextFile('assets/icon.svg')).toBeTruthy()
expect(isTextFile('sections/template.liquid')).toBeTruthy()
expect(isTextFile('templates/cart.json')).toBeTruthy()
expect(isTextFile('AGENTS.md')).toBeTruthy()
})

test(`returns false when it's not a text file`, async () => {
Expand Down
15 changes: 14 additions & 1 deletion packages/theme/src/cli/utilities/theme-fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ import type {
const FILE_EVENT_DEBOUNCE_TIME_IN_MS = 250

const THEME_DIRECTORY_PATTERNS = [
'AGENTS.md',
'assets/**/*.*',
'config/**/*.json',
'config/styles.css',
'layout/**/*.liquid',
'locales/**/*.json',
'sections/**/*.{liquid,json}',
Expand All @@ -41,11 +43,13 @@ const THEME_DIRECTORY_PATTERNS = [
]

const THEME_PARTITION_REGEX = {
agentInstructionsRegex: /^AGENTS\.md$/,
layoutLiquidRegex: /^layout\/.+\.liquid$/,
sectionLiquidRegex: /^sections\/.+\.liquid$/,
blockLiquidRegex: /^blocks\/.+\.liquid$/,
configSchemaRegex: /^config\/settings_schema\.json$/,
configDataRegex: /^config\/settings_data\.json$/,
configStylesheetRegex: /^config\/styles\.css$/,
sectionJsonRegex: /^sections\/.+\.json$/,
templateJsonRegex: /^templates\/.+\.json$/,
jsonRegex: /^(?!config\/).*\.json$/,
Expand Down Expand Up @@ -468,13 +472,17 @@ export function partitionThemeFiles<T extends {key: string}>(files: T[]) {
const contextualizedJsonFiles: T[] = []
const configSchemaFile: T[] = []
const configDataFile: T[] = []
const configStylesheetFiles: T[] = []
const staticAssetFiles: T[] = []
const blockLiquidFiles: T[] = []
const layoutFiles: T[] = []
const agentInstructionFiles: T[] = []

files.forEach((file) => {
const fileKey = file.key
if (fileKey.endsWith('.liquid')) {
if (THEME_PARTITION_REGEX.agentInstructionsRegex.test(fileKey)) {
agentInstructionFiles.push(file)
} else if (fileKey.endsWith('.liquid')) {
if (THEME_PARTITION_REGEX.sectionLiquidRegex.test(fileKey)) {
sectionLiquidFiles.push(file)
} else if (THEME_PARTITION_REGEX.blockLiquidRegex.test(fileKey)) {
Expand All @@ -488,6 +496,8 @@ export function partitionThemeFiles<T extends {key: string}>(files: T[]) {
configSchemaFile.push(file)
} else if (THEME_PARTITION_REGEX.configDataRegex.test(fileKey)) {
configDataFile.push(file)
} else if (THEME_PARTITION_REGEX.configStylesheetRegex.test(fileKey)) {
configStylesheetFiles.push(file)
} else if (THEME_PARTITION_REGEX.jsonRegex.test(fileKey)) {
if (THEME_PARTITION_REGEX.contextualizedJsonRegex.test(fileKey)) {
contextualizedJsonFiles.push(file)
Expand All @@ -512,9 +522,11 @@ export function partitionThemeFiles<T extends {key: string}>(files: T[]) {
otherJsonFiles,
configSchemaFile,
configDataFile,
configStylesheetFiles,
staticAssetFiles,
blockLiquidFiles,
layoutFiles,
agentInstructionFiles,
}
}

Expand All @@ -533,6 +545,7 @@ export function isTextFile(path: string) {
'text/x-sass',
'text/x-scss',
'image/svg+xml',
'text/markdown',
]

return textFileTypes.includes(lookupMimeType(path))
Expand Down
14 changes: 14 additions & 0 deletions packages/theme/src/cli/utilities/theme-uploader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ describe('theme-uploader', () => {
{key: 'templates/index.liquid', checksum: '4'},
{key: 'assets/liquid.liquid', checksum: '5'},
{key: 'config/settings_data.json', checksum: '6'},
{key: 'config/styles.css', checksum: '9'},
{key: 'AGENTS.md', checksum: '10'},
{key: 'assets/image.png', checksum: '7'},
{key: 'layout/custom.liquid', checksum: '8'},
]
Expand Down Expand Up @@ -282,6 +284,8 @@ describe('theme-uploader', () => {
'templates/index.liquid',
'assets/liquid.liquid',
'config/settings_data.json',
'config/styles.css',
'AGENTS.md',
'assets/image.png',
],
adminSession,
Expand All @@ -305,6 +309,8 @@ describe('theme-uploader', () => {
['templates/product.context.uk.json', {key: 'templates/product.context.uk.json', checksum: '8'}],
['blocks/block.liquid', {key: 'blocks/block.liquid', checksum: '9'}],
['layout/theme.liquid', {key: 'layout/theme.liquid', checksum: '10'}],
['config/styles.css', {key: 'config/styles.css', checksum: '11', value: ':root { --color-primary: #000; }'}],
['AGENTS.md', {key: 'AGENTS.md', checksum: '12', value: '# Theme instructions'}],
]),
)

Expand Down Expand Up @@ -345,6 +351,14 @@ describe('theme-uploader', () => {
{
key: 'assets/image.png',
},
{
key: 'config/styles.css',
value: ':root { --color-primary: #000; }',
},
{
key: 'AGENTS.md',
value: '# Theme instructions',
},
],
adminSession,
)
Expand Down
14 changes: 12 additions & 2 deletions packages/theme/src/cli/utilities/theme-uploader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ function getRemoteFilesToBeDeleted(remoteChecksums: Checksum[], themeFileSystem:
return filesToBeDeleted
}

// Contextual Json Files -> Json Files -> Liquid Files -> Config Files -> Static Asset Files
// Contextual JSON files -> JSON files -> Liquid files -> Config files -> Other independent files
function orderFilesToBeDeleted(files: Checksum[]): Checksum[] {
const fileSets = partitionThemeFiles(files)
return [
Expand All @@ -214,6 +214,8 @@ function orderFilesToBeDeleted(files: Checksum[]): Checksum[] {
...fileSets.layoutFiles,
...fileSets.otherLiquidFiles,
...fileSets.configDataFile,
...fileSets.configStylesheetFiles,
...fileSets.agentInstructionFiles,
...fileSets.configSchemaFile,
...fileSets.staticAssetFiles,
]
Expand Down Expand Up @@ -334,6 +336,8 @@ function selectUploadableFiles(themeFileSystem: ThemeFileSystem, remoteChecksums
* - The other Liquid files (for example, snippets, and liquid templates)
* - The other JSON files (for example, locales)
* - The static assets
* - Config stylesheets
* - Agent instructions
*
*/
function orderFilesToBeUploaded(files: ChecksumWithSize[]): {
Expand All @@ -344,7 +348,13 @@ function orderFilesToBeUploaded(files: ChecksumWithSize[]): {
return {
// Most JSON files here are locales. Since we filter locales out in `replaceTemplates`,
// and assets can be served locally, we can give priority to the unique Liquid files:
independentFiles: [fileSets.otherLiquidFiles, fileSets.otherJsonFiles, fileSets.staticAssetFiles],
independentFiles: [
fileSets.otherLiquidFiles,
fileSets.otherJsonFiles,
fileSets.staticAssetFiles,
fileSets.configStylesheetFiles,
fileSets.agentInstructionFiles,
],
// Follow order of dependencies:
dependentFiles: [
fileSets.configSchemaFile,
Expand Down
Loading