PluginProbe
Code Snippets / 4.0.0-beta.3
Code Snippets v4.0.0-beta.3
4.0.0-beta.3 4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 All 66 releases
code-snippets / js / utils / files.ts

files.ts in Code Snippets 4.0.0-beta.3, at js/utils/files.ts

142 lines 4.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { TIMEOUTS } from '../../../tests/e2e/helpers/constants'
2 import { getSnippetType } from './snippets/snippets'
3 import type { SnippetsExport } from '../types/schema/SnippetsExport'
4 import type { Snippet } from '../types/Snippet'
5
6 const JSON_INDENT_SPACES = 2
7 const EXPORT_FILENAME = 'snippets'
8 const EXPORT_GENERATOR = 'Code Snippets'
9 const DEFAULT_PRIORITY = 10
10 const EXPORT_DATE_LENGTH = 16
11
12 const MIME_INFO = <const> {
13 php: ['php', 'text/php'],
14 html: ['php', 'text/php'],
15 css: ['css', 'text/css'],
16 js: ['js', 'text/javascript'],
17 cond: ['json', 'application/json'],
18 json: ['json', 'application/json']
19 }
20
21 export const downloadAsFile = (content: BlobPart, filename: string, type: string) => {
22 const link = document.createElement('a')
23 link.download = filename
24 link.href = URL.createObjectURL(new Blob([content], { type }))
25
26 setTimeout(() => URL.revokeObjectURL(link.href), TIMEOUTS.DEFAULT)
27
28 // Some browsers (notably headless Chromium) can ignore programmatic clicks on detached anchors.
29 // Appending the link to the DOM before clicking improves reliability.
30 link.style.display = 'none'
31 document.body.appendChild(link)
32
33 setTimeout(() => {
34 link.click()
35 link.remove()
36 }, 0)
37 }
38
39 export const downloadSnippetExportFile = (
40 content: SnippetsExport | string,
41 { id, name, scope }: Snippet,
42 type?: keyof typeof MIME_INFO
43 ) => {
44 const sanitizedName = name.toLowerCase().replace(/[^\w-]+/g, '-').trim()
45 const title = '' === sanitizedName ? `snippet-${id}` : sanitizedName
46
47 if ('string' === typeof content) {
48 const [ext, mimeType] = MIME_INFO[type ?? getSnippetType({ scope })]
49 const filename = `${title}.code-snippets.${ext}`
50 downloadAsFile(content, filename, mimeType)
51 } else {
52 const filename = `${title}.code-snippets.json`
53 downloadAsFile(JSON.stringify(content, undefined, JSON_INDENT_SPACES), filename, 'application/json')
54 }
55 }
56
57 type DefaultExportValueCheck = (value: unknown) => boolean
58
59 const isNullish = (value: unknown): value is undefined | null => undefined === value || null === value
60
61 const DEFAULT_EXPORT_VALUE_CHECKS: Record<string, DefaultExportValueCheck> = {
62 id: value => 0 === value,
63 desc: value => '' === value,
64 name: value => '' === value,
65 code: value => '' === value,
66 tags: value => Array.isArray(value) && 0 === value.length,
67 scope: value => 'global' === value,
68 condition_id: value => 0 === value,
69 active: value => false === value,
70 locked: value => false === value,
71 trashed: value => false === value,
72 priority: value => DEFAULT_PRIORITY === value,
73 modified: value => '' === value || isNullish(value),
74 last_active: value => 0 === value || isNullish(value),
75 network: value => null === value || false === value,
76 shared_network: value => null === value || false === value,
77 code_error: value => null === value || false === value,
78 code_error_trace: value => null === value || false === value
79 }
80
81 const isDefaultExportValue = (field: string, value: unknown): boolean =>
82 (DEFAULT_EXPORT_VALUE_CHECKS[field] ?? isNullish)(value)
83
84 const buildExportSnippet = ({
85 id,
86 name,
87 desc,
88 code,
89 tags,
90 scope,
91 active,
92 locked,
93 trashed,
94 network,
95 shared_network,
96 modified,
97 priority,
98 conditionId,
99 lastActive,
100 code_error,
101 code_error_trace
102 }: Snippet): SnippetsExport['snippets'][number] =>
103 Object.fromEntries(
104 Object.entries({
105 id,
106 name,
107 desc,
108 code,
109 tags,
110 scope,
111 active,
112 locked,
113 trashed,
114 network,
115 shared_network,
116 modified,
117 priority,
118 condition_id: conditionId,
119 last_active: lastActive,
120 code_error,
121 code_error_trace
122 }).filter(([field, value]) => !isDefaultExportValue(field, value))
123 )
124
125 export const downloadBulkSnippetExportFile = (snippets: readonly Snippet[]) => {
126 if (0 === snippets.length) {
127 return
128 }
129
130 const content: SnippetsExport = {
131 generator: EXPORT_GENERATOR,
132 date_created: new Date().toISOString().slice(0, EXPORT_DATE_LENGTH).replace('T', ' '),
133 snippets: snippets.map(buildExportSnippet)
134 }
135
136 downloadAsFile(
137 JSON.stringify(content, undefined, JSON_INDENT_SPACES),
138 `${EXPORT_FILENAME}.code-snippets.json`,
139 'application/json'
140 )
141 }
142