-
Notifications
You must be signed in to change notification settings - Fork 450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(cli): add non-studio app template #8394
Changes from all commits
d59295d
9773a36
7851cad
a428dd6
63b3ca3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import {processTemplate} from './processTemplate' | ||
|
||
const defaultCoreAppTemplate = ` | ||
import {defineCliConfig} from 'sanity/cli' | ||
|
||
export default defineCliConfig({ | ||
__experimental_coreAppConfiguration: { | ||
appLocation: '%appLocation%' | ||
}, | ||
}) | ||
` | ||
|
||
export interface GenerateCliConfigOptions { | ||
organizationId?: string | ||
appLocation: string | ||
} | ||
|
||
export function createCoreAppCliConfig(options: GenerateCliConfigOptions): string { | ||
return processTemplate({ | ||
template: defaultCoreAppTemplate, | ||
variables: options, | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
const coreAppTemplates = ['core-app'] | ||
|
||
/** | ||
* Determine if a given template is a studio template. | ||
* This function may need to be more robust once we | ||
* introduce remote templates, for example. | ||
* | ||
* @param templateName - Name of the template | ||
* @returns boolean indicating if the template is a studio template | ||
*/ | ||
export function determineCoreAppTemplate(templateName: string): boolean { | ||
return coreAppTemplates.includes(templateName) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import traverse from '@babel/traverse' | ||
import {parse, print} from 'recast' | ||
import * as parser from 'recast/parsers/typescript' | ||
|
||
interface TemplateOptions<T> { | ||
template: string | ||
variables: T | ||
includeBooleanTransform?: boolean | ||
} | ||
|
||
export function processTemplate<T extends object>(options: TemplateOptions<T>): string { | ||
const {template, variables, includeBooleanTransform = false} = options | ||
const ast = parse(template.trimStart(), {parser}) | ||
|
||
traverse(ast, { | ||
StringLiteral: { | ||
enter({node}) { | ||
const value = node.value | ||
if (!value.startsWith('%') || !value.endsWith('%')) { | ||
return | ||
} | ||
const variableName = value.slice(1, -1) as keyof T | ||
if (!(variableName in variables)) { | ||
throw new Error(`Template variable '${value}' not defined`) | ||
} | ||
const newValue = variables[variableName] | ||
/* | ||
* although there are valid non-strings in our config, | ||
* they're not in StringLiteral nodes, so assume undefined | ||
*/ | ||
node.value = typeof newValue === 'string' ? newValue : '' | ||
}, | ||
}, | ||
...(includeBooleanTransform && { | ||
Identifier: { | ||
enter(path) { | ||
if (!path.node.name.startsWith('__BOOL__')) { | ||
return | ||
} | ||
const variableName = path.node.name.replace(/^__BOOL__(.+?)__$/, '$1') as keyof T | ||
if (!(variableName in variables)) { | ||
throw new Error(`Template variable '${variableName.toString()}' not defined`) | ||
} | ||
const value = variables[variableName] | ||
if (typeof value !== 'boolean') { | ||
throw new Error(`Expected boolean value for '${variableName.toString()}'`) | ||
} | ||
path.replaceWith({type: 'BooleanLiteral', value}) | ||
}, | ||
}, | ||
}), | ||
}) | ||
|
||
return print(ast, {quote: 'single'}).code | ||
} |
Unchanged files with check annotations Beta
) | ||
const debounceSelectionChange = useMemo( | ||
() => debounce(handleSelectionChange, 200), | ||
[handleSelectionChange], | ||
) | ||
const currentSelectionIsOverlapping = useMemo(() => { | ||
if (!currentSelection || addedCommentsDecorations.length === 0) return false | ||
return addedCommentsDecorations.some((d) => { | ||
if (!editorRef.current) return false | ||
const testA = PortableTextEditor.isSelectionsOverlapping( | ||
}, [handleBuildRangeDecorations, textComments]) | ||
const showFloatingButton = Boolean( | ||
currentSelection && canSubmit && selectionReferenceElement && !mouseDownRef.current, | ||
) | ||
const showFloatingInput = Boolean(nextCommentSelection && popoverAuthoringReferenceElement) | ||
</BoundaryElementProvider> | ||
<Stack ref={setRootElement} onMouseDown={handleMouseDown} onMouseUp={handleMouseUp}> | ||
{props.renderDefault({ | ||
...props, | ||
onEditorChange, | ||
editorRef, |
const disabled = getItemDisabled?.(index) ?? false | ||
const selected = getItemSelected?.(index) ?? false | ||
if (!disabled) { | ||
i += 1 | ||
} | ||
acc[index] = { | ||
activeIndex: disabled ? null : i, |
const rangeDecorations = useMemo((): RangeDecoration[] => { | ||
const result = [...(rangeDecorationsProp || []), ...presenceCursorDecorations] | ||
const reconciled = immutableReconcile(previousRangeDecorations.current, result) | ||
previousRangeDecorations.current = reconciled | ||
return reconciled | ||
}, [presenceCursorDecorations, rangeDecorationsProp]) | ||
[validation], | ||
) | ||
const reconciled = immutableReconcile(prev.current, validation) | ||
prev.current = reconciled | ||
return useMemo(() => { | ||
return { |
} | ||
} | ||
const items: PortableTextMemberItem[] = result.map((item) => { | ||
const key = pathToString(item.node.path) | ||
const existingItem = portableTextMemberItemsRef.current.find((refItem) => refItem.key === key) | ||
const isObject = item.kind !== 'textBlock' |
export const BrandLogo = () => ( | ||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 530"> | ||
<g> | ||
<path |
return str.replace(/^drafts\./, '') | ||
} | ||
export function resolveProductionUrl(document, rev) { | ||
Check warning on line 7 in examples/movies-studio/resolveProductionUrl.ts
|
||
const id = stripDraftId(document._id) | ||
if (rev) { |
], | ||
document: { | ||
// @todo | ||
Check warning on line 34 in examples/movies-studio/sanity.config.ts
|
||
//productionUrl: resolveProductionUrl, | ||
}, | ||
}) |
* @returns The same string as the input | ||
* @public | ||
*/ | ||
export function groq(strings: TemplateStringsArray, ...keys: any[]): string { | ||
const lastIndex = strings.length - 1 | ||
return ( | ||
strings.slice(0, lastIndex).reduce((acc, str, i) => { |
export function diffNumber<A>( | ||
fromInput: NumberInput<A>, | ||
toInput: NumberInput<A>, | ||
options: DiffOptions, | ||
Check warning on line 12 in packages/@sanity/diff/src/calculate/diffSimple.ts
|
||
): NumberDiff<A> { | ||
const fromValue = fromInput.value | ||
const toValue = toInput.value | ||
export function diffBoolean<A>( | ||
fromInput: BooleanInput<A>, | ||
toInput: BooleanInput<A>, | ||
options: DiffOptions, | ||
Check warning on line 40 in packages/@sanity/diff/src/calculate/diffSimple.ts
|
||
): BooleanDiff<A> { | ||
const fromValue = fromInput.value | ||
const toValue = toInput.value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📝 Confirm this is the key we want to use