diff --git a/apps/client-web/src/docs_legacy/pages/DocumentContentPage.tsx b/apps/client-web/src/docs_legacy/pages/DocumentContentPage.tsx
index 44967cf2e..72521595f 100644
--- a/apps/client-web/src/docs_legacy/pages/DocumentContentPage.tsx
+++ b/apps/client-web/src/docs_legacy/pages/DocumentContentPage.tsx
@@ -18,9 +18,12 @@ import { useFormulaActions } from './hooks/useFormulaActions'
import { AppError404 } from '@/routes/_shared/AppError'
import { type DocMeta, DocMetaProvider } from '../store/DocMeta'
import { MashcardEventBus, BlockMetaUpdated, ReloadDocument } from '@mashcard/schema'
+import { formulaI18n } from '@mashcard/editor/src/helpers'
+import { useFormulaI18n } from '@mashcard/editor/src/hooks/useFormulaI18n'
export const DocumentContentPage: FC = () => {
const { t } = useDocsI18n()
+ const { t: formulaT } = useFormulaI18n()
const { domain, docId, historyId } = useParams() as unknown as {
domain: string
docId?: string
@@ -141,8 +144,9 @@ export const DocumentContentPage: FC = () => {
useEffect(() => {
const functionClauses = generateFormulaFunctionClauses()
- const formulaContext = FormulaContext.getInstance({
- domain,
+ const formulaContext = FormulaContext.getFormulaInstance({
+ username: domain,
+ i18n: formulaI18n(formulaT),
backendActions: { commit: commitFormula },
functionClauses,
features: featureFlags
diff --git a/packages/editor/__snapshots__/components/ui/Formula/__tests__/FormulaDisplay.test.tsx.snap b/packages/editor/__snapshots__/components/ui/Formula/__tests__/FormulaDisplay.test.tsx.snap
index 5682a6191..d2bc58b6e 100644
--- a/packages/editor/__snapshots__/components/ui/Formula/__tests__/FormulaDisplay.test.tsx.snap
+++ b/packages/editor/__snapshots__/components/ui/Formula/__tests__/FormulaDisplay.test.tsx.snap
@@ -759,7 +759,7 @@ exports[`FormulaDisplay [partial error 2] basic "=custom::ADD(1)" 2`] = `
class="mashcard-formula-borderless"
style="color: rgb(207, 31, 40);"
>
- #<Error> errors.parse.not_found.function,[object Object]
+ #<Error> errors.parse.not_found.function {"key":"custom::ADD"}
diff --git a/packages/editor/__snapshots__/components/ui/Formula/__tests__/FormulaResult.test.tsx.snap b/packages/editor/__snapshots__/components/ui/Formula/__tests__/FormulaResult.test.tsx.snap
index d1b36f1da..383551870 100644
--- a/packages/editor/__snapshots__/components/ui/Formula/__tests__/FormulaResult.test.tsx.snap
+++ b/packages/editor/__snapshots__/components/ui/Formula/__tests__/FormulaResult.test.tsx.snap
@@ -2410,7 +2410,7 @@ exports[`FormulaResult chain "={a:1}.b" -> [object Object] 1`] = `
class="mashcard-formula-borderless"
style="color: rgb(207, 31, 40);"
>
- #<Error> errors.interpret.not_found.key,[object Object]
+ #<Error> errors.interpret.not_found.key {"key":"b"}
- #<Error> errors.parse.not_found.function,[object Object]
+ #<Error> errors.parse.not_found.function {"key":"custom::ADD"}
`;
@@ -1063,7 +1063,7 @@ exports[`FormulaValue [partial error 2] basic "=custom::ADD(1)" 3`] = `
class="mashcard-formula-borderless"
style="color: rgb(207, 31, 40);"
>
- #<Error> errors.parse.not_found.function,[object Object]
+ #<Error> errors.parse.not_found.function {"key":"custom::ADD"}
`;
@@ -1074,7 +1074,7 @@ exports[`FormulaValue [partial error 2] basic "=custom::ADD(1)" 4`] = `
class="mashcard-formula-borderless"
style="color: rgb(207, 31, 40);"
>
- #<Error> errors.parse.not_found.function,[object Object]
+ #<Error> errors.parse.not_found.function {"key":"custom::ADD"}
`;
diff --git a/packages/editor/src/components/blockViews/FormulaView/useFormula.ts b/packages/editor/src/components/blockViews/FormulaView/useFormula.ts
index ac546c397..e36e59a4b 100644
--- a/packages/editor/src/components/blockViews/FormulaView/useFormula.ts
+++ b/packages/editor/src/components/blockViews/FormulaView/useFormula.ts
@@ -505,12 +505,12 @@ export const useFormula = ({
setReferences(e.payload.meta)
},
{
- eventId: `${formulaContext?.domain}#${namespaceId},${variableId}`,
+ eventId: `${formulaContext?.username}#${namespaceId},${variableId}`,
subscribeId: `UseFormula#${namespaceId},${variableId}`
}
)
return () => listener.unsubscribe()
- }, [formulaContext?.domain, namespaceId, variableId])
+ }, [formulaContext?.username, namespaceId, variableId])
React.useEffect(() => {
const listener = MashcardEventBus.subscribe(
diff --git a/packages/editor/src/components/blockViews/Spreadsheet/SpreadsheetCell.tsx b/packages/editor/src/components/blockViews/Spreadsheet/SpreadsheetCell.tsx
index 5489255d7..186b0e802 100644
--- a/packages/editor/src/components/blockViews/Spreadsheet/SpreadsheetCell.tsx
+++ b/packages/editor/src/components/blockViews/Spreadsheet/SpreadsheetCell.tsx
@@ -79,7 +79,7 @@ export const SpreadsheetCell: React.FC = ({
async (variable: VariableInterface | undefined): Promise => {
if (!variable) return
// TODO check no persist
- const value = display(fetchResult(variable.t)).result
+ const value = display(fetchResult(variable.t), formulaContext!).result
const oldValue = block.text
if (value === oldValue) return
devLog('Spreadsheet cell formula updated', { cellId, value, rootId })
@@ -98,7 +98,7 @@ export const SpreadsheetCell: React.FC = ({
},
meta: null,
namespaceId: rootId,
- username: formulaContext.domain,
+ username: formulaContext.username,
key: variable?.currentUUID ?? tableId
})
)
@@ -194,7 +194,9 @@ export const SpreadsheetCell: React.FC = ({
latestEditing.current = false
}
- const displayResult = savedVariableT ? display(fetchResult(savedVariableT)).result : currentBlock.text
+ const displayResult = savedVariableT
+ ? display(fetchResult(savedVariableT), formulaContext!).result
+ : currentBlock.text
const fallbackDisplayData: VariableDisplayData | undefined = displayResult
? {
definition: displayResult,
diff --git a/packages/editor/src/components/blockViews/Spreadsheet/SpreadsheetRender.tsx b/packages/editor/src/components/blockViews/Spreadsheet/SpreadsheetRender.tsx
index 8c1bfb4ed..0ef9fdf08 100644
--- a/packages/editor/src/components/blockViews/Spreadsheet/SpreadsheetRender.tsx
+++ b/packages/editor/src/components/blockViews/Spreadsheet/SpreadsheetRender.tsx
@@ -12,7 +12,7 @@ import {
SpreadsheetCellContainer,
SpreadsheetColumnEditable
} from './SpreadsheetView'
-import { display, VariableDisplayData } from '@mashcard/formula'
+import { display, SpreadsheetType, VariableDisplayData } from '@mashcard/formula'
import React from 'react'
import { FormulaDisplay } from '../../ui/Formula'
import { styled } from '@mashcard/design-system'
@@ -29,7 +29,7 @@ export interface Column {
}
export interface SpreadsheetRenderProps {
- title: string
+ spreadsheet: SpreadsheetType
rows: Row[]
valuesMatrix: Map>
columns: Column[]
@@ -38,7 +38,7 @@ export interface SpreadsheetRenderProps {
export const SpreadsheetRender: React.FC = ({
rows,
- title,
+ spreadsheet,
columns,
valuesMatrix,
defaultSelection
@@ -56,7 +56,7 @@ export const SpreadsheetRender: React.FC = ({
new Map(
columns.map(c => {
const displayData = valuesMatrix.get(rowId)?.get(c.columnId)
- return [c.columnId, displayData ? display(displayData.result).result : '']
+ return [c.columnId, displayData ? display(displayData.result, spreadsheet._formulaContext).result : '']
})
)
]
@@ -99,7 +99,8 @@ export const SpreadsheetRender: React.FC = ({
context={spreadsheetContext}
columnId={column.columnId}
columnActions={[]}
- draggable={false}>
+ draggable={false}
+ >
= ({
+ cellId={{ rowId: rowBlock.rowId, columnId: column.columnId }}
+ >
{
// TODO: remove this when switch pages
@@ -75,18 +75,18 @@ export function useFormulaSpreadsheet({
spreadsheetId,
namespaceId: rootId,
rows: rowData,
- username: formulaContext?.domain
+ username: formulaContext?.username
})
- }, [rootId, spreadsheetId, rowData, formulaContext?.domain])
+ }, [rootId, spreadsheetId, rowData, formulaContext?.username])
React.useEffect(() => {
void dispatchFormulaSpreadsheetColumnChange({
spreadsheetId,
namespaceId: rootId,
columns: columnData,
- username: formulaContext?.domain
+ username: formulaContext?.username
})
- }, [rootId, spreadsheetId, columnData, formulaContext?.domain])
+ }, [rootId, spreadsheetId, columnData, formulaContext?.username])
React.useEffect(() => {
if (!formulaContext) return
@@ -123,7 +123,7 @@ export function useFormulaSpreadsheet({
return {
deleteSpreadsheet: () => {
- void dispatchFormulaSpreadsheetRemove({ id: spreadsheetId, username: formulaContext?.domain })
+ void dispatchFormulaSpreadsheetRemove({ id: spreadsheetId, username: formulaContext?.username })
}
}
}
diff --git a/packages/editor/src/components/ui/Formula/AutocompleteList/__tests__/AutocompleteList.test.tsx b/packages/editor/src/components/ui/Formula/AutocompleteList/__tests__/AutocompleteList.test.tsx
index a9e35f3dd..7aa91825d 100644
--- a/packages/editor/src/components/ui/Formula/AutocompleteList/__tests__/AutocompleteList.test.tsx
+++ b/packages/editor/src/components/ui/Formula/AutocompleteList/__tests__/AutocompleteList.test.tsx
@@ -208,7 +208,7 @@ describe('AutocompleteList', () => {
})
it('renders variable kind correctly', async () => {
- const formulaContext = FormulaContext.getInstance({ domain: 'test' })
+ const formulaContext = FormulaContext.getFormulaInstance({ username: 'test' })
const interpretContext = { ctx: {}, arguments: [] }
const namespaceId = '37198be0-d10d-42dc-ae8b-20d45a95401b'
diff --git a/packages/editor/src/components/ui/Formula/FormulaError.tsx b/packages/editor/src/components/ui/Formula/FormulaError.tsx
index 0f551d1fa..6dd6fe9d8 100644
--- a/packages/editor/src/components/ui/Formula/FormulaError.tsx
+++ b/packages/editor/src/components/ui/Formula/FormulaError.tsx
@@ -1,5 +1,6 @@
import { FC } from 'react'
import { ErrorMessage } from '@mashcard/formula'
+import { formulaI18n } from '../../../helpers'
import { useFormulaI18n } from '../../../hooks/useFormulaI18n'
export interface FormulaErrorProps {
@@ -8,13 +9,7 @@ export interface FormulaErrorProps {
export const FormulaError: FC = ({ error }) => {
const { t } = useFormulaI18n()
-
- let errorMessage: string
- if (typeof error.message === 'string') {
- errorMessage = t(error.message)
- } else {
- errorMessage = t(error.message[0], error.message[1])
- }
+ const errorMessage = formulaI18n(t)(error.message)
return (
<>
diff --git a/packages/editor/src/components/ui/Formula/FormulaValue.tsx b/packages/editor/src/components/ui/Formula/FormulaValue.tsx
index 2fe5f0f71..9c3ac1d7e 100644
--- a/packages/editor/src/components/ui/Formula/FormulaValue.tsx
+++ b/packages/editor/src/components/ui/Formula/FormulaValue.tsx
@@ -1,9 +1,10 @@
import { FC, ReactElement } from 'react'
import { resultToColorType, VariableDisplayData, display } from '@mashcard/formula'
import { cx, Icon, Tooltip } from '@mashcard/design-system'
-import { SelectedType } from '../../blockViews/FormulaView'
+import { getFormulaContext, SelectedType } from '../../blockViews/FormulaView'
import { FORMULA_COLOR_METAS, FORMULA_ICONS, FORMULA_STYLES } from './color'
import * as Root from './Formula.style'
+import { useEditorContext } from '../../../hooks'
export interface FormulaValueProps {
displayData: VariableDisplayData
@@ -20,11 +21,14 @@ export const FormulaValue: FC = ({
disablePopover,
displayData: { result, type }
}) => {
+ const { editor } = useEditorContext()
+ const formulaContext = getFormulaContext(editor)
+
const colorType = resultToColorType(result)
const { colorCode } = FORMULA_COLOR_METAS[colorType]
const icon = FORMULA_ICONS[colorType]
const hasBorder = type === 'normal' && border
- const displayResult = display(result).result
+ const displayResult = display(result, formulaContext!).result
if (!hasBorder) {
return (
diff --git a/packages/editor/src/components/ui/Formula/Render/FormulaSpreadsheet.tsx b/packages/editor/src/components/ui/Formula/Render/FormulaSpreadsheet.tsx
index 6f5b69c4c..47aacbc1e 100644
--- a/packages/editor/src/components/ui/Formula/Render/FormulaSpreadsheet.tsx
+++ b/packages/editor/src/components/ui/Formula/Render/FormulaSpreadsheet.tsx
@@ -38,7 +38,7 @@ export const FormulaSpreadsheet: React.FC = ({
return (
{
+ const { useEditorContext } = jest.requireActual('../../../../hooks/useEditorContext')
+ return { useEditorContext: jest.fn().mockImplementation(useEditorContext) }
+})
+
describe('FormulaDisplay', () => {
let ctx: Awaited>
beforeAll(async () => {
jest.useRealTimers()
ctx = await makeContext(input.options)
jest.clearAllTimers()
+
+ const editor = mockEditor({
+ extensionManager: {
+ extensions: [{ name: Formula.name, options: { formulaContext: ctx.formulaContext } }]
+ }
+ })
+
+ jest.spyOn(editorHooks, 'useEditorContext').mockImplementation(() => ({ editor, documentEditable: true }))
})
it.each(input.basicTestCases)('$jestTitle', async args => {
diff --git a/packages/editor/src/components/ui/Formula/__tests__/FormulaResult.test.tsx b/packages/editor/src/components/ui/Formula/__tests__/FormulaResult.test.tsx
index 2261081c8..7ca2db2ec 100644
--- a/packages/editor/src/components/ui/Formula/__tests__/FormulaResult.test.tsx
+++ b/packages/editor/src/components/ui/Formula/__tests__/FormulaResult.test.tsx
@@ -1,6 +1,9 @@
import { BasicNames, buildTestCases, makeContext, TestCaseInput } from '@mashcard/formula'
import { render } from '@testing-library/react'
+import { Formula } from '../../../../extensions'
+import { mockEditor } from '../../../../test'
import { FormulaResult } from '../FormulaResult'
+import * as editorHooks from '../../../../hooks/useEditorContext'
const [input, testCases] = buildTestCases(BasicNames)
@@ -17,12 +20,25 @@ jest.mock('react-i18next', () => ({
}
}))
+jest.mock('../../../../hooks/useEditorContext', () => {
+ const { useEditorContext } = jest.requireActual('../../../../hooks/useEditorContext')
+ return { useEditorContext: jest.fn().mockImplementation(useEditorContext) }
+})
+
describe('FormulaResult', () => {
let ctx: Awaited>
beforeAll(async () => {
jest.useRealTimers()
ctx = await makeContext(input.options)
jest.clearAllTimers()
+
+ const editor = mockEditor({
+ extensionManager: {
+ extensions: [{ name: Formula.name, options: { formulaContext: ctx.formulaContext } }]
+ }
+ })
+
+ jest.spyOn(editorHooks, 'useEditorContext').mockImplementation(() => ({ editor, documentEditable: true }))
})
it.each(testCases)('$jestTitle', async args => {
diff --git a/packages/editor/src/components/ui/Formula/__tests__/FormulaValue.test.tsx b/packages/editor/src/components/ui/Formula/__tests__/FormulaValue.test.tsx
index 75610adb2..de2764d90 100644
--- a/packages/editor/src/components/ui/Formula/__tests__/FormulaValue.test.tsx
+++ b/packages/editor/src/components/ui/Formula/__tests__/FormulaValue.test.tsx
@@ -1,15 +1,31 @@
import { render } from '@testing-library/react'
import { buildTestCases, dumpDisplayResultForDisplay, makeContext } from '@mashcard/formula'
import { FormulaValue } from '../FormulaValue'
+import { mockEditor } from '../../../../test'
+import { Formula } from '../../../../extensions'
+import * as editorHooks from '../../../../hooks/useEditorContext'
const [input] = buildTestCases(['basic'])
+jest.mock('../../../../hooks/useEditorContext', () => {
+ const { useEditorContext } = jest.requireActual('../../../../hooks/useEditorContext')
+ return { useEditorContext: jest.fn().mockImplementation(useEditorContext) }
+})
+
describe('FormulaValue', () => {
let ctx: Awaited>
beforeAll(async () => {
jest.useRealTimers()
ctx = await makeContext(input.options)
jest.clearAllTimers()
+
+ const editor = mockEditor({
+ extensionManager: {
+ extensions: [{ name: Formula.name, options: { formulaContext: ctx.formulaContext } }]
+ }
+ })
+
+ jest.spyOn(editorHooks, 'useEditorContext').mockImplementation(() => ({ editor, documentEditable: true }))
})
it.each(input.basicTestCases)('$jestTitle', async args => {
diff --git a/packages/editor/src/helpers/formula.ts b/packages/editor/src/helpers/formula.ts
index b6dd618f3..3846b85a4 100644
--- a/packages/editor/src/helpers/formula.ts
+++ b/packages/editor/src/helpers/formula.ts
@@ -1,5 +1,6 @@
-import { CodeFragmentWithIndex } from '@mashcard/formula'
+import { CodeFragmentWithIndex, ErrorMessageType, I18N } from '@mashcard/formula'
import { JSONContent } from '@tiptap/core'
+import { TFunction } from 'react-i18next'
import { FormulaInput } from '../components/blockViews'
const maybeRemoveDefinitionEqual = (definition: string | undefined, formulaIsNormal: boolean): string => {
@@ -84,3 +85,13 @@ export const codeFragments2content = (
const contents = newCodeFragments.map(codeFragment => attrsToJSONContent(codeFragment))
return [buildJSONContentByArray(contents), newCodeFragments]
}
+
+export const formulaI18n =
+ (t: TFunction): I18N =>
+ (message: ErrorMessageType) => {
+ if (typeof message === 'string') {
+ return t(message)
+ } else {
+ return t(message[0], message[1])
+ }
+ }
diff --git a/packages/formula/src/__tests__/control.test.ts b/packages/formula/src/__tests__/control.test.ts
index 1e1c07f77..84be06700 100644
--- a/packages/formula/src/__tests__/control.test.ts
+++ b/packages/formula/src/__tests__/control.test.ts
@@ -15,12 +15,12 @@ const page: PageInput = {
describe('Controls', () => {
it('feature', async () => {
- const noFeatureCtx = await makeContext({ initializeOptions: { domain: 'test', features: [] }, pages: [page] })
+ const noFeatureCtx = await makeContext({ initializeOptions: { username: 'test', features: [] }, pages: [page] })
const input = `=Button("Foo", Set(#${namespaceId}.${testName1}, (1 + #${namespaceId}.${testName1})))`
const { errorMessages: errorMessage1 } = noFeatureCtx.parseDirectly({ definition: input, namespaceId })
expect(errorMessage1).toEqual([{ message: ['errors.parse.not_found.function', { key: 'Button' }], type: 'deps' }])
- const featureCtx = await makeContext({ initializeOptions: { domain: 'test' }, pages: [page] })
+ const featureCtx = await makeContext({ initializeOptions: { username: 'test' }, pages: [page] })
featureCtx.formulaContext.features = []
const { errorMessages: errorMessage2 } = featureCtx.parseDirectly({ definition: input, namespaceId })
expect(errorMessage2).toEqual([{ message: 'Feature formula-controls not enabled', type: 'deps' }])
diff --git a/packages/formula/src/__tests__/event.test.ts b/packages/formula/src/__tests__/event.test.ts
index e019201ae..4b0899b49 100644
--- a/packages/formula/src/__tests__/event.test.ts
+++ b/packages/formula/src/__tests__/event.test.ts
@@ -13,7 +13,7 @@ describe('event', () => {
ctx = await makeContext({
...input.options,
uuidFunction: index => uuid(),
- initializeOptions: { domain: uuid() }
+ initializeOptions: { username: uuid() }
})
})
diff --git a/packages/formula/src/__tests__/formulas.test.ts b/packages/formula/src/__tests__/formulas.test.ts
index 558b9d58e..370dbd827 100644
--- a/packages/formula/src/__tests__/formulas.test.ts
+++ b/packages/formula/src/__tests__/formulas.test.ts
@@ -4,7 +4,7 @@ import { FormulaContext } from '../context/context'
describe('appendFormulas TODO', () => {
it('constant', async () => {
- const formulaContext = new FormulaContext({ domain: 'test' })
+ const formulaContext = new FormulaContext({ username: 'test' })
await appendFormulas(formulaContext, [])
expect(formulaContext.variables).toEqual({})
@@ -40,7 +40,7 @@ describe('appendFormulas TODO', () => {
})
it('parse error', async () => {
- const formulaContext = new FormulaContext({ domain: 'test' })
+ const formulaContext = new FormulaContext({ username: 'test' })
await appendFormulas(formulaContext, [])
expect(formulaContext.variables).toEqual({})
diff --git a/packages/formula/src/__tests__/grammar.test.ts b/packages/formula/src/__tests__/grammar.test.ts
index 25c0d9b93..7dd4ae106 100644
--- a/packages/formula/src/__tests__/grammar.test.ts
+++ b/packages/formula/src/__tests__/grammar.test.ts
@@ -140,7 +140,7 @@ describe('Simple test case TODO', () => {
if (value !== undefined) {
const variableValue = await innerInterpret({ parseResult, ctx: { ...ctx, meta: newMeta } })
- const displayResult = displayF(variableValue.result)
+ const displayResult = displayF(variableValue.result, ctx.formulaContext)
expect(errorMessages).toEqual([])
diff --git a/packages/formula/src/__tests__/persist.test.ts b/packages/formula/src/__tests__/persist.test.ts
index 471f32fce..552875a89 100644
--- a/packages/formula/src/__tests__/persist.test.ts
+++ b/packages/formula/src/__tests__/persist.test.ts
@@ -176,7 +176,7 @@ const cells: Cell[] = [
}
]
-const formulaContext = FormulaContext.getInstance({ domain: 'test' })
+const formulaContext = FormulaContext.getFormulaInstance({ username: 'test' })
void dispatchFormulaBlockNameChange({ id: namespaceId, name: 'Page1', username: 'test' })
const spreadsheet: SpreadsheetType = new SpreadsheetClass({
@@ -351,6 +351,28 @@ const testCases: {
testCase: { type: 'Error', result: { message: 'bang!', type: 'runtime' } },
displayResult: { type: 'Error', result: '# bang!' },
dumpResult: { type: 'Error', result: { message: 'bang!', type: 'runtime' } }
+ },
+ {
+ testCase: {
+ type: 'Error',
+ result: { message: 'errors.interpret.runtime.division_by_zero', type: 'runtime' }
+ },
+ displayResult: { type: 'Error', result: '# errors.interpret.runtime.division_by_zero' },
+ dumpResult: {
+ type: 'Error',
+ result: { message: 'errors.interpret.runtime.division_by_zero', type: 'runtime' }
+ }
+ },
+ {
+ testCase: {
+ type: 'Error',
+ result: { message: ['errors.interpret.not_found.key', { key: 'foo' }], type: 'runtime' }
+ },
+ displayResult: { type: 'Error', result: '# errors.interpret.not_found.key {"key":"foo"}' },
+ dumpResult: {
+ type: 'Error',
+ result: { message: ['errors.interpret.not_found.key', { key: 'foo' }], type: 'runtime' }
+ }
}
],
Array: [
@@ -452,7 +474,7 @@ describe('persist', () => {
expect(castedValue).toMatchObject(castedResult)
}
- const displayValue = display(testCase)
+ const displayValue = display(testCase, formulaContext)
if (displayResult !== null) {
// eslint-disable-next-line jest/no-conditional-expect
expect(displayValue).toEqual(displayResult)
diff --git a/packages/formula/src/context/context.ts b/packages/formula/src/context/context.ts
index 3e4cbb936..fea20d10f 100644
--- a/packages/formula/src/context/context.ts
+++ b/packages/formula/src/context/context.ts
@@ -11,6 +11,7 @@ import {
SpreadsheetReloadViaId
} from '../events'
import { buildFunctionKey, BUILTIN_CLAUSES } from '../functions'
+import { defaultI18n } from '../grammar'
import { CodeFragmentVisitor } from '../grammar/codeFragment'
import {
block2completion,
@@ -45,6 +46,7 @@ import {
FunctionGroup,
FunctionKey,
FunctionNameType,
+ I18N,
NameDependencyWithKind,
NamespaceId,
SpreadsheetCompletion,
@@ -63,7 +65,8 @@ import { FORMULA_FEATURE_CONTROL } from './features'
import { dumpDisplayResultForDisplay } from './persist'
export interface FormulaContextArgs {
- domain: string
+ username: string
+ i18n?: I18N
tickTimeout?: number
functionClauses?: AnyFunctionClause[]
backendActions?: BackendActions
@@ -74,9 +77,10 @@ export type ContextState = any
export class FormulaContext implements ContextInterface {
private static instance?: FormulaContext
- domain: string
+ options: FormulaContextArgs
+ username: string
+ i18n: I18N
tickKey: string
- tickTimeout: number
features: Features
dirtyFormulas: Record = {}
variables: Record = {}
@@ -90,25 +94,20 @@ export class FormulaContext implements ContextInterface {
reverseVariableDependencies: Record = {}
reverseFunctionDependencies: Record = {}
functionClausesMap: Record = {}
- backendActions: BackendActions | undefined
reservedNames: string[] = []
eventListeners: EventSubscribed[] = []
variableNameStore: typeof variableNameStore = variableNameStore
- constructor({
- domain,
- tickTimeout,
- functionClauses = [],
- backendActions,
- features = [FORMULA_FEATURE_CONTROL]
- }: FormulaContextArgs) {
- this.domain = domain
- this.tickTimeout = tickTimeout ?? 1000
- this.tickKey = `FormulaContext#${domain}`
+ constructor(options: FormulaContextArgs) {
+ this.options = options
+
+ const { username, i18n, functionClauses = [], features = [FORMULA_FEATURE_CONTROL] } = options
+
+ this.username = username
+ this.tickKey = `FormulaContext#${username}`
this.features = features
- if (backendActions) {
- this.backendActions = backendActions
- }
+
+ this.i18n = i18n ?? defaultI18n
this.viewRenders = DEFAULT_VIEWS.reduce((o: Record, acc: View) => {
o[acc.type] = acc.render
@@ -120,7 +119,7 @@ export class FormulaContext implements ContextInterface {
async e => {
await this.setBlock(e.payload.id, e.payload.meta)
},
- { subscribeId: `Domain#${this.domain}`, eventId: this.domain }
+ { subscribeId: `Domain#${this.username}`, eventId: this.username }
)
this.eventListeners.push(blockNameSubscription)
@@ -130,10 +129,7 @@ export class FormulaContext implements ContextInterface {
async e => {
await this.tick(e.payload.state)
},
- {
- eventId: this.tickKey,
- subscribeId: `Domain#${this.domain}`
- }
+ { eventId: this.tickKey, subscribeId: `Domain#${this.username}` }
)
this.eventListeners.push(tickSubscription)
@@ -180,7 +176,10 @@ export class FormulaContext implements ContextInterface {
public async invoke(name: string, ctx: FunctionContext, ...args: any[]): Promise {
const clause = this.functionClausesMap[name]
if (!clause) {
- return { type: 'Error', result: { message: ['errors.parse.not_found.function', { key: name }], type: 'fatal' } }
+ return {
+ type: 'Error',
+ result: { message: ['errors.parse.not_found.function', { key: name }], type: 'fatal' }
+ }
}
return await (clause.reference as (ctx: FunctionContext, ...args: any[]) => Promise)(ctx, ...args)
@@ -277,7 +276,7 @@ export class FormulaContext implements ContextInterface {
id: nameDependency.id,
namespaceId: nameDependency.namespaceId,
key: nameDependency.id,
- username: this.domain,
+ username: this.username,
scope: null,
meta: {
name: nameDependency.name,
@@ -299,7 +298,7 @@ export class FormulaContext implements ContextInterface {
id: oldName.id,
namespaceId: oldName.namespaceId,
key: oldName.id,
- username: this.domain,
+ username: this.username,
scope: null,
meta: {
name: oldName.name,
@@ -341,7 +340,7 @@ export class FormulaContext implements ContextInterface {
SpreadsheetReloadViaId({
id: spreadsheet.spreadsheetId,
namespaceId: spreadsheet.namespaceId,
- username: this.domain,
+ username: this.username,
scope: null,
meta: null,
key: spreadsheet.spreadsheetId
@@ -435,12 +434,12 @@ export class FormulaContext implements ContextInterface {
private async tick(state: ContextState): Promise {
await this.commitDirty()
const newState = state
- await new Promise(resolve => setTimeout(resolve, this.tickTimeout))
- MashcardEventBus.dispatch(FormulaContextTickTrigger({ domain: this.domain, state: newState }))
+ await new Promise(resolve => setTimeout(resolve, this.options.tickTimeout))
+ MashcardEventBus.dispatch(FormulaContextTickTrigger({ username: this.username, state: newState }))
}
private async commitDirty(): Promise {
- if (!this.backendActions) {
+ if (!this.options.backendActions) {
this.dirtyFormulas = {}
return
}
@@ -458,8 +457,8 @@ export class FormulaContext implements ContextInterface {
}
})
if (commitFormulas.length > 0 || deleteFormulas.length > 0) {
- // console.log('commit dirty', commitFormulas, deleteFormulas, this.backendActions)
- const { success } = await this.backendActions.commit(commitFormulas, deleteFormulas)
+ // console.log('commit dirty', commitFormulas, deleteFormulas, this.options.backendActions)
+ const { success } = await this.options.backendActions.commit(commitFormulas, deleteFormulas)
if (success) {
this.dirtyFormulas = {}
} else {
@@ -492,7 +491,7 @@ export class FormulaContext implements ContextInterface {
return codeFragments.map((c, index) => ({ ...c, index }))
}
- public static getInstance(args: FormulaContextArgs): FormulaContext {
+ public static getFormulaInstance(args: FormulaContextArgs): FormulaContext {
if (this.instance === undefined) {
this.instance = new FormulaContext(args)
}
diff --git a/packages/formula/src/context/persist.ts b/packages/formula/src/context/persist.ts
index 962521af4..b98b81520 100644
--- a/packages/formula/src/context/persist.ts
+++ b/packages/formula/src/context/persist.ts
@@ -42,8 +42,9 @@ export const cast = ,
}
export const display = , Display extends AnyDisplayResult>(
- v: Value
+ v: Value,
+ ctx: ContextInterface
): Display => {
- const result: any = FormulaAttributes[v.type].display(v as any, display)
+ const result: any = FormulaAttributes[v.type].display(v as any, ctx, display)
return result
}
diff --git a/packages/formula/src/context/task.ts b/packages/formula/src/context/task.ts
index 314793ec8..3e4794eaf 100644
--- a/packages/formula/src/context/task.ts
+++ b/packages/formula/src/context/task.ts
@@ -48,7 +48,7 @@ export const createVariableTask = ({
void variableValue.then(async value => {
const newTask: VariableTask = { ...task, variableValue: value, execEndTime: new Date(), async: false }
const result = MashcardEventBus.dispatch(
- FormulaTaskCompleted({ task: newTask, namespaceId, variableId, username: formulaContext.domain })
+ FormulaTaskCompleted({ task: newTask, namespaceId, variableId, username: formulaContext.username })
)
await Promise.all(result)
})
diff --git a/packages/formula/src/context/variable.ts b/packages/formula/src/context/variable.ts
index 69a7063b4..89bee5979 100644
--- a/packages/formula/src/context/variable.ts
+++ b/packages/formula/src/context/variable.ts
@@ -137,7 +137,7 @@ export class VariableClass implements VariableInterface {
await this.completeTask(e.payload)
},
{
- eventId: `${formulaContext.domain}#${t.meta.namespaceId},${t.meta.variableId}`,
+ eventId: `${formulaContext.username}#${t.meta.namespaceId},${t.meta.variableId}`,
subscribeId: `Task#${t.meta.namespaceId},${t.meta.variableId}`
}
)
@@ -150,7 +150,7 @@ export class VariableClass implements VariableInterface {
meta: this,
scope: null,
key: this.id,
- username: this.formulaContext.domain,
+ username: this.formulaContext.username,
level,
namespaceId: this.t.meta.namespaceId,
id: this.t.meta.variableId
@@ -220,7 +220,7 @@ export class VariableClass implements VariableInterface {
meta: newVariableDependencies,
scope: null,
key: this.id,
- username: this.formulaContext.domain,
+ username: this.formulaContext.username,
level: 0,
namespaceId: dependency.namespaceId,
id: dependency.variableId
@@ -279,7 +279,7 @@ export class VariableClass implements VariableInterface {
meta: newVariableDependencies,
scope: null,
key: this.id,
- username: this.formulaContext.domain,
+ username: this.formulaContext.username,
level: 0,
namespaceId: dependency.namespaceId,
id: dependency.variableId
@@ -482,7 +482,7 @@ export class VariableClass implements VariableInterface {
> = {
kind: 'BlockRename',
event: FormulaBlockNameChangedTrigger,
- eventId: `${this.formulaContext.domain}#${blockId}`,
+ eventId: `${this.formulaContext.username}#${blockId}`,
scope: {},
key: `BlockRename#${blockId}`,
definitionHandler: (deps, variable, payload) => {
@@ -499,7 +499,7 @@ export class VariableClass implements VariableInterface {
> = {
kind: 'BlockDelete',
event: FormulaBlockNameDeletedTrigger,
- eventId: `${this.formulaContext.domain}#${blockId}`,
+ eventId: `${this.formulaContext.username}#${blockId}`,
scope: {},
key: `BlockDelete#${blockId}`
}
@@ -513,7 +513,7 @@ export class VariableClass implements VariableInterface {
> = {
kind: 'NameChange',
event: FormulaContextNameChanged,
- eventId: `${this.formulaContext.domain}#${namespaceId}#${name}`,
+ eventId: `${this.formulaContext.username}#${namespaceId}#${name}`,
scope: {},
key: `OtherNameChange#${namespaceId}#${name}`,
skipIf: (variable, payload) => variable.isReadyT
@@ -525,7 +525,7 @@ export class VariableClass implements VariableInterface {
> = {
kind: 'NameChange',
event: FormulaContextNameChanged,
- eventId: `${this.formulaContext.domain}#$Block#${name}`,
+ eventId: `${this.formulaContext.username}#$Block#${name}`,
scope: {},
key: `BlockNameChange#${namespaceId}#${name}`,
skipIf: (variable, payload) => variable.isReadyT
@@ -538,7 +538,7 @@ export class VariableClass implements VariableInterface {
> = {
kind: 'NameRemove',
event: FormulaContextNameRemove,
- eventId: `${this.formulaContext.domain}#${namespaceId}#${name}`,
+ eventId: `${this.formulaContext.username}#${namespaceId}#${name}`,
scope: {},
key: `OtherNameRemove#${namespaceId}#${name}`,
skipIf: (variable, payload) => !variable.isReadyT
diff --git a/packages/formula/src/controls/block.ts b/packages/formula/src/controls/block.ts
index d33ccc3ff..7955b2f2d 100644
--- a/packages/formula/src/controls/block.ts
+++ b/packages/formula/src/controls/block.ts
@@ -41,7 +41,7 @@ export class BlockClass implements BlockType {
this._name = e.payload.meta
await this._formulaContext.setName(this.nameDependency())
},
- { subscribeId: `Block#${this.id}`, eventId: `${this._formulaContext.domain}#${this.id}` }
+ { subscribeId: `Block#${this.id}`, eventId: `${this._formulaContext.username}#${this.id}` }
)
const blockDeleteSubcription = MashcardEventBus.subscribe(
@@ -49,7 +49,7 @@ export class BlockClass implements BlockType {
async e => {
await this._formulaContext.removeBlock(this.id)
},
- { subscribeId: `Block#${this.id}`, eventId: `${this._formulaContext.domain}#${this.id}` }
+ { subscribeId: `Block#${this.id}`, eventId: `${this._formulaContext.username}#${this.id}` }
)
this.eventListeners.push(blockNameSubscription, blockDeleteSubcription)
@@ -86,7 +86,7 @@ export class BlockClass implements BlockType {
id: this.id,
namespaceId: this.id,
key: this.id,
- username: this._formulaContext.domain,
+ username: this._formulaContext.username,
scope: null,
meta: this._name
})
diff --git a/packages/formula/src/controls/cell.ts b/packages/formula/src/controls/cell.ts
index 72aa4e981..56941e437 100644
--- a/packages/formula/src/controls/cell.ts
+++ b/packages/formula/src/controls/cell.ts
@@ -52,7 +52,7 @@ export class CellClass implements CellType {
getValue(): string {
const displayData = this.spreadsheet.findCellDisplayData({ rowId: this.rowId, columnId: this.columnId })
if (displayData) {
- return display(displayData.result).result
+ return display(displayData.result, this.spreadsheet._formulaContext).result
}
return this.value
}
diff --git a/packages/formula/src/controls/spreadsheet.ts b/packages/formula/src/controls/spreadsheet.ts
index e3bd16109..a025a5090 100644
--- a/packages/formula/src/controls/spreadsheet.ts
+++ b/packages/formula/src/controls/spreadsheet.ts
@@ -111,7 +111,7 @@ export class SpreadsheetClass implements SpreadsheetType {
await this._formulaContext.setName(this.nameDependency())
},
{
- eventId: `${this._formulaContext.domain}#${namespaceId},${spreadsheetId}`,
+ eventId: `${this._formulaContext.username}#${namespaceId},${spreadsheetId}`,
subscribeId: `Spreadsheet#${spreadsheetId}`
}
)
@@ -122,7 +122,7 @@ export class SpreadsheetClass implements SpreadsheetType {
async e => {
await this._formulaContext.removeSpreadsheet(spreadsheetId)
},
- { eventId: `${this._formulaContext.domain}#${spreadsheetId}`, subscribeId: `Spreadsheet#${spreadsheetId}` }
+ { eventId: `${this._formulaContext.username}#${spreadsheetId}`, subscribeId: `Spreadsheet#${spreadsheetId}` }
)
this.eventListeners.push(spreadsheetDeleteSubcription)
@@ -144,7 +144,7 @@ export class SpreadsheetClass implements SpreadsheetType {
const result = MashcardEventBus.dispatch(
SpreadsheetReloadViaId({
id: this.spreadsheetId,
- username: this._formulaContext.domain,
+ username: this._formulaContext.username,
scope: { columns: changedColumnIds },
namespaceId: this.namespaceId,
key: this.spreadsheetId,
@@ -154,7 +154,7 @@ export class SpreadsheetClass implements SpreadsheetType {
await Promise.all(result)
},
{
- eventId: `${this._formulaContext.domain}#${namespaceId},${spreadsheetId}`,
+ eventId: `${this._formulaContext.username}#${namespaceId},${spreadsheetId}`,
subscribeId: `Spreadsheet#${spreadsheetId}`
}
)
@@ -179,7 +179,7 @@ export class SpreadsheetClass implements SpreadsheetType {
const result = MashcardEventBus.dispatch(
SpreadsheetReloadViaId({
id: this.spreadsheetId,
- username: this._formulaContext.domain,
+ username: this._formulaContext.username,
scope: { rows: changedRowIds },
namespaceId: this.namespaceId,
key: this.spreadsheetId,
@@ -189,7 +189,7 @@ export class SpreadsheetClass implements SpreadsheetType {
await Promise.all(result)
},
{
- eventId: `${this._formulaContext.domain}#${namespaceId},${spreadsheetId}`,
+ eventId: `${this._formulaContext.username}#${namespaceId},${spreadsheetId}`,
subscribeId: `Spreadsheet#${spreadsheetId}`
}
)
@@ -450,7 +450,7 @@ export class SpreadsheetClass implements SpreadsheetType {
}
const displayData = this._formulaContext.findVariableDisplayDataById(this.namespaceId, cell.variableId)
- if (displayData) return display(displayData.result).result
+ if (displayData) return display(displayData.result, this._formulaContext).result
return cell.value
}
diff --git a/packages/formula/src/controls/types.ts b/packages/formula/src/controls/types.ts
index a7eadde9f..77729eded 100644
--- a/packages/formula/src/controls/types.ts
+++ b/packages/formula/src/controls/types.ts
@@ -190,6 +190,7 @@ export interface SpreadsheetAllPersistence {
}
export interface SpreadsheetType {
+ _formulaContext: ContextInterface
spreadsheetId: SpreadsheetId
namespaceId: NamespaceId
namespaceName: (pageId: NamespaceId) => string
diff --git a/packages/formula/src/events/inner.ts b/packages/formula/src/events/inner.ts
index 1925554ec..17d1f502c 100644
--- a/packages/formula/src/events/inner.ts
+++ b/packages/formula/src/events/inner.ts
@@ -23,10 +23,10 @@ export const FormulaContextNameRemove = event>()(
+export const FormulaContextTickTrigger = event<{ username: string; state: ContextState }, Promise>()(
'FormulaContextTickTrigger',
- ({ domain, state }) => {
- return { id: `FormulaContext#${domain}` }
+ ({ username, state }) => {
+ return { id: `FormulaContext#${username}` }
}
)
diff --git a/packages/formula/src/grammar/codeFragment.ts b/packages/formula/src/grammar/codeFragment.ts
index feb6c7c0a..0b8eb1947 100644
--- a/packages/formula/src/grammar/codeFragment.ts
+++ b/packages/formula/src/grammar/codeFragment.ts
@@ -873,7 +873,10 @@ export class CodeFragmentVisitor extends CodeFragmentCstVisitor {
const clauseErrorMessages: ErrorMessage[] = []
if (!clause) {
- clauseErrorMessages.push({ message: ['errors.parse.not_found.function', { key: functionKey }], type: 'deps' })
+ clauseErrorMessages.push({
+ message: ['errors.parse.not_found.function', { key: functionKey }],
+ type: 'deps'
+ })
} else if (clause.feature && !this.ctx.formulaContext.features.includes(clause.feature)) {
clauseErrorMessages.push({ message: `Feature ${clause.feature} not enabled`, type: 'deps' })
}
diff --git a/packages/formula/src/grammar/dependency.ts b/packages/formula/src/grammar/dependency.ts
index 55df5f587..b32bb7221 100644
--- a/packages/formula/src/grammar/dependency.ts
+++ b/packages/formula/src/grammar/dependency.ts
@@ -42,7 +42,7 @@ export const parseTrackSpreadsheet = (visitor: Visitor, spreadsheet: Spreadsheet
const spreadsheetNameEventDependency: EventDependency<
typeof SpreadsheetUpdateNameViaId extends EventType ? X : never
> = {
- eventId: `${visitor.ctx.formulaContext.domain}#${spreadsheet.namespaceId},${spreadsheet.spreadsheetId}`,
+ eventId: `${visitor.ctx.formulaContext.username}#${spreadsheet.namespaceId},${spreadsheet.spreadsheetId}`,
event: SpreadsheetUpdateNameViaId,
kind: 'SpreadsheetName',
key: `SpreadsheetName#${spreadsheet.spreadsheetId}`,
diff --git a/packages/formula/src/grammar/operations/access.ts b/packages/formula/src/grammar/operations/access.ts
index fe3303f03..c0f0cf9d3 100644
--- a/packages/formula/src/grammar/operations/access.ts
+++ b/packages/formula/src/grammar/operations/access.ts
@@ -27,7 +27,10 @@ export const accessAttribute = async (
if (value) {
return value
} else {
- return { type: 'Error', result: { message: ['errors.interpret.not_found.key', { key }], type: 'runtime' } }
+ return {
+ type: 'Error',
+ result: { message: ['errors.interpret.not_found.key', { key }], type: 'runtime' }
+ }
}
}
diff --git a/packages/formula/src/grammar/operations/equalCompare.ts b/packages/formula/src/grammar/operations/equalCompare.ts
index a48adaf99..11f4e267b 100644
--- a/packages/formula/src/grammar/operations/equalCompare.ts
+++ b/packages/formula/src/grammar/operations/equalCompare.ts
@@ -34,7 +34,10 @@ export const equalCompareOperator: OperatorType = {
{ definition: '= 1 <> "a"', result: true },
{ definition: '= 4 > 3 = true', result: true },
{ definition: '= 2 * 2 > 3 != false', result: true },
- { definition: '= 3 = 1/0', result: { message: 'errors.interpret.runtime.division_by_zero', type: 'runtime' } }
+ {
+ definition: '= 3 = 1/0',
+ result: { message: 'errors.interpret.runtime.division_by_zero', type: 'runtime' }
+ }
],
errorTestCases: [
{
diff --git a/packages/formula/src/grammar/operations/multiplication.ts b/packages/formula/src/grammar/operations/multiplication.ts
index 8d994599e..dfbf15b16 100644
--- a/packages/formula/src/grammar/operations/multiplication.ts
+++ b/packages/formula/src/grammar/operations/multiplication.ts
@@ -18,7 +18,10 @@ export const multiplicationOperator: OperatorType = {
result = lhsResult * rhsResult
} else if (tokenMatcher(operator, Div)) {
if (rhsResult === 0) {
- return { type: 'Error', result: { message: 'errors.interpret.runtime.division_by_zero', type: 'runtime' } }
+ return {
+ type: 'Error',
+ result: { message: 'errors.interpret.runtime.division_by_zero', type: 'runtime' }
+ }
}
result = lhsResult / rhsResult
diff --git a/packages/formula/src/grammar/util.ts b/packages/formula/src/grammar/util.ts
index f785b3e5e..84c9d0077 100644
--- a/packages/formula/src/grammar/util.ts
+++ b/packages/formula/src/grammar/util.ts
@@ -11,7 +11,8 @@ import {
FormulaCheckType,
FormulaColorType,
FormulaType,
- FunctionContext
+ FunctionContext,
+ I18N
} from '../type'
import { InterpretArgument } from './interpreter'
import { checkValidName } from './lexer'
@@ -369,3 +370,8 @@ export const parseErrorMessage = (message: string): ErrorMessageType => {
const [msg, context] = JSON.parse(message.substring(PARSE_PREFIX_FLAG.length))
return [msg, context]
}
+
+export const defaultI18n: I18N = input => {
+ if (typeof input === 'string') return input
+ return `${input[0]} ${JSON.stringify(input[1])}`
+}
diff --git a/packages/formula/src/tests/feature/event/spreadsheetEvent.ts b/packages/formula/src/tests/feature/event/spreadsheetEvent.ts
index 97ad5ebda..b315e35f4 100644
--- a/packages/formula/src/tests/feature/event/spreadsheetEvent.ts
+++ b/packages/formula/src/tests/feature/event/spreadsheetEvent.ts
@@ -153,12 +153,12 @@ export const SpreadsheetEventTestCase: TestCaseInterface = {
triggerEvents: ctx => [
{
event: FormulaSpreadsheetDeleted,
- eventId: `${ctx.formulaContext.domain}#${spreadsheet1Id}`,
- payload: { id: spreadsheet1Id, username: ctx.formulaContext.domain }
+ eventId: `${ctx.formulaContext.username}#${spreadsheet1Id}`,
+ payload: { id: spreadsheet1Id, username: ctx.formulaContext.username }
},
{
event: FormulaContextNameRemove,
- eventId: `${ctx.formulaContext.domain}#${page0Id}#spreadsheet1foobar`
+ eventId: `${ctx.formulaContext.username}#${page0Id}#spreadsheet1foobar`
},
{
event: FormulaUpdatedViaId,
@@ -166,7 +166,7 @@ export const SpreadsheetEventTestCase: TestCaseInterface = {
},
{
event: FormulaContextNameChanged,
- eventId: `${ctx.formulaContext.domain}#${ctx.meta.namespaceId}#${ctx.meta.name}`,
+ eventId: `${ctx.formulaContext.username}#${ctx.meta.namespaceId}#${ctx.meta.name}`,
callLength: 0
}
],
@@ -179,12 +179,12 @@ export const SpreadsheetEventTestCase: TestCaseInterface = {
triggerEvents: ctx => [
{
event: FormulaSpreadsheetDeleted,
- eventId: `${ctx.formulaContext.domain}#${spreadsheet1Id}`,
- payload: { id: spreadsheet1Id, username: ctx.formulaContext.domain }
+ eventId: `${ctx.formulaContext.username}#${spreadsheet1Id}`,
+ payload: { id: spreadsheet1Id, username: ctx.formulaContext.username }
},
{
event: FormulaContextNameRemove,
- eventId: `${ctx.formulaContext.domain}#${page0Id}#spreadsheet1foobar`
+ eventId: `${ctx.formulaContext.username}#${page0Id}#spreadsheet1foobar`
},
{
event: FormulaUpdatedViaId,
@@ -192,7 +192,7 @@ export const SpreadsheetEventTestCase: TestCaseInterface = {
},
{
event: FormulaContextNameChanged,
- eventId: `${ctx.formulaContext.domain}#${ctx.meta.namespaceId}#${ctx.meta.name}`,
+ eventId: `${ctx.formulaContext.username}#${ctx.meta.namespaceId}#${ctx.meta.name}`,
callLength: 0
}
],
diff --git a/packages/formula/src/tests/feature/event/variableEvent.ts b/packages/formula/src/tests/feature/event/variableEvent.ts
index 81e790912..6937afff4 100644
--- a/packages/formula/src/tests/feature/event/variableEvent.ts
+++ b/packages/formula/src/tests/feature/event/variableEvent.ts
@@ -65,14 +65,14 @@ export const VariableEventTestCase: TestCaseInterface = {
saveEvents: ctx => [
{
event: FormulaVariableDependencyUpdated,
- eventId: `${ctx.formulaContext.domain}#${page0Id},${variableId}`,
+ eventId: `${ctx.formulaContext.username}#${page0Id},${variableId}`,
payload: { meta: [{ namespaceId: page0Id, variableId: dependencyVariableId }], id: variableId }
}
],
triggerEvents: ctx => [
{
event: FormulaVariableDependencyUpdated,
- eventId: `${ctx.formulaContext.domain}#${page0Id},${variableId}`,
+ eventId: `${ctx.formulaContext.username}#${page0Id},${variableId}`,
payload: { meta: [], id: variableId }
}
]
diff --git a/packages/formula/src/tests/feature/functionCall.ts b/packages/formula/src/tests/feature/functionCall.ts
index 1e45dbda1..ad55c94c8 100644
--- a/packages/formula/src/tests/feature/functionCall.ts
+++ b/packages/formula/src/tests/feature/functionCall.ts
@@ -46,7 +46,10 @@ export const FunctionCallTestCase: TestCaseInterface = {
testCases: {
functionClauses,
successTestCases: [
- { definition: '= ABS(1/0)', result: { message: 'errors.interpret.runtime.division_by_zero', type: 'runtime' } },
+ {
+ definition: '= ABS(1/0)',
+ result: { message: 'errors.interpret.runtime.division_by_zero', type: 'runtime' }
+ },
{
definition: '=Abs(-1) + abs(1) + ABS(1) + core::ABS(-1)',
result: 4,
@@ -183,8 +186,16 @@ export const FunctionCallTestCase: TestCaseInterface = {
errorMessage: 'errors.parse.missing.closing_parenthesis',
groupOptions: [{ name: 'basicError' }]
},
- { definition: '=POWER(1,', errorType: 'syntax', errorMessage: 'errors.parse.missing.closing_parenthesis' },
- { definition: '=POWER(1,2', errorType: 'syntax', errorMessage: 'errors.parse.missing.closing_parenthesis' },
+ {
+ definition: '=POWER(1,',
+ errorType: 'syntax',
+ errorMessage: 'errors.parse.missing.closing_parenthesis'
+ },
+ {
+ definition: '=POWER(1,2',
+ errorType: 'syntax',
+ errorMessage: 'errors.parse.missing.closing_parenthesis'
+ },
{
definition: '=custom::FORTY_TWO(1, 1, 1)',
errorType: 'deps',
diff --git a/packages/formula/src/tests/testCases.ts b/packages/formula/src/tests/testCases.ts
index e653423e3..569dc2353 100644
--- a/packages/formula/src/tests/testCases.ts
+++ b/packages/formula/src/tests/testCases.ts
@@ -120,7 +120,7 @@ const reduceTestCaseInput = (testCases: TestCaseInterface[]): TestCaseInput => {
]
}),
{
- options: { pages: [{ pageName: 'Default' }], initializeOptions: { domain: 'test' } },
+ options: { pages: [{ pageName: 'Default' }], initializeOptions: { username: 'test' } },
successTestCases: [],
completeTestCases: [],
formatTestCases: [],
diff --git a/packages/formula/src/tests/testEvent.ts b/packages/formula/src/tests/testEvent.ts
index 5789b63f3..fd0dca998 100644
--- a/packages/formula/src/tests/testEvent.ts
+++ b/packages/formula/src/tests/testEvent.ts
@@ -36,17 +36,17 @@ export const AllowEvents = {
empty_sync: (ctx: ExtendedCtx, args: any) => {},
empty_async: async (ctx: ExtendedCtx, args: any) => {},
blockChangeName: async (ctx: ExtendedCtx, args: OmitUsername) =>
- await dispatchFormulaBlockNameChange({ ...args, username: ctx.formulaContext.domain }),
+ await dispatchFormulaBlockNameChange({ ...args, username: ctx.formulaContext.username }),
blockDelete: async (ctx: ExtendedCtx, args: OmitUsername) =>
- await dispatchFormulaBlockSoftDelete({ ...args, username: ctx.formulaContext.domain }),
+ await dispatchFormulaBlockSoftDelete({ ...args, username: ctx.formulaContext.username }),
spreadsheetChangeName: async (ctx: ExtendedCtx, args: OmitUsername) =>
- await dispatchFormulaSpreadsheetNameChange({ ...args, username: ctx.formulaContext.domain }),
+ await dispatchFormulaSpreadsheetNameChange({ ...args, username: ctx.formulaContext.username }),
spreadsheetDelete: async (ctx: ExtendedCtx, args: OmitUsername) =>
- await dispatchFormulaSpreadsheetRemove({ ...args, username: ctx.formulaContext.domain }),
+ await dispatchFormulaSpreadsheetRemove({ ...args, username: ctx.formulaContext.username }),
columnChange: async (ctx: ExtendedCtx, args: OmitUsername) =>
- await dispatchFormulaSpreadsheetColumnChange({ ...args, username: ctx.formulaContext.domain }),
+ await dispatchFormulaSpreadsheetColumnChange({ ...args, username: ctx.formulaContext.username }),
rowChange: async (ctx: ExtendedCtx, args: OmitUsername) =>
- await dispatchFormulaSpreadsheetRowChange({ ...args, username: ctx.formulaContext.domain }),
+ await dispatchFormulaSpreadsheetRowChange({ ...args, username: ctx.formulaContext.username }),
variableInsertOnly: async (ctx: ExtendedCtx, args: Parameters[1]) =>
await variableInsertOnlyEvent(ctx, args),
variableInsertAndAwait: async (ctx: ExtendedCtx, args: Parameters[1]) =>
diff --git a/packages/formula/src/tests/testHelper.ts b/packages/formula/src/tests/testHelper.ts
index 63aa172c0..1a86dc038 100644
--- a/packages/formula/src/tests/testHelper.ts
+++ b/packages/formula/src/tests/testHelper.ts
@@ -167,7 +167,7 @@ const buildSpreadsheet = (
]
}
-const defaultInitializeOptions: FormulaContextArgs = { domain: 'test' }
+const defaultInitializeOptions: FormulaContextArgs = { username: 'test' }
export const makeContext = async (options: MakeContextOptions): Promise => {
let uuidState: UUIDState = { uuidFunction: options.uuidFunction ?? DEFAULT_UUID_FUNCTION, counter: 0, cache: {} }
@@ -183,7 +183,7 @@ export const makeContext = async (options: MakeContextOptions): Promise [...Array(20)].map(() => uuid())
export const buildEvent = (input: Args): ((ctx: ExtendedCtx) => Promise) => {
return async ctx => {
for (const [f, args] of input) {
- await AllowEvents[f](ctx, { ...args, username: ctx.formulaContext.domain } as any)
+ await AllowEvents[f](ctx, { ...args, username: ctx.formulaContext.username } as any)
}
}
}
diff --git a/packages/formula/src/type/index.ts b/packages/formula/src/type/index.ts
index 957a81304..609fa0118 100644
--- a/packages/formula/src/type/index.ts
+++ b/packages/formula/src/type/index.ts
@@ -145,7 +145,11 @@ export interface FormulaTypeAttributes<
type: Type
shortName: ShortName
dump: (result: Value, dumpF: (o: AnyTypeResult) => any) => Dump
- display: (result: Value, displayF: (o: AnyTypeResult) => Display) => Display
+ display: (
+ result: Value,
+ ctx: ContextInterface,
+ displayF: (o: AnyTypeResult, ctx: ContextInterface) => Display
+ ) => Display
cast: (
dump: Dump,
ctx: ContextInterface,
@@ -363,7 +367,8 @@ export interface FindKey {
}
export interface ContextInterface {
- domain: string
+ username: string
+ i18n: I18N
features: string[]
dirtyFormulas: Record
checkName: (name: string, namespaceId: NamespaceId, variableId: VariableId) => ErrorMessage | undefined
@@ -371,7 +376,6 @@ export interface ContextInterface {
reverseVariableDependencies: Record
reverseFunctionDependencies: Record
invoke: (name: FunctionNameType, ctx: FunctionContext, ...args: any[]) => Promise
- backendActions: BackendActions | undefined
variableCount: () => number
getDefaultVariableName: (namespaceId: NamespaceId, type: FormulaType) => string
completions: (namespaceId: NamespaceId, variableId: VariableId | undefined) => Completion[]
@@ -783,3 +787,5 @@ export interface ErrorMessage {
readonly message: ErrorMessageType
readonly type: ErrorType
}
+
+export type I18N = (input: ErrorMessageType) => string
diff --git a/packages/formula/src/types/array.ts b/packages/formula/src/types/array.ts
index 54ce490ea..e0eef6744 100644
--- a/packages/formula/src/types/array.ts
+++ b/packages/formula/src/types/array.ts
@@ -14,5 +14,8 @@ export const FormulaArrayAttributes: FormulaTypeAttributes f(a, ctx))
return { ...rest, result: array, meta: extractSubType(array) }
},
- display: ({ result, meta, ...rest }, f) => ({ ...rest, result: `[${result.map(v => f(v).result).join('')}]` })
+ display: ({ result, meta, ...rest }, ctx, f) => ({
+ ...rest,
+ result: `[${result.map(v => f(v, ctx).result).join('')}]`
+ })
}
diff --git a/packages/formula/src/types/error.ts b/packages/formula/src/types/error.ts
index b20986325..8292ee576 100644
--- a/packages/formula/src/types/error.ts
+++ b/packages/formula/src/types/error.ts
@@ -23,6 +23,5 @@ export const FormulaErrorAttributes: FormulaTypeAttributes rest,
cast: rest => rest,
- // TODO add i18n to display
- display: ({ result, ...rest }) => ({ ...rest, result: `# ${result.message}` })
+ display: ({ result, ...rest }, ctx) => ({ ...rest, result: `# ${ctx.i18n(result.message)}` })
}
diff --git a/packages/formula/src/types/record.ts b/packages/formula/src/types/record.ts
index 186ef6030..c86f92c5c 100644
--- a/packages/formula/src/types/record.ts
+++ b/packages/formula/src/types/record.ts
@@ -20,8 +20,8 @@ export const FormulaRecordAttributes: FormulaTypeAttributes f(a, ctx))
return { ...rest, result: record, meta: extractSubType(Object.values(record)) }
},
- display: ({ result, meta, ...rest }, f) => {
- const recordArray = Object.entries(result).map(([key, value]) => `${key}: ${f(value).result}`)
+ display: ({ result, meta, ...rest }, ctx, f) => {
+ const recordArray = Object.entries(result).map(([key, value]) => `${key}: ${f(value, ctx).result}`)
const recordResult = recordArray.join(', ')
return { ...rest, result: `{${recordResult}}` }
}