betterstart-cli 0.0.104 → 0.0.105

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 (140) hide show
  1. package/dist/cli.js +6416 -5203
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +1 -1
  4. package/dist/assets/adapters/next/templates/renderers/commands/init/banner-art.ts +0 -7
  5. package/dist/assets/adapters/next/templates/renderers/commands/init/verify-database-reachable.ts +0 -30
  6. package/dist/assets/adapters/next/templates/renderers/commands/seed/build-seed-script.ts +0 -171
  7. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-authorship-alias-block.ts +0 -4
  8. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-authorship-data-fields.ts +0 -4
  9. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-format-action-date-source.ts +0 -18
  10. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-read-select-option-type.ts +0 -6
  11. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-relationship-data-types.ts +0 -25
  12. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/build-result-mapping.ts +0 -62
  13. package/dist/assets/adapters/next/templates/renderers/generators/actions/action-helpers/generate-populate-list-rels-function.ts +0 -50
  14. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/build-restore-many-to-many-statements.ts +0 -27
  15. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/build-select-option-types.ts +0 -37
  16. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-bulk-sort-order-content.ts +0 -93
  17. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-create-content.ts +0 -157
  18. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-create-select-option-content.ts +0 -134
  19. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-delete-bulk-content.ts +0 -85
  20. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-delete-content.ts +0 -66
  21. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-distinct-files.ts +0 -45
  22. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-by-id-content.ts +0 -55
  23. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-by-slug-content.ts +0 -55
  24. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-plural-content.ts +0 -106
  25. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-select-options-content.ts +0 -55
  26. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-get-versions-content.ts +0 -19
  27. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-m2m-files.ts +0 -151
  28. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-restore-content.ts +0 -123
  29. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/gen-update-content.ts +0 -187
  30. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/generate-resolve-media-function.ts +0 -40
  31. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/generate-slug-helpers.ts +0 -73
  32. package/dist/assets/adapters/next/templates/renderers/generators/actions/entity-file-contents/generate-version-snapshot-helpers.ts +0 -104
  33. package/dist/assets/adapters/next/templates/renderers/generators/actions/lifecycle-hook-emissions/lifecycle-context.ts +0 -22
  34. package/dist/assets/adapters/next/templates/renderers/generators/actions/lifecycle-hook-emissions/lifecycle-hook-import.ts +0 -4
  35. package/dist/assets/adapters/next/templates/renderers/generators/actions/markdown-renderer.ts +0 -411
  36. package/dist/assets/adapters/next/templates/renderers/generators/actions/select-fields-resolver.ts +0 -99
  37. package/dist/assets/adapters/next/templates/renderers/generators/actions/single-actions/generate-single-actions.ts +0 -292
  38. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-authorship-value.ts +0 -8
  39. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-column-def.ts +0 -297
  40. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-first-column-def.ts +0 -483
  41. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-image-cell-media.ts +0 -38
  42. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-image-element.ts +0 -22
  43. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-relationship-label.ts +0 -26
  44. package/dist/assets/adapters/next/templates/renderers/generators/columns/column-defs/generate-select-label.ts +0 -17
  45. package/dist/assets/adapters/next/templates/renderers/generators/columns/custom-cell.ts +0 -24
  46. package/dist/assets/adapters/next/templates/renderers/generators/columns/generate-columns.ts +0 -55
  47. package/dist/assets/adapters/next/templates/renderers/generators/create-page.ts +0 -16
  48. package/dist/assets/adapters/next/templates/renderers/generators/database/generate-database.ts +0 -5
  49. package/dist/assets/adapters/next/templates/renderers/generators/database/generate-junction-table.ts +0 -27
  50. package/dist/assets/adapters/next/templates/renderers/generators/database/generate-select-options-table.ts +0 -35
  51. package/dist/assets/adapters/next/templates/renderers/generators/database/generate-table-definition.ts +0 -25
  52. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/build-entity-dev-mode-snippets.ts +0 -180
  53. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/build-form-dev-mode-snippets.ts +0 -97
  54. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/build-single-dev-mode-snippets.ts +0 -60
  55. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/create-dev-mode-integration-artifact.ts +0 -89
  56. package/dist/assets/adapters/next/templates/renderers/generators/dev-mode-integration/lifecycle-hook-code.ts +0 -55
  57. package/dist/assets/adapters/next/templates/renderers/generators/edit-page.ts +0 -33
  58. package/dist/assets/adapters/next/templates/renderers/generators/email-template/generate-email-template.ts +0 -248
  59. package/dist/assets/adapters/next/templates/renderers/generators/email-template/generate-field-value.ts +0 -31
  60. package/dist/assets/adapters/next/templates/renderers/generators/emitted-helpers.ts +0 -16
  61. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/generate-icon-postfix.ts +0 -27
  62. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-boolean-field.ts +0 -47
  63. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-creatable-select-field.ts +0 -122
  64. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-date-field.ts +0 -47
  65. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-default-field.ts +0 -53
  66. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-gallery-field.ts +0 -46
  67. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-group-field.ts +0 -16
  68. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-icon-field.ts +0 -31
  69. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-markdown-field.ts +0 -50
  70. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-media-field.ts +0 -47
  71. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-multi-relationship-field.ts +0 -91
  72. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-multi-select-field.ts +0 -219
  73. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-number-field.ts +0 -48
  74. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-richtext-field.ts +0 -50
  75. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-select-field.ts +0 -61
  76. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-separator-field.ts +0 -16
  77. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-single-relationship-field.ts +0 -93
  78. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx/render-textarea-field.ts +0 -53
  79. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx-nested/render-list-field.ts +0 -163
  80. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx-nested/render-nested-field.ts +0 -164
  81. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx-nested/render-nested-object-list-field.ts +0 -59
  82. package/dist/assets/adapters/next/templates/renderers/generators/form/field-jsx-nested/render-text-input-field.ts +0 -27
  83. package/dist/assets/adapters/next/templates/renderers/generators/form/form-entity/generate-form.ts +0 -822
  84. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/build-default-value-from-sync-functions.ts +0 -41
  85. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/build-ui-imports.ts +0 -58
  86. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/generate-default-value.ts +0 -67
  87. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/generate-nested-list-default-value.ts +0 -13
  88. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/label-with-description.ts +0 -14
  89. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/render-tabs-trigger.ts +0 -18
  90. package/dist/assets/adapters/next/templates/renderers/generators/form/form-shared/select-read-values-expression.ts +0 -21
  91. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/build-group-creatable-select-handlers.ts +0 -67
  92. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/build-group-creatable-select-state.ts +0 -29
  93. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/build-group-field-array-hooks.ts +0 -13
  94. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/build-group-fields-jsx.ts +0 -30
  95. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/generate-card-component.ts +0 -129
  96. package/dist/assets/adapters/next/templates/renderers/generators/form/form-single/generate-single-form.ts +0 -66
  97. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-columns/generate-column-def.ts +0 -72
  98. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-columns/generate-columns.ts +0 -89
  99. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-page/generate-page.ts +0 -23
  100. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-page-content.ts +0 -246
  101. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-submission-drawer.ts +0 -216
  102. package/dist/assets/adapters/next/templates/renderers/generators/form-admin/admin-table.ts +0 -273
  103. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-actions/exclusive-date-upper-bound-helper.ts +0 -11
  104. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-actions/generate-form-actions.ts +0 -505
  105. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-multistep/build-component-source.ts +0 -197
  106. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/build-field-error-helper.ts +0 -16
  107. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/error-message-line.ts +0 -13
  108. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-field-jsx.ts +0 -226
  109. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-file-upload-field-jsx.ts +0 -41
  110. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-list-field-jsx.ts +0 -160
  111. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-multiselect-field-jsx.ts +0 -40
  112. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-number-field-jsx.ts +0 -41
  113. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/generate-text-field-jsx.ts +0 -39
  114. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-shared/label-with-description-line.ts +0 -14
  115. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-component-single/build-single-step-form-component-source.ts +0 -100
  116. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-database.ts +0 -29
  117. package/dist/assets/adapters/next/templates/renderers/generators/form-pipeline/form-hook.ts +0 -142
  118. package/dist/assets/adapters/next/templates/renderers/generators/hook/generate-hook.ts +0 -169
  119. package/dist/assets/adapters/next/templates/renderers/generators/hook/generate-single-hook.ts +0 -30
  120. package/dist/assets/adapters/next/templates/renderers/generators/navigation-extract.ts +0 -19
  121. package/dist/assets/adapters/next/templates/renderers/generators/page-content/generate-page-content.ts +0 -419
  122. package/dist/assets/adapters/next/templates/renderers/generators/page.ts +0 -24
  123. package/dist/assets/adapters/next/templates/renderers/generators/row-actions-emitters/build-delete-dialog-source.ts +0 -108
  124. package/dist/assets/adapters/next/templates/renderers/generators/row-actions-emitters/build-row-actions-source.ts +0 -61
  125. package/dist/assets/adapters/next/templates/renderers/generators/single-page.ts +0 -59
  126. package/dist/assets/adapters/next/templates/renderers/generators/sortable-header/build-sort-label-expr.ts +0 -9
  127. package/dist/assets/adapters/next/templates/renderers/generators/sortable-header/build-sortable-header-button-jsx.ts +0 -20
  128. package/dist/assets/adapters/next/templates/renderers/generators/sortable-header/build-sortable-header-def.ts +0 -14
  129. package/dist/assets/adapters/next/templates/renderers/generators/table.ts +0 -284
  130. package/dist/assets/adapters/next/templates/renderers/generators/thankyou-email-template.ts +0 -110
  131. package/dist/assets/adapters/next/templates/renderers/generators/webhook-events/render-extract.ts +0 -14
  132. package/dist/assets/adapters/next/templates/renderers/init/scaffolders/next-config/create-next-config-template.ts +0 -48
  133. package/dist/assets/adapters/next/templates/renderers/init/scaffolders/tailwind/admin-shadow-input-utility.ts +0 -9
  134. package/dist/assets/adapters/next/templates/renderers/init/scaffolders/tailwind/admin-theme-block.ts +0 -42
  135. package/dist/assets/adapters/next/templates/renderers/init/templates/app/admin.ts +0 -12
  136. package/dist/assets/adapters/next/templates/renderers/integration-runtime/render-core-email-provider.ts +0 -27
  137. package/dist/assets/adapters/next/templates/renderers/integration-runtime/render-core-storage-provider.ts +0 -27
  138. package/dist/assets/adapters/next/templates/renderers/snapshots/barrels/render-db-barrel.ts +0 -8
  139. package/dist/assets/adapters/next/templates/renderers/snapshots/barrels/render-navigation-barrel.ts +0 -63
  140. package/dist/assets/adapters/next/templates/renderers/snapshots/barrels/render-webhook-events-barrel.ts +0 -16
@@ -1,104 +0,0 @@
1
- export function renderVersionSnapshotHelpersRowsTemplate({
2
- fieldName,
3
- relIdCol,
4
- junctionVar,
5
- entityIdCol
6
- }: {
7
- fieldName: string
8
- relIdCol: string
9
- junctionVar: string
10
- entityIdCol: string
11
- }): string {
12
- return ` const ${fieldName}Rows = await client
13
- .select({ ${relIdCol}: ${junctionVar}.${relIdCol} })
14
- .from(${junctionVar})
15
- .where(eq(${junctionVar}.${entityIdCol}, id))
16
- snapshot.${fieldName} = ${fieldName}Rows.map((row) => row.${relIdCol})`
17
- }
18
-
19
- export function renderVersionSnapshotHelpersSourceTemplate({
20
- ctxSingular,
21
- loadM2MStatements
22
- }: {
23
- ctxSingular: string
24
- loadM2MStatements: string
25
- }): string {
26
- return `
27
- export async function build${ctxSingular}VersionSnapshotWithRelationships(
28
- row: Partial<${ctxSingular}> | Record<string, unknown>,
29
- client: VersionSnapshotClient = db
30
- ): Promise<Record<string, unknown>> {
31
- const source = row as Record<string, unknown>
32
- const snapshot = build${ctxSingular}VersionSnapshot(source)
33
- const id = typeof source.id === 'string' ? source.id : null
34
-
35
- if (!id) {
36
- for (const key of VERSION_M2M_KEYS) {
37
- snapshot[key] = Array.isArray(snapshot[key]) ? snapshot[key] : []
38
- }
39
- return snapshot
40
- }
41
-
42
- ${loadM2MStatements}
43
-
44
- return snapshot
45
- }
46
- `
47
- }
48
-
49
- export function renderVersionSnapshotHelpersGeneratedFunctionTemplate({
50
- snapshotClientType,
51
- snapshotKeys,
52
- restoreKeys,
53
- m2mKeys,
54
- ctxSingular,
55
- relationshipSnapshotHelper
56
- }: {
57
- snapshotClientType: string
58
- snapshotKeys: string
59
- restoreKeys: string
60
- m2mKeys: string
61
- ctxSingular: string
62
- relationshipSnapshotHelper: string
63
- }): string {
64
- return `${snapshotClientType}const VERSION_SNAPSHOT_KEYS = [${snapshotKeys}] as const
65
- const VERSION_RESTORE_KEYS = [${restoreKeys}] as const
66
- const VERSION_M2M_KEYS = [${m2mKeys}] as const
67
-
68
- export function build${ctxSingular}VersionSnapshot(row: Partial<${ctxSingular}> | Record<string, unknown>): Record<string, unknown> {
69
- const source = row as unknown as Record<string, unknown>
70
- const snapshot: Record<string, unknown> = {}
71
-
72
- for (const key of VERSION_SNAPSHOT_KEYS) {
73
- if (key in source) {
74
- snapshot[key] = source[key]
75
- }
76
- }
77
-
78
- for (const key of VERSION_M2M_KEYS) {
79
- snapshot[key] = Array.isArray(snapshot[key]) ? snapshot[key] : []
80
- }
81
-
82
- return snapshot
83
- }
84
- ${relationshipSnapshotHelper}
85
-
86
- export function build${ctxSingular}RestoreData(data: Record<string, unknown>): Record<string, unknown> {
87
- const restoreData: Record<string, unknown> = {}
88
-
89
- for (const key of VERSION_RESTORE_KEYS) {
90
- if (key in data) {
91
- restoreData[key] = data[key]
92
- }
93
- }
94
-
95
- return restoreData
96
- }
97
-
98
- export function has${ctxSingular}VersionChanges(
99
- previous: Record<string, unknown>,
100
- next: Record<string, unknown>
101
- ): boolean {
102
- return JSON.stringify(previous) !== JSON.stringify(next)
103
- }`
104
- }
@@ -1,22 +0,0 @@
1
- export function renderLifecycleContextContentTemplate({
2
- userExpression,
3
- entityType,
4
- schemaType,
5
- sourceType,
6
- extras
7
- }: {
8
- userExpression: string
9
- entityType: string
10
- schemaType: string
11
- sourceType: string
12
- extras: string
13
- }): string {
14
- return `{
15
- user: ${userExpression},
16
- entityType: '${entityType}',${schemaType}
17
- timestamp: now,
18
- sourceType: '${sourceType}' as const,
19
- ipAddress: auditRequestMetadata.ipAddress,
20
- userAgent: auditRequestMetadata.userAgent${extras}
21
- }`
22
- }
@@ -1,4 +0,0 @@
1
- export function renderLifecycleHookImportContentTemplate(): string {
2
- return `\nimport { getAuditRequestMetadata } from '@admin/actions/audit/get-audit-request-metadata'
3
- import { runAfterHooks, runBeforeHooks } from '@admin/lib/lifecycle-hooks'`
4
- }
@@ -1,411 +0,0 @@
1
- export function renderGenMarkdownRendererContentComponentTemplate(): string {
2
- return `import { randomUUID } from 'node:crypto'
3
- import { createRequire } from 'node:module'
4
- import katex from 'katex'
5
- import MarkdownIt from 'markdown-it'
6
- import sanitizeHtml from 'sanitize-html'
7
-
8
- type MarkdownToken = MarkdownIt.Token
9
-
10
- interface DollarMathOptions {
11
- allow_space?: boolean
12
- allow_digits?: boolean
13
- double_inline?: boolean
14
- allow_labels?: boolean
15
- renderer?: (content: string, options: { displayMode: boolean }) => string
16
- labelNormalizer?: (label: string) => string
17
- labelRenderer?: (label: string) => string
18
- }
19
-
20
- type DollarMathPlugin = (md: MarkdownIt, options?: DollarMathOptions) => void
21
-
22
- const dollarmathModule = createRequire(import.meta.url)('markdown-it-dollarmath') as
23
- | DollarMathPlugin
24
- | { default: DollarMathPlugin }
25
- const dollarmath =
26
- typeof dollarmathModule === 'function' ? dollarmathModule : dollarmathModule.default
27
-
28
- interface MarkdownInlineState {
29
- src: string
30
- pos: number
31
- md: MarkdownIt
32
- env: unknown
33
- tokens: MarkdownToken[]
34
- push(type: string, tag: string, nesting: -1 | 0 | 1): MarkdownToken
35
- }
36
-
37
- interface MarkdownBlockState {
38
- src: string
39
- bMarks: number[]
40
- tShift: number[]
41
- sCount: number[]
42
- eMarks: number[]
43
- blkIndent: number
44
- line: number
45
- push(type: string, tag: string, nesting: -1 | 0 | 1): MarkdownToken
46
- }
47
-
48
- interface MarkdownRenderContext {
49
- placeholderPrefix: string
50
- trustedMathHtml: string[]
51
- }
52
-
53
- const highlightColorNames = new Set([
54
- 'gray',
55
- 'brown',
56
- 'orange',
57
- 'yellow',
58
- 'green',
59
- 'blue',
60
- 'purple',
61
- 'pink',
62
- 'red'
63
- ])
64
-
65
- const mathBlockEnvironmentNames = new Set([
66
- 'align',
67
- 'align*',
68
- 'aligned',
69
- 'alignedat',
70
- 'alignedat*',
71
- 'array',
72
- 'bmatrix',
73
- 'cases',
74
- 'equation',
75
- 'equation*',
76
- 'gather',
77
- 'gather*',
78
- 'gathered',
79
- 'matrix',
80
- 'multline',
81
- 'multline*',
82
- 'pmatrix',
83
- 'smallmatrix',
84
- 'split',
85
- 'vmatrix'
86
- ])
87
-
88
- const cssLengthPattern = /^-?(?:(?:\\d+(?:\\.\\d+)?)|(?:\\.\\d+))(?:em|ex|mu|px|rem|%)$|^0$/
89
- const cssBorderWidthPattern = /^(?:(?:\\d+(?:\\.\\d+)?)|(?:\\.\\d+))(?:em|px|rem)$|^0$/
90
-
91
- let activeRenderContext: MarkdownRenderContext | null = null
92
-
93
- function renderKatex(content: string, displayMode: boolean) {
94
- return katex.renderToString(content, {
95
- displayMode,
96
- output: 'htmlAndMathml',
97
- throwOnError: false,
98
- strict: 'ignore',
99
- trust: false
100
- })
101
- }
102
-
103
- function renderTrustedMathPlaceholder(content: string, displayMode: boolean) {
104
- const html = sanitizeKatexHtml(renderKatex(content, displayMode))
105
- if (!activeRenderContext) return html
106
-
107
- const placeholder = \`\${activeRenderContext.placeholderPrefix + activeRenderContext.trustedMathHtml.length}__\`
108
- activeRenderContext.trustedMathHtml.push(html)
109
- return placeholder
110
- }
111
-
112
- function slugify(text: string): string {
113
- return text
114
- .toLowerCase()
115
- .trim()
116
- .replace(/[^\\w\\s-]/g, '')
117
- .replace(/\\s+/g, '-')
118
- .replace(/-+/g, '-')
119
- .replace(/^-+|-+$/g, '')
120
- }
121
-
122
- function headingAnchorPlugin(md: MarkdownIt) {
123
- md.core.ruler.push('heading_anchors', (state) => {
124
- const tokens = state.tokens
125
- for (let i = 0; i < tokens.length; i++) {
126
- const token = tokens[i]
127
- if (token.type !== 'heading_open') continue
128
-
129
- const contentToken = tokens[i + 1]
130
- if (!contentToken || contentToken.type !== 'inline' || !contentToken.content) continue
131
-
132
- const slug = slugify(contentToken.content)
133
- const idIndex = token.attrIndex('id')
134
- if (idIndex < 0) {
135
- token.attrPush(['id', slug])
136
- } else if (token.attrs) {
137
- token.attrs[idIndex][1] = slug
138
- }
139
- }
140
- return true
141
- })
142
- }
143
-
144
- function betterStartMathPlugin(md: MarkdownIt) {
145
- md.inline.ruler.before('escape', 'betterstart_bracket_inline_math', tokenizeBracketInlineMath)
146
- md.block.ruler.before('paragraph', 'betterstart_bracket_block_math', tokenizeBracketBlockMath, {
147
- alt: ['paragraph', 'reference', 'blockquote', 'list']
148
- })
149
- }
150
-
151
- function tokenizeBracketInlineMath(state: MarkdownInlineState, silent: boolean): boolean {
152
- if (!state.src.startsWith('\\\\(', state.pos)) return false
153
-
154
- const closingIndex = findUnescapedSequence(state.src, '\\\\)', state.pos + 2)
155
- if (closingIndex === -1) return false
156
-
157
- const content = state.src.slice(state.pos + 2, closingIndex)
158
- if (!content.trim() || content.includes('\\n')) return false
159
-
160
- if (!silent) {
161
- const token = state.push('html_inline', '', 0)
162
- token.content = renderTrustedMathPlaceholder(content, false)
163
- }
164
-
165
- state.pos = closingIndex + 2
166
- return true
167
- }
168
-
169
- function tokenizeBracketBlockMath(
170
- state: MarkdownBlockState,
171
- startLine: number,
172
- endLine: number,
173
- silent: boolean
174
- ): boolean {
175
- if (state.sCount[startLine] - state.blkIndent >= 4) return false
176
-
177
- const startPosition = state.bMarks[startLine] + state.tShift[startLine]
178
- const firstLine = state.src.slice(startPosition, state.eMarks[startLine])
179
-
180
- if (firstLine.startsWith('\\\\[')) {
181
- const closingIndex = findUnescapedSequence(state.src, '\\\\]', startPosition + 2)
182
- if (closingIndex === -1) return false
183
-
184
- const closingLine = findLineForPosition(state, startLine, endLine, closingIndex + 2)
185
- if (closingLine === -1) return false
186
- if (/\\S/.test(state.src.slice(closingIndex + 2, state.eMarks[closingLine]))) return false
187
-
188
- if (!silent) {
189
- const token = state.push('html_block', '', 0)
190
- token.block = true
191
- token.content = renderTrustedMathPlaceholder(state.src.slice(startPosition + 2, closingIndex).trim(), true)
192
- token.markup = '\\\\[\\\\]'
193
- token.map = [startLine, closingLine + 1]
194
- }
195
-
196
- state.line = closingLine + 1
197
- return true
198
- }
199
-
200
- const environmentMatch = /^\\\\begin\\{([^}]+)\\}/.exec(firstLine)
201
- if (!environmentMatch || !mathBlockEnvironmentNames.has(environmentMatch[1])) return false
202
-
203
- const closingSequence = \`\\\\end{\${environmentMatch[1]}}\`
204
- const closingIndex = findUnescapedSequence(state.src, closingSequence, startPosition + environmentMatch[0].length)
205
- if (closingIndex === -1) return false
206
-
207
- const closingEnd = closingIndex + closingSequence.length
208
- const closingLine = findLineForPosition(state, startLine, endLine, closingEnd)
209
- if (closingLine === -1) return false
210
- if (/\\S/.test(state.src.slice(closingEnd, state.eMarks[closingLine]))) return false
211
-
212
- if (!silent) {
213
- const token = state.push('html_block', '', 0)
214
- token.block = true
215
- token.content = renderTrustedMathPlaceholder(state.src.slice(startPosition, closingEnd).trim(), true)
216
- token.markup = '\\\\begin'
217
- token.map = [startLine, closingLine + 1]
218
- }
219
-
220
- state.line = closingLine + 1
221
- return true
222
- }
223
-
224
- function findLineForPosition(
225
- state: MarkdownBlockState,
226
- startLine: number,
227
- endLine: number,
228
- position: number
229
- ) {
230
- for (let line = startLine; line < endLine; line++) {
231
- if (position <= state.eMarks[line]) return line
232
- }
233
-
234
- return -1
235
- }
236
-
237
- function findUnescapedSequence(value: string, sequence: string, start: number) {
238
- let index = value.indexOf(sequence, start)
239
-
240
- while (index !== -1) {
241
- if (!isEscaped(value, index)) return index
242
- index = value.indexOf(sequence, index + sequence.length)
243
- }
244
-
245
- return -1
246
- }
247
-
248
- function isEscaped(value: string, index: number) {
249
- let slashCount = 0
250
-
251
- for (let offset = index - 1; offset >= 0 && value[offset] === '\\\\'; offset--) {
252
- slashCount++
253
- }
254
-
255
- return slashCount % 2 === 1
256
- }
257
-
258
- const md = MarkdownIt({
259
- html: true,
260
- linkify: true,
261
- typographer: true,
262
- breaks: true
263
- })
264
- .use(headingAnchorPlugin)
265
- .use(betterStartMathPlugin)
266
- .use(dollarmath, {
267
- allow_space: false,
268
- allow_digits: false,
269
- double_inline: true,
270
- allow_labels: true,
271
- renderer(content: string, { displayMode }: { displayMode: boolean }) {
272
- return renderTrustedMathPlaceholder(content, displayMode)
273
- },
274
- labelNormalizer(label: string) {
275
- const normalized = label
276
- .trim()
277
- .replace(/[\\s]+/g, '-')
278
- .replace(/[^A-Za-z0-9_.:-]/g, '')
279
- return normalized || 'equation'
280
- },
281
- labelRenderer(label: string) {
282
- return \`<a id="\${label}" href="#\${label}" class="mathlabel" title="Permalink to this equation">&para;</a>\`
283
- }
284
- })
285
-
286
- function sanitizeMarkdownHtml(html: string): string {
287
- return sanitizeHtml(html, {
288
- allowedTags: sanitizeHtml.defaults.allowedTags.concat([
289
- 'img',
290
- 'u',
291
- 'span'
292
- ]),
293
- allowedAttributes: {
294
- ...sanitizeHtml.defaults.allowedAttributes,
295
- a: ['href', 'name', 'target', 'rel', 'id'],
296
- annotation: ['encoding'],
297
- h1: ['id'],
298
- h2: ['id'],
299
- h3: ['id'],
300
- h4: ['id'],
301
- h5: ['id'],
302
- h6: ['id'],
303
- img: ['src', 'alt', 'title', 'width', 'height'],
304
- span: ['aria-hidden', 'data-highlight-color']
305
- },
306
- allowedSchemes: ['http', 'https', 'mailto', 'tel'],
307
- transformTags: {
308
- span(tagName, attribs) {
309
- const highlightColor = attribs['data-highlight-color']
310
- const sanitizedAttribs: Record<string, string> = {}
311
-
312
- if (highlightColor && highlightColorNames.has(highlightColor)) {
313
- sanitizedAttribs['data-highlight-color'] = highlightColor
314
- }
315
-
316
- return {
317
- tagName,
318
- attribs: sanitizedAttribs
319
- }
320
- }
321
- }
322
- })
323
- }
324
-
325
- function sanitizeKatexHtml(html: string): string {
326
- return sanitizeHtml(html, {
327
- allowedTags: [
328
- 'annotation',
329
- 'div',
330
- 'math',
331
- 'mfrac',
332
- 'mi',
333
- 'mn',
334
- 'mo',
335
- 'mover',
336
- 'mrow',
337
- 'msqrt',
338
- 'mspace',
339
- 'mstyle',
340
- 'msub',
341
- 'msubsup',
342
- 'msup',
343
- 'mtable',
344
- 'mtd',
345
- 'mtext',
346
- 'mtr',
347
- 'semantics',
348
- 'span'
349
- ],
350
- allowedAttributes: {
351
- annotation: ['encoding'],
352
- div: ['class', 'style'],
353
- math: ['xmlns'],
354
- span: ['class', 'style', 'aria-hidden'],
355
- mtd: ['columnalign'],
356
- mtr: ['rowalign'],
357
- mstyle: ['scriptlevel', 'displaystyle'],
358
- mspace: ['width'],
359
- mrow: ['class'],
360
- mo: ['stretchy', 'fence', 'separator', 'lspace', 'rspace'],
361
- mi: ['mathvariant'],
362
- mn: ['mathvariant'],
363
- mtext: ['mathvariant'],
364
- semantics: [],
365
- mfrac: ['linethickness']
366
- },
367
- allowedStyles: {
368
- '*': {
369
- 'border-bottom-width': [cssBorderWidthPattern],
370
- 'border-style': [/^solid$/],
371
- 'border-width': [cssBorderWidthPattern],
372
- height: [cssLengthPattern],
373
- left: [cssLengthPattern],
374
- 'margin-left': [cssLengthPattern],
375
- 'margin-right': [cssLengthPattern],
376
- 'min-width': [cssLengthPattern],
377
- 'padding-left': [cssLengthPattern],
378
- position: [/^relative$/],
379
- top: [cssLengthPattern],
380
- 'vertical-align': [cssLengthPattern],
381
- width: [cssLengthPattern]
382
- }
383
- }
384
- })
385
- }
386
-
387
- export function renderMarkdownSync(src: string): string {
388
- const context: MarkdownRenderContext = {
389
- placeholderPrefix: \`__BETTERSTART_KATEX_\${randomUUID()}_\`,
390
- trustedMathHtml: []
391
- }
392
-
393
- activeRenderContext = context
394
- let html: string
395
- try {
396
- html = md.render(src)
397
- } finally {
398
- activeRenderContext = null
399
- }
400
-
401
- let sanitized = sanitizeMarkdownHtml(html)
402
- context.trustedMathHtml.forEach((mathHtml, index) => {
403
- sanitized = sanitized
404
- .split(\`\${context.placeholderPrefix + index}__\`)
405
- .join(mathHtml)
406
- })
407
-
408
- return sanitized
409
- }
410
- `
411
- }
@@ -1,99 +0,0 @@
1
- export function renderResolveSelectFieldsSourceDynamicRowsTemplate({
2
- selectOptionsTableVar
3
- }: {
4
- selectOptionsTableVar: string
5
- }): string {
6
- return `
7
- const dynamicRows = await db
8
- .select({
9
- fieldName: ${selectOptionsTableVar}.fieldName,
10
- label: ${selectOptionsTableVar}.label,
11
- value: ${selectOptionsTableVar}.value
12
- })
13
- .from(${selectOptionsTableVar})
14
-
15
- for (const row of dynamicRows) {
16
- labelMaps[row.fieldName] ??= {}
17
- labelMaps[row.fieldName][row.value] = row.label
18
- }
19
- `
20
- }
21
-
22
- export function renderResolveSelectFieldsSourceStaticSelectOptionLabelsTemplate({
23
- staticLabelMaps,
24
- exportedExport,
25
- singular,
26
- dynamicRowsBlock,
27
- assignments
28
- }: {
29
- staticLabelMaps: string
30
- exportedExport: string
31
- singular: string
32
- dynamicRowsBlock: string
33
- assignments: string
34
- }): string {
35
- return `const STATIC_SELECT_OPTION_LABELS = {
36
- ${staticLabelMaps}
37
- } satisfies Record<string, Record<string, string>>
38
-
39
- function cloneSelectOptionLabelMaps(): Record<string, Record<string, string>> {
40
- return Object.fromEntries(
41
- Object.entries(STATIC_SELECT_OPTION_LABELS).map(([fieldName, labels]) => [
42
- fieldName,
43
- { ...labels }
44
- ])
45
- )
46
- }
47
-
48
- function toSelectOptionValues(value: unknown, labels: Record<string, string>): SelectOptionValue[] {
49
- const values = Array.isArray(value) ? value : value ? [value] : []
50
-
51
- return values
52
- .filter((item): item is string => typeof item === 'string' && item.length > 0)
53
- .map((item) => ({
54
- label: labels[item] ?? item,
55
- value: item
56
- }))
57
- }
58
-
59
- function resolveSelectFieldPath(
60
- source: Record<string, unknown>,
61
- path: readonly string[],
62
- labels: Record<string, string>
63
- ): void {
64
- const [fieldName, ...rest] = path
65
- if (!fieldName) return
66
-
67
- if (rest.length === 0) {
68
- source[fieldName] = toSelectOptionValues(source[fieldName], labels)
69
- return
70
- }
71
-
72
- const value = source[fieldName]
73
- if (Array.isArray(value)) {
74
- for (const item of value) {
75
- if (item && typeof item === 'object') {
76
- resolveSelectFieldPath(item as Record<string, unknown>, rest, labels)
77
- }
78
- }
79
- return
80
- }
81
-
82
- if (value && typeof value === 'object') {
83
- resolveSelectFieldPath(value as Record<string, unknown>, rest, labels)
84
- }
85
- }
86
-
87
- ${exportedExport}async function resolve${singular}SelectFields(rows: ${singular}[]): Promise<${singular}[]> {
88
- if (rows.length === 0) return rows
89
-
90
- const labelMaps = cloneSelectOptionLabelMaps()
91
- ${dynamicRowsBlock}
92
- for (const row of rows) {
93
- const source = row as unknown as Record<string, unknown>
94
- ${assignments}
95
- }
96
-
97
- return rows
98
- }`
99
- }