Skip to content
This repository has been archived by the owner on Feb 16, 2024. It is now read-only.

Commit

Permalink
feat: pass the parser function to error handler
Browse files Browse the repository at this point in the history
  • Loading branch information
brawaru committed Oct 10, 2023
1 parent e741506 commit 24c7efd
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 1 deletion.
11 changes: 10 additions & 1 deletion src/parser/error-handling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
type MessageFormatElement,
createLiteralElement,
type ParserOptions,
type parse,
} from '@formatjs/icu-messageformat-parser'

export type ParseErrorHandlerResult = MessageFormatElement[] | undefined | void
Expand Down Expand Up @@ -77,6 +78,9 @@ export interface ParseErrorContext {
/** Parser options that were used to parse the message. */
get parserOptions(): ParserOptions | undefined

/** Function that can be used to parse a custom message. */
get parseMessage(): typeof parse

/**
* Call one of the built-in error handling strategies.
*
Expand All @@ -95,7 +99,12 @@ export interface ParseErrorContext {
export function createParseErrorContext(
info: Pick<
ParseErrorContext,
'error' | 'moduleId' | 'message' | 'messageId' | 'parserOptions'
| 'error'
| 'moduleId'
| 'message'
| 'messageId'
| 'parserOptions'
| 'parseMessage'
>,
) {
const ctx = {
Expand Down
1 change: 1 addition & 0 deletions src/plugin/message-parsing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export function parseMessages(
message,
messageId,
parserOptions,
parseMessage,
}),
)

Expand Down
27 changes: 27 additions & 0 deletions test/__snapshots__/rollup.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,33 @@ export { example as default };
"
`;

exports[`rollup > should pass parsing fc to error handler 1`] = `
"const greeting = [
{
type: 0,
value: \\"Hello, <bold>\\"
},
{
type: 1,
value: \\"name\\"
},
{
type: 0,
value: \\"</bold!\\"
}
];
var messages = {
greeting: greeting
};
function example() {
return messages
}
export { example as default };
"
`;

exports[`rollup > should prevent json plugins if specified 1`] = `
"var type = 0;
var target = \\"World\\";
Expand Down
61 changes: 61 additions & 0 deletions test/__snapshots__/webpack.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,67 @@ const greeting = [
;// CONCATENATED MODULE: ./test/fixtures/errored/input.mjs
function example() {
return en_messages
}
var __webpack_exports__default = __webpack_exports__.Z;
export { __webpack_exports__default as default };
"
`;
exports[`webpack > should pass parsing fc to error handler 1`] = `
"/******/ // The require scope
/******/ var __webpack_require__ = {};
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
Z: () => (/* binding */ example)
});
;// CONCATENATED MODULE: ./test/fixtures/errored/en.messages.json
const greeting = [
{
type: 0,
value: \\"Hello, <bold>\\"
},
{
type: 1,
value: \\"name\\"
},
{
type: 0,
value: \\"</bold!\\"
}
];
/* harmony default export */ const en_messages = ({
greeting: greeting
});
;// CONCATENATED MODULE: ./test/fixtures/errored/input.mjs
function example() {
return en_messages
}
Expand Down
71 changes: 71 additions & 0 deletions test/rollup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,77 @@ describe('rollup', () => {
`)
})

it('should pass parsing fc to error handler', async () => {
const onParseError = vi.fn(function ({
message,
useBuiltinStrategy,
parseMessage,
parserOptions,
}) {
try {
return parseMessage(message, { ...parserOptions, ignoreTag: true })
} catch (e) {
return useBuiltinStrategy('use-message-as-literal')
}
} satisfies PluginOptions['onParseError'])

const { generate } = await rollup({
input: [
resolve(
dirname(fileURLToPath(import.meta.url)),
'fixtures/errored/input.mjs',
),
],
plugins: [
icuMessages({
format: 'crowdin',
parserOptions() {
return {
...this.getDefaultOptions(),
}
},
onParseError,
}),
],
})

const { output } = await generate({ format: 'esm' })

expect(output).toHaveLength(1)

expect(output[0]?.code).toMatchSnapshot()

expect(onParseError.mock.calls).toHaveLength(1)

const context = onParseError.mock.calls[0][0]

expect(context).toBeDefined()

const { parseMessage } = context

expect(parseMessage).toBeTypeOf('function')

expect(onParseError.mock.results[0]).toMatchInlineSnapshot(`
{
"type": "return",
"value": [
{
"type": 0,
"value": "Hello, <bold>",
},
{
"type": 1,
"value": "name",
},
{
"type": 0,
"value": "</bold!",
},
],
}
`)
})

it('exposes filter in public API', () => {
expect(icuMessages({}).api).toHaveProperty('filter')
})
Expand Down
50 changes: 50 additions & 0 deletions test/webpack.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,56 @@ describe(
}
`)
})

it('should pass parsing fc to error handler', async () => {
const onParseError = vi.fn(function ({
message,
useBuiltinStrategy,
parseMessage,
parserOptions,
}) {
try {
return parseMessage(message, { ...parserOptions, ignoreTag: true })
} catch (e) {
return useBuiltinStrategy('use-message-as-literal')
}
} satisfies _distWebpack.PluginOptions['onParseError'])

const out = await buildFile('fixtures/errored/input.mjs', (config) => {
;(config.plugins ??= []).push(
icuMessages({
format: 'crowdin',
onParseError,
}),
)
})

expect(out).toMatchSnapshot()

const { mock } = onParseError

expect(mock.calls?.[0]?.[0]?.parseMessage).toBeTypeOf('function')

expect(mock.results[0]).toMatchInlineSnapshot(`
{
"type": "return",
"value": [
{
"type": 0,
"value": "Hello, <bold>",
},
{
"type": 1,
"value": "name",
},
{
"type": 0,
"value": "</bold!",
},
],
}
`)
})
},
{ timeout: 60_000 },
)

0 comments on commit 24c7efd

Please sign in to comment.