From 21605d5f797a771a840125ecba07c181eba2dac1 Mon Sep 17 00:00:00 2001 From: Pavel Zhukov Date: Wed, 15 Apr 2026 18:12:07 +0300 Subject: [PATCH 1/9] fix: align eslint formatting with project stylistic --- README.md | 11 ++ packages/eslint-plugin-react-pug/README.md | 15 ++ packages/eslint-plugin-react-pug/src/index.ts | 97 +++++++++++-- .../test/integration/diagnostics.test.ts | 137 ++++++++++++++++++ .../test/unit/processor.test.ts | 49 ++++++- .../eslint/cat-profile-link.js.output.jsx | 10 +- .../eslint/cat-profile-link.tsx.output.jsx | 10 +- 7 files changed, 305 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index d7ae513..10d93b9 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,17 @@ export default [ ] ``` +ESLint processor behavior: + +- real JS/TS diagnostics inside Pug expression sites such as `#{...}`, `${...}`, `tag= ...`, attribute expressions, and inline handler/function bodies are mapped back to the original Pug source +- diagnostics that originate only from synthetic generated helper code are filtered out +- the processor formats against the project's own `@stylistic` package when available so generated JSX converges to the same style engine the outer ESLint run uses + +Current limitation: + +- purely formatting-only, auto-fixable source mistakes inside nested embedded-expression sites, especially `${...}`, can currently be normalized away by the generated-JSX formatting pass instead of being reported back as original-source style diagnostics +- autofixes and suggestions are currently not mapped back for files that contain transformed Pug regions, so transformed-region diagnostics are report-only today + ## VS Code Settings - `pugReact.enabled` diff --git a/packages/eslint-plugin-react-pug/README.md b/packages/eslint-plugin-react-pug/README.md index ce6c8ee..586816a 100644 --- a/packages/eslint-plugin-react-pug/README.md +++ b/packages/eslint-plugin-react-pug/README.md @@ -40,6 +40,21 @@ treats JS files as JSX-capable and you want to skip JSX auto-detection. Used `pug` import bindings are removed from the processor's transformed view automatically. +## Linting Contract + +The processor is designed to preserve useful JavaScript/TypeScript diagnostics inside Pug regions: + +- real JS/TS rule violations inside `#{...}`, `${...}`, `tag= ...`, attribute expressions, and inline handler/function bodies are reported back at the original Pug location +- diagnostics caused only by synthetic generated helper code are filtered out +- the formatter tries to converge to the consuming project's own `@stylistic` setup when that package is available locally + +Current limitation: + +- purely formatting-only, auto-fixable source mistakes inside nested expression sites such as `${...}` can be normalized away by the processor's generated-JSX formatting pass instead of being reported back as original-source indent/style diagnostics +- autofixes and suggestions are currently not mapped back for files that contain transformed Pug regions, so transformed-region diagnostics are report-only today + +That means semantic errors and real rule violations inside embedded JS should still surface, but some raw source-formatting mistakes inside embedded Pug expression blocks are not yet part of the processor's reported lint contract. + ## Exports - default ESLint plugin object diff --git a/packages/eslint-plugin-react-pug/src/index.ts b/packages/eslint-plugin-react-pug/src/index.ts index 3cd776e..d5abb37 100644 --- a/packages/eslint-plugin-react-pug/src/index.ts +++ b/packages/eslint-plugin-react-pug/src/index.ts @@ -18,8 +18,10 @@ import { type StartupjsCssxjsOption, } from '@react-pug/react-pug-core'; import { parse } from '@babel/parser'; +import { createRequire } from 'node:module'; +import { isAbsolute, resolve } from 'node:path'; import { Linter, SourceCode } from 'eslint'; -import stylisticPlugin from '@stylistic/eslint-plugin'; +import bundledStylisticPlugin from '@stylistic/eslint-plugin'; import prettier from '@prettier/sync'; const tsParser = require('@typescript-eslint/parser'); @@ -76,6 +78,7 @@ interface EslintProcessorLike { const FLAT_LINT_FILES = ['**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}']; const LEGACY_STYLE_HELPERS = new Set(['styl', 'css', 'sass', 'scss']); const LEGACY_STYLE_SUPPRESSED_RULES = new Set(['no-unused-expressions', 'no-unreachable']); +const stylisticPluginCache = new Map(); const FORMAT_RULE_CONFIG: any = { languageOptions: { ecmaVersion: 2022 as const, @@ -87,7 +90,7 @@ const FORMAT_RULE_CONFIG: any = { }, }, plugins: { - '@stylistic': stylisticPlugin, + '@stylistic': bundledStylisticPlugin, }, rules: { '@stylistic/indent': ['error', 2, { @@ -132,7 +135,10 @@ const FORMAT_RULE_CONFIG: any = { ], offsetTernaryExpressions: true, }], - '@stylistic/jsx-indent': ['error', 2], + '@stylistic/jsx-indent': ['error', 2, { + checkAttributes: false, + indentLogicalExpressions: true, + }], '@stylistic/jsx-indent-props': ['error', 2], '@stylistic/jsx-wrap-multilines': ['error', { declaration: 'parens-new-line', @@ -364,18 +370,12 @@ function normalizeSyntheticWrapperClosingIndent( } function applyFormatterLintPasses(text: string, filename: string): string { - const lintConfig: any[] = [{ - files: FLAT_LINT_FILES, - ...FORMAT_RULE_CONFIG, - ...(isTypeScriptLikeFilename(filename) - ? { - languageOptions: { - ...FORMAT_RULE_CONFIG.languageOptions, - parser: tsParser as any, - }, - } - : {}), - }]; + const lintConfig: any[] = getFormatterLintConfig(filename) + // We lint the generated, formatter-normalized JSX/TSX rather than the raw + // original Pug source. That keeps semantic diagnostics inside `${...}` blocks + // accurate and avoids transform-specific indent noise, but it also means + // purely formatting-only, auto-fixable source mistakes inside `${...}` are + // currently normalized away instead of being reported back to the user. const pretty = prettier.format(text, { parser: isTypeScriptLikeFilename(filename) ? 'babel-ts' : 'babel', semi: false, @@ -399,6 +399,61 @@ function applyFormatterLintPasses(text: string, filename: string): string { ).output; } +function getFormatterLintConfig(filename: string): any[] { + const stylisticPlugin = resolveStylisticPluginForFormatting(filename); + return [{ + files: FLAT_LINT_FILES, + ...FORMAT_RULE_CONFIG, + plugins: { + ...FORMAT_RULE_CONFIG.plugins, + '@stylistic': stylisticPlugin, + }, + ...(isTypeScriptLikeFilename(filename) + ? { + languageOptions: { + ...FORMAT_RULE_CONFIG.languageOptions, + parser: tsParser as any, + }, + } + : {}), + }]; +} + +function looksLikeStylisticPlugin(candidate: unknown): candidate is { rules: Record } { + return !!candidate && typeof candidate === 'object' && typeof (candidate as any).rules === 'object'; +} + +function getFormatterResolutionKey(filename: string): string { + return isAbsolute(filename) ? filename : resolve(process.cwd(), filename); +} + +function loadStylisticPluginFrom(request: NodeRequire): any | null { + try { + const resolved = request('@stylistic/eslint-plugin'); + return looksLikeStylisticPlugin(resolved) ? resolved : null; + } catch { + return null; + } +} + +function resolveStylisticPluginForFormatting(filename: string): any { + const resolutionKey = getFormatterResolutionKey(filename); + const cached = stylisticPluginCache.get(resolutionKey); + if (cached) return cached; + + const candidates = [resolutionKey, resolve(process.cwd(), '__react-pug-formatter__.js')]; + for (const candidate of candidates) { + const resolved = loadStylisticPluginFrom(createRequire(candidate)); + if (resolved) { + stylisticPluginCache.set(resolutionKey, resolved); + return resolved; + } + } + + stylisticPluginCache.set(resolutionKey, bundledStylisticPlugin); + return bundledStylisticPlugin; +} + function normalizeFormattedExpressionForLint( text: string, wrapperLineIndentWidth: number, @@ -410,7 +465,7 @@ function normalizeFormattedExpressionForLint( hasSyntheticWrapperLines?: boolean; } { if ( - formattingContext.containerKind !== 'standalone' + needsSyntheticRootJsxWrapper(formattingContext.containerKind) && text.includes('\n') && isRootJsxExpression(text, filename) ) { @@ -436,6 +491,16 @@ function normalizeFormattedExpressionForLint( }; } +function needsSyntheticRootJsxWrapper( + containerKind: RegionFormattingContext['containerKind'], +): boolean { + return ( + containerKind === 'call-argument' + || containerKind === 'conditional-branch' + || containerKind === 'logical-operand' + ); +} + function getSyntheticWrapperLineRanges(text: string): InsertionOffsetRange[] { const firstNewline = text.indexOf('\n'); const lastNewline = text.lastIndexOf('\n'); diff --git a/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts b/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts index 46dc874..befb348 100644 --- a/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts +++ b/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts @@ -154,4 +154,141 @@ describe('eslint processor diagnostic mapping', () => { expect(unused?.endLine).toBe(expected.line) expect(unused?.endColumn).toBe(expected.column + 'myValue'.length) }) + + it('does not report false indent diagnostics for nested multiline ternaries inside ${} interpolations', async () => { + const filePath = resolve(repoRoot, 'nested-template-ternary-indent.js') + const input = [ + "import { pug } from 'startupjs'", + 'const monthAmount = 10', + 'const yearAmount = 100', + '', + 'const view = pug`', + ' Span.text= ${monthAmount != null && yearAmount != null', + " ? t(msg`Each business you add is {monthAmount}/month or {yearAmount}/year.`, { monthAmount: '$' + monthAmount, yearAmount: '$' + yearAmount })", + ' : monthAmount != null', + " ? t(msg`Each business you add is {amount}/month.`, { amount: '$' + monthAmount })", + " : t(msg`Each business you add is {amount}/year.`, { amount: '$' + yearAmount })", + ' }', + '`', + '', + ].join('\n') + + const eslint = new ESLint({ + cwd: repoRoot, + fix: false, + ignore: false, + overrideConfigFile: true, + overrideConfig: [ + ...neostandard({ + ts: true, + }), + { + plugins: { + 'react-pug': reactPugPlugin as any, + }, + processor: 'react-pug/react-pug', + }, + ] as any, + }) + + const [result] = await eslint.lintText(input, { filePath }) + expect(result.messages.filter(message => message.ruleId === '@stylistic/indent')).toEqual([]) + }) + + it('maps real no-undef inside ${} interpolations to the exact original symbol', async () => { + const filePath = resolve(repoRoot, 'nested-template-real-error.js') + const input = [ + "import { pug } from 'startupjs'", + 'const Span = "span"', + 'const t = (value) => value', + 'const msg = (strings) => strings[0]', + 'const monthAmount = 10', + 'const yearAmount = 100', + '', + 'const view = pug`', + ' Span.text= ${monthAmount != null && yearAmount != null', + " ? t(msg`Each business you add is {monthAmount}/month or {yearAmount}/year.`, { monthAmount: '$' + monthAmount, yearAmount: '$' + yearAmount + unknownSuffix })", + ' : monthAmount != null', + " ? t(msg`Each business you add is {amount}/month.`, { amount: '$' + monthAmount })", + " : t(msg`Each business you add is {amount}/year.`, { amount: '$' + yearAmount })", + ' }', + '`', + '', + ].join('\n') + + const eslint = new ESLint({ + cwd: repoRoot, + fix: false, + ignore: false, + overrideConfigFile: true, + overrideConfig: [ + ...neostandard({ + ts: true, + }), + { + plugins: { + 'react-pug': reactPugPlugin as any, + }, + processor: 'react-pug/react-pug', + }, + ] as any, + }) + + const [result] = await eslint.lintText(input, { filePath }) + const unknown = result.messages.find((message) => ( + message.ruleId === 'no-undef' + && message.message.includes('unknownSuffix') + )) + + expect(unknown).toBeTruthy() + const expectedStart = input.indexOf('unknownSuffix') + const expected = offsetToLineColumn(input, expectedStart) + expect(unknown?.line).toBe(expected.line) + expect(unknown?.column).toBe(expected.column) + expect(unknown?.endLine).toBe(expected.line) + expect(unknown?.endColumn).toBe(expected.column + 'unknownSuffix'.length) + }) + + it('currently normalizes source-formatting mistakes inside ${} interpolations instead of reporting indent diagnostics', async () => { + const filePath = resolve(repoRoot, 'nested-template-source-indent-gap.js') + const input = [ + "import { pug } from 'startupjs'", + 'const Span = "span"', + 'const t = (value) => value', + 'const msg = (strings) => strings[0]', + 'const monthAmount = 10', + 'const yearAmount = 100', + '', + 'const view = pug`', + ' Span.text= ${monthAmount != null && yearAmount != null', + " ? t(msg`Each business you add is {monthAmount}/month or {yearAmount}/year.`, { monthAmount: '$' + monthAmount, yearAmount: '$' + yearAmount })", + ' : monthAmount != null', + " ? t(msg`Each business you add is {amount}/month.`, { amount: '$' + monthAmount })", + " : t(msg`Each business you add is {amount}/year.`, { amount: '$' + yearAmount })", + ' }', + '`', + '', + ].join('\n') + + const eslint = new ESLint({ + cwd: repoRoot, + fix: false, + ignore: false, + overrideConfigFile: true, + overrideConfig: [ + ...neostandard({ + ts: true, + }), + { + plugins: { + 'react-pug': reactPugPlugin as any, + }, + processor: 'react-pug/react-pug', + }, + ] as any, + }) + + const [result] = await eslint.lintText(input, { filePath }) + expect(result.messages.filter(message => message.ruleId === '@stylistic/indent')).toEqual([]) + }) }) diff --git a/packages/eslint-plugin-react-pug/test/unit/processor.test.ts b/packages/eslint-plugin-react-pug/test/unit/processor.test.ts index 4686010..1afdd6a 100644 --- a/packages/eslint-plugin-react-pug/test/unit/processor.test.ts +++ b/packages/eslint-plugin-react-pug/test/unit/processor.test.ts @@ -106,7 +106,10 @@ function lintStylisticIndent(code: string, filename = 'file.jsx') { ], offsetTernaryExpressions: true, }], - '@stylistic/jsx-indent': ['error', 2], + '@stylistic/jsx-indent': ['error', 2, { + checkAttributes: false, + indentLogicalExpressions: true, + }], '@stylistic/jsx-indent-props': ['error', 2], '@stylistic/jsx-wrap-multilines': ['error', { declaration: 'parens-new-line', @@ -406,7 +409,7 @@ describe('eslint-plugin-react-pug processor', () => { }" `); - const lintMessages = lintStylisticIndent(code, 'file.jsx'); + const lintMessages = lintStartupjsUiStyle(code, 'file.jsx'); const mapped = processor.postprocess([lintMessages as any], 'file.jsx'); expect(mapped.filter(message => String(message.ruleId).includes('indent'))).toEqual([]); }); @@ -573,6 +576,48 @@ describe('eslint-plugin-react-pug processor', () => { expect(mapped.filter(message => message.ruleId === '@stylistic/jsx-closing-tag-location')).toEqual([]); }); + it('formats nested multiline ternaries inside ${} interpolations with consumer-aligned indentation', () => { + const processor = createReactPugProcessor(); + const input = [ + 'const monthAmount = 10', + 'const yearAmount = 100', + 'const view = pug`', + ' Span.text= ${monthAmount != null && yearAmount != null', + " ? t(msg`Each business you add is {monthAmount}/month or {yearAmount}/year.`, { monthAmount: '$' + monthAmount, yearAmount: '$' + yearAmount })", + ' : monthAmount != null', + " ? t(msg`Each business you add is {amount}/month.`, { amount: '$' + monthAmount })", + " : t(msg`Each business you add is {amount}/year.`, { amount: '$' + yearAmount })", + ' }', + '`', + ].join('\n'); + + const [block] = processor.preprocess(input, 'file.jsx'); + const code = typeof block === 'string' ? block : block.text; + expect(code).toMatchInlineSnapshot(` + "const monthAmount = 10 + const yearAmount = 100 + const view = ( + + {monthAmount != null && yearAmount != null + ? t( + msg\`Each business you add is {monthAmount}/month or {yearAmount}/year.\`, + { + monthAmount: '$' + monthAmount, + yearAmount: '$' + yearAmount + } + ) + : monthAmount != null + ? t(msg\`Each business you add is {amount}/month.\`, { + amount: '$' + monthAmount + }) + : t(msg\`Each business you add is {amount}/year.\`, { + amount: '$' + yearAmount + })} + + )" + `); + }); + it('suppresses legacy styl warnings without hiding normal linting', () => { const processor = createReactPugProcessor(); const input = [ diff --git a/test/fixtures/real-project/snapshots/eslint/cat-profile-link.js.output.jsx b/test/fixtures/real-project/snapshots/eslint/cat-profile-link.js.output.jsx index 11cbe12..c6dcc7f 100644 --- a/test/fixtures/real-project/snapshots/eslint/cat-profile-link.js.output.jsx +++ b/test/fixtures/real-project/snapshots/eslint/cat-profile-link.js.output.jsx @@ -60,7 +60,11 @@ const Profile = observer(({ $cat, $event }) => {
) : ( - )} @@ -82,8 +86,8 @@ function renderExpired () { Cat profile link is incorrect or already expired. Your cat meetup - profile link is only valid for a limited period of time. If you believe - this is an error, please contact the cat meetup organizer. + profile link is only valid for a limited period of time. If you + believe this is an error, please contact the cat meetup organizer. diff --git a/test/fixtures/real-project/snapshots/eslint/cat-profile-link.tsx.output.jsx b/test/fixtures/real-project/snapshots/eslint/cat-profile-link.tsx.output.jsx index 11cbe12..c6dcc7f 100644 --- a/test/fixtures/real-project/snapshots/eslint/cat-profile-link.tsx.output.jsx +++ b/test/fixtures/real-project/snapshots/eslint/cat-profile-link.tsx.output.jsx @@ -60,7 +60,11 @@ const Profile = observer(({ $cat, $event }) => {
) : ( - )} @@ -82,8 +86,8 @@ function renderExpired () { Cat profile link is incorrect or already expired. Your cat meetup - profile link is only valid for a limited period of time. If you believe - this is an error, please contact the cat meetup organizer. + profile link is only valid for a limited period of time. If you + believe this is an error, please contact the cat meetup organizer. From cd72c3e23c661a454bf61abb448ce241f244c7fc Mon Sep 17 00:00:00 2001 From: Pavel Zhukov Date: Wed, 15 Apr 2026 18:42:13 +0300 Subject: [PATCH 2/9] feat: lint embedded pug expressions as source-faithful JS --- README.md | 3 +- example/src/TypeScriptInPug.tsx | 2 +- packages/eslint-plugin-react-pug/README.md | 5 +- packages/eslint-plugin-react-pug/src/index.ts | 277 +++++++++++++++++- .../test/integration/autofix.test.ts | 4 +- .../test/integration/diagnostics.test.ts | 49 +++- .../integration/fixture-diagnostics.test.ts | 2 +- .../startupjs-ui-regressions.test.ts | 4 +- .../test/unit/processor.test.ts | 19 ++ .../src/language/extractRegions.ts | 2 + .../src/language/lintTransform.ts | 54 +++- .../react-pug-core/src/language/mapping.ts | 21 ++ .../react-pug-core/src/language/pugToTsx.ts | 130 +++++++- .../src/language/shadowDocument.ts | 1 + .../test/unit/lintTransform.test.ts | 18 ++ .../react-pug-core/test/unit/pugToTsx.test.ts | 35 +++ .../snapshots/diagnostics/src/App.tsx.txt | 6 +- .../src/StartupjsUiMdxComponents.js.txt | 4 +- .../src/StartupjsUiTextInput.tsx.txt | 4 +- .../src/StartupjsUiWrapInput.tsx.txt | 9 +- .../src/TypeScriptErrorsInPug.tsx.txt | 3 +- .../diagnostics/src/TypeScriptInPug.tsx.txt | 3 +- .../snapshots/post-fix-diagnostics.json | 163 +++++++++++ .../cat-profile-link.js.diagnostics.txt | 7 +- .../cat-profile-link.tsx.diagnostics.txt | 7 +- .../event-tabs-breed.js.diagnostics.txt | 6 +- .../event-tabs-breed.tsx.diagnostics.txt | 6 +- .../event-tabs-layout.js.diagnostics.txt | 27 +- .../event-tabs-layout.tsx.diagnostics.txt | 27 +- 29 files changed, 861 insertions(+), 37 deletions(-) create mode 100644 test/fixtures/example-unformatted/snapshots/post-fix-diagnostics.json diff --git a/README.md b/README.md index 10d93b9..f87250e 100644 --- a/README.md +++ b/README.md @@ -124,12 +124,13 @@ export default [ ESLint processor behavior: - real JS/TS diagnostics inside Pug expression sites such as `#{...}`, `${...}`, `tag= ...`, attribute expressions, and inline handler/function bodies are mapped back to the original Pug source +- formatting diagnostics for those embedded expression sites are linted against source-faithful JS wrappers rather than only against generated JSX - diagnostics that originate only from synthetic generated helper code are filtered out - the processor formats against the project's own `@stylistic` package when available so generated JSX converges to the same style engine the outer ESLint run uses Current limitation: -- purely formatting-only, auto-fixable source mistakes inside nested embedded-expression sites, especially `${...}`, can currently be normalized away by the generated-JSX formatting pass instead of being reported back as original-source style diagnostics +- multiline unbuffered `- ...` statements that are authored across several Pug lines do not yet get the same source-faithful formatting-diagnostic surface as embedded expression sites - autofixes and suggestions are currently not mapped back for files that contain transformed Pug regions, so transformed-region diagnostics are report-only today ## VS Code Settings diff --git a/example/src/TypeScriptInPug.tsx b/example/src/TypeScriptInPug.tsx index ac3bf17..066fcb6 100644 --- a/example/src/TypeScriptInPug.tsx +++ b/example/src/TypeScriptInPug.tsx @@ -48,7 +48,7 @@ export default function TypeScriptInPug () { if maybeTitle != null p #{maybeTitle as string} - each item in (items as string[]) + each item in items as string[] Card(title=item!) ` } diff --git a/packages/eslint-plugin-react-pug/README.md b/packages/eslint-plugin-react-pug/README.md index 586816a..6aec0e9 100644 --- a/packages/eslint-plugin-react-pug/README.md +++ b/packages/eslint-plugin-react-pug/README.md @@ -45,16 +45,15 @@ Used `pug` import bindings are removed from the processor's transformed view aut The processor is designed to preserve useful JavaScript/TypeScript diagnostics inside Pug regions: - real JS/TS rule violations inside `#{...}`, `${...}`, `tag= ...`, attribute expressions, and inline handler/function bodies are reported back at the original Pug location +- formatting diagnostics for those embedded expression sites are linted against source-faithful JS wrappers rather than only against generated JSX - diagnostics caused only by synthetic generated helper code are filtered out - the formatter tries to converge to the consuming project's own `@stylistic` setup when that package is available locally Current limitation: -- purely formatting-only, auto-fixable source mistakes inside nested expression sites such as `${...}` can be normalized away by the processor's generated-JSX formatting pass instead of being reported back as original-source indent/style diagnostics +- multiline unbuffered `- ...` statements that are authored across several Pug lines do not yet get the same source-faithful formatting-diagnostic surface as embedded expression sites - autofixes and suggestions are currently not mapped back for files that contain transformed Pug regions, so transformed-region diagnostics are report-only today -That means semantic errors and real rule violations inside embedded JS should still surface, but some raw source-formatting mistakes inside embedded Pug expression blocks are not yet part of the processor's reported lint contract. - ## Exports - default ESLint plugin object diff --git a/packages/eslint-plugin-react-pug/src/index.ts b/packages/eslint-plugin-react-pug/src/index.ts index d5abb37..d8df3ed 100644 --- a/packages/eslint-plugin-react-pug/src/index.ts +++ b/packages/eslint-plugin-react-pug/src/index.ts @@ -64,6 +64,14 @@ interface CachedLintState { formatted: RewrittenPugRegionsResult | null; legacyStyleStatementRanges: InsertionOffsetRange[]; syntheticStyleCallRanges: InsertionOffsetRange[]; + embeddedLintBlocks: EmbeddedLintBlockState[]; +} + +interface EmbeddedLintBlockState { + text: string; + filename: string; + boundaryMap: Array; + syntheticRanges: InsertionOffsetRange[]; } interface EslintProcessorLike { @@ -300,6 +308,122 @@ function getExpressionParserPlugins(filename: string): any[] { ] as any; } +interface EmbeddedLintBlockBuilder { + text: string; + boundaryMap: Array; + syntheticRanges: InsertionOffsetRange[]; +} + +function appendSyntheticBlockText( + builder: EmbeddedLintBlockBuilder, + text: string, +): void { + if (text.length === 0) return; + const start = builder.text.length; + if (builder.boundaryMap.length === 0) builder.boundaryMap.push(null); + else builder.boundaryMap[builder.boundaryMap.length - 1] = null; + builder.text += text; + for (let i = 0; i < text.length; i += 1) builder.boundaryMap.push(null); + builder.syntheticRanges.push({ start, end: builder.text.length }); +} + +function appendMappedBlockText( + builder: EmbeddedLintBlockBuilder, + text: string, + boundaryMap: number[], +): void { + if (text.length === 0) { + if (builder.boundaryMap.length === 0) builder.boundaryMap.push(boundaryMap[0] ?? null); + return; + } + + if (builder.boundaryMap.length === 0) builder.boundaryMap.push(boundaryMap[0] ?? null); + else builder.boundaryMap[builder.boundaryMap.length - 1] = boundaryMap[0] ?? null; + + builder.text += text; + for (let i = 0; i < text.length; i += 1) { + builder.boundaryMap.push(boundaryMap[i + 1] ?? null); + } +} + +function appendMappedCodeWithIndent( + builder: EmbeddedLintBlockBuilder, + code: string, + boundaryMap: number[], + indent: string, +): void { + let lineStart = true; + for (let index = 0; index < code.length; index += 1) { + if (lineStart) appendSyntheticBlockText(builder, indent); + appendMappedBlockText(builder, code[index], [boundaryMap[index], boundaryMap[index + 1]]); + lineStart = code[index] === '\n'; + } +} + +function createEmbeddedLintBlockFilename( + filename: string, + kind: 'expression' | 'statement', +): string { + const suffix = isTypeScriptLikeFilename(filename) ? 'tsx' : 'jsx'; + return `../../../pug-react-embedded-${kind}.${suffix}`; +} + +function createEmbeddedLintBlocks(transformed: LintTransformState, filename: string): EmbeddedLintBlockState[] { + const expressionSites = transformed.embeddedJsLintSites.filter(site => site.kind === 'expression'); + const statementSites = transformed.embeddedJsLintSites.filter(site => site.kind === 'statement'); + const blocks: EmbeddedLintBlockState[] = []; + + const buildExpressionBlock = () => { + if (expressionSites.length === 0) return; + const builder: EmbeddedLintBlockBuilder = { + text: '', + boundaryMap: [], + syntheticRanges: [], + }; + + expressionSites.forEach((site, index) => { + appendSyntheticBlockText(builder, `const __reactPugExpr${index} = (\n`); + appendMappedCodeWithIndent(builder, site.code, site.boundaryMap, ' '); + appendSyntheticBlockText(builder, '\n)\n'); + if (index < expressionSites.length - 1) appendSyntheticBlockText(builder, '\n'); + }); + + blocks.push({ + text: builder.text, + filename: createEmbeddedLintBlockFilename(filename, 'expression'), + boundaryMap: builder.boundaryMap, + syntheticRanges: builder.syntheticRanges, + }); + }; + + const buildStatementBlock = () => { + if (statementSites.length === 0) return; + const builder: EmbeddedLintBlockBuilder = { + text: '', + boundaryMap: [], + syntheticRanges: [], + }; + + statementSites.forEach((site, index) => { + appendSyntheticBlockText(builder, '(() => {\n'); + appendMappedCodeWithIndent(builder, site.code, site.boundaryMap, ' '); + appendSyntheticBlockText(builder, '\n})()\n'); + if (index < statementSites.length - 1) appendSyntheticBlockText(builder, '\n'); + }); + + blocks.push({ + text: builder.text, + filename: createEmbeddedLintBlockFilename(filename, 'statement'), + boundaryMap: builder.boundaryMap, + syntheticRanges: builder.syntheticRanges, + }); + }; + + buildExpressionBlock(); + buildStatementBlock(); + return blocks; +} + function rebaseFormattedRegion( text: string, baseIndent: string, @@ -371,11 +495,11 @@ function normalizeSyntheticWrapperClosingIndent( function applyFormatterLintPasses(text: string, filename: string): string { const lintConfig: any[] = getFormatterLintConfig(filename) - // We lint the generated, formatter-normalized JSX/TSX rather than the raw - // original Pug source. That keeps semantic diagnostics inside `${...}` blocks - // accurate and avoids transform-specific indent noise, but it also means - // purely formatting-only, auto-fixable source mistakes inside `${...}` are - // currently normalized away instead of being reported back to the user. + // This pass shapes the generated JSX/TSX surface only. Embedded JS expression + // sites such as `${...}`, `#{...}`, attr expressions and inline handler bodies + // also get a separate source-faithful lint surface below, but generated-region + // autofixes/suggestions are still intentionally dropped because they are not + // safely mappable back through the transform today. const pretty = prettier.format(text, { parser: isTypeScriptLikeFilename(filename) ? 'babel-ts' : 'babel', semi: false, @@ -744,6 +868,98 @@ function mapLintMessage( }; } +function mapEmbeddedLintOffsetToOriginal( + block: EmbeddedLintBlockState, + offset: number, +): number | null { + const clamped = Math.max(0, Math.min(offset, block.text.length)); + return block.boundaryMap[clamped] ?? null; +} + +function findLineBounds(text: string, offset: number): { start: number; end: number } { + const clamped = Math.max(0, Math.min(offset, text.length)); + const start = text.lastIndexOf('\n', Math.max(0, clamped - 1)) + 1; + const nextNewline = text.indexOf('\n', clamped); + return { + start, + end: nextNewline >= 0 ? nextNewline : text.length, + }; +} + +function findFirstMappableOffsetOnLine( + block: EmbeddedLintBlockState, + offset: number, +): number | null { + const { start, end } = findLineBounds(block.text, offset); + for (let index = Math.max(start, Math.min(offset, end)); index <= end; index += 1) { + if (block.boundaryMap[index] != null) return index; + } + return null; +} + +function findLastMappableOffsetOnLine( + block: EmbeddedLintBlockState, + offset: number, +): number | null { + const { start, end } = findLineBounds(block.text, offset); + for (let index = Math.max(start, Math.min(offset, end)); index >= start; index -= 1) { + if (block.boundaryMap[index] != null) return index; + } + return null; +} + +function mapEmbeddedLintMessage( + message: EslintLintMessage, + block: EmbeddedLintBlockState, + originalText: string, +): EslintLintMessage | null { + if (typeof message.ruleId !== 'string' || !message.ruleId.startsWith('@stylistic/')) { + return null; + } + if (message.line == null || message.column == null) return null; + + const start = lineColumnToOffset(block.text, message.line, message.column); + const end = (message.endLine != null && message.endColumn != null) + ? lineColumnToOffset(block.text, message.endLine, message.endColumn) + : start + 1; + let mappedStartOffset = start; + let mappedEndOffset = Math.max(start + 1, end); + + if (overlapsRangeList(block.syntheticRanges, mappedStartOffset, mappedEndOffset)) { + const relocatedStart = findFirstMappableOffsetOnLine(block, mappedStartOffset); + const relocatedEnd = findLastMappableOffsetOnLine(block, mappedEndOffset); + if (relocatedStart == null || relocatedEnd == null) return null; + mappedStartOffset = relocatedStart; + mappedEndOffset = Math.max(relocatedStart + 1, relocatedEnd); + } + + const originalStart = mapEmbeddedLintOffsetToOriginal(block, mappedStartOffset); + const originalEnd = mapEmbeddedLintOffsetToOriginal(block, mappedEndOffset); + if (originalStart == null || originalEnd == null) return null; + + const startLc = offsetToLineColumn(originalText, originalStart); + const endLc = offsetToLineColumn(originalText, originalEnd); + + return { + ...Object.fromEntries(Object.entries(message).filter(([key]) => key !== 'fix' && key !== 'suggestions')), + line: startLc.line, + column: startLc.column, + endLine: endLc.line, + endColumn: endLc.column, + }; +} + +function lintMessageDedupKey(message: EslintLintMessage): string { + return JSON.stringify([ + message.ruleId ?? null, + message.message ?? null, + message.line ?? null, + message.column ?? null, + message.endLine ?? null, + message.endColumn ?? null, + ]); +} + function createReactPugProcessor( options: EslintReactPugProcessorOptions = {}, ): EslintProcessorLike { @@ -774,6 +990,7 @@ function createReactPugProcessor( formatted: null, legacyStyleStatementRanges, syntheticStyleCallRanges: [], + embeddedLintBlocks: [], }); } else { cache.delete(filename); @@ -806,18 +1023,30 @@ function createReactPugProcessor( || containsJsxSyntax(text, filename) ); const formatted = hasTransformedPug ? formatLintCode(transformed, filename) : null; + const embeddedLintBlocks = hasTransformedPug + ? createEmbeddedLintBlocks(transformed, filename) + : []; cache.set(filename, { originalText: text, transformed, formatted, legacyStyleStatementRanges, syntheticStyleCallRanges: collectMappedInsertionRangesByKind(transformed, 'style-call'), + embeddedLintBlocks, }); - if (!shouldUseVirtualJsxFilename) return [transformed.code]; - return [{ - text: hasTransformedPug ? (formatted?.code ?? transformed.code) : transformed.code, - filename: getVirtualLintFilename(filename), - }]; + const mainBlock: string | { text: string; filename: string } = shouldUseVirtualJsxFilename + ? { + text: hasTransformedPug ? (formatted?.code ?? transformed.code) : transformed.code, + filename: getVirtualLintFilename(filename), + } + : transformed.code; + return [ + mainBlock, + ...embeddedLintBlocks.map(block => ({ + text: block.text, + filename: block.filename, + })), + ]; }, postprocess(messages: EslintLintMessage[][], filename: string): EslintLintMessage[] { @@ -827,9 +1056,31 @@ function createReactPugProcessor( const flat = messages.flat(); if (!cached) return flat; - return flat - .map((msg) => mapLintMessage(msg, cached)) - .filter((msg): msg is EslintLintMessage => msg != null); + const [mainMessages = [], ...embeddedMessages] = messages; + const mapped = [ + ...mainMessages + .map((msg) => mapLintMessage(msg, cached)) + .filter((msg): msg is EslintLintMessage => msg != null), + ]; + + embeddedMessages.forEach((blockMessages, index) => { + const block = cached.embeddedLintBlocks[index]; + if (!block) return; + for (const message of blockMessages) { + const mappedMessage = mapEmbeddedLintMessage(message, block, cached.originalText); + if (mappedMessage) mapped.push(mappedMessage); + } + }); + + const deduped: EslintLintMessage[] = []; + const seen = new Set(); + for (const message of mapped) { + const key = lintMessageDedupKey(message); + if (seen.has(key)) continue; + seen.add(key); + deduped.push(message); + } + return deduped; }, supportsAutofix: true, diff --git a/packages/eslint-plugin-react-pug/test/integration/autofix.test.ts b/packages/eslint-plugin-react-pug/test/integration/autofix.test.ts index d9704cd..7d8708a 100644 --- a/packages/eslint-plugin-react-pug/test/integration/autofix.test.ts +++ b/packages/eslint-plugin-react-pug/test/integration/autofix.test.ts @@ -9,6 +9,7 @@ import reactPugPlugin from '../../src/index' const repoRoot = resolve(__dirname, '../../../..') const fixtureRoot = resolve(repoRoot, 'test/fixtures/example-unformatted') const snapshotRoot = resolve(fixtureRoot, 'snapshots/fixed') +const postFixDiagnosticsSnapshot = resolve(fixtureRoot, 'snapshots/post-fix-diagnostics.json') const reactHooksStubPlugin = { rules: { 'rules-of-hooks': { @@ -93,7 +94,8 @@ describe('eslint --fix integration for react-pug processor', () => { message: message.message, })) )) - expect(allMessages).toEqual([]) + expect(allMessages.every(message => String(message.ruleId).startsWith('@stylistic/'))).toBe(true) + await expect(JSON.stringify(allMessages, null, 2) + '\n').toMatchFileSnapshot(postFixDiagnosticsSnapshot) const fixedFiles = [ 'src/App.tsx', diff --git a/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts b/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts index befb348..3262340 100644 --- a/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts +++ b/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts @@ -249,7 +249,7 @@ describe('eslint processor diagnostic mapping', () => { expect(unknown?.endColumn).toBe(expected.column + 'unknownSuffix'.length) }) - it('currently normalizes source-formatting mistakes inside ${} interpolations instead of reporting indent diagnostics', async () => { + it('reports original indent diagnostics inside ${} interpolations', async () => { const filePath = resolve(repoRoot, 'nested-template-source-indent-gap.js') const input = [ "import { pug } from 'startupjs'", @@ -289,6 +289,51 @@ describe('eslint processor diagnostic mapping', () => { }) const [result] = await eslint.lintText(input, { filePath }) - expect(result.messages.filter(message => message.ruleId === '@stylistic/indent')).toEqual([]) + const indentMessages = result.messages.filter(message => message.ruleId === '@stylistic/indent') + expect(indentMessages.length).toBeGreaterThan(0) + expect(indentMessages.every(message => (message.line ?? 0) >= 10 && (message.line ?? 0) <= 13)).toBe(true) + }) + + it('reports original indent diagnostics inside inline handler bodies', async () => { + const filePath = resolve(repoRoot, 'embedded-handler-indent.js') + const input = [ + "import { pug } from 'startupjs'", + 'const ready = true', + 'const run = () => {}', + '', + 'const view = pug`', + ' Button(', + ' onClick=() => {', + ' if (ready) {', + ' run()', + ' }', + ' }', + ' ) Save', + '`', + '', + ].join('\n') + + const eslint = new ESLint({ + cwd: repoRoot, + fix: false, + ignore: false, + overrideConfigFile: true, + overrideConfig: [ + ...neostandard({ + ts: true, + }), + { + plugins: { + 'react-pug': reactPugPlugin as any, + }, + processor: 'react-pug/react-pug', + }, + ] as any, + }) + + const [result] = await eslint.lintText(input, { filePath }) + const indentMessages = result.messages.filter(message => message.ruleId === '@stylistic/indent') + expect(indentMessages.length).toBeGreaterThan(0) + expect(indentMessages.some(message => (message.line ?? 0) >= 8 && (message.line ?? 0) <= 10)).toBe(true) }) }) diff --git a/packages/eslint-plugin-react-pug/test/integration/fixture-diagnostics.test.ts b/packages/eslint-plugin-react-pug/test/integration/fixture-diagnostics.test.ts index 8ccc7d2..70ae0ec 100644 --- a/packages/eslint-plugin-react-pug/test/integration/fixture-diagnostics.test.ts +++ b/packages/eslint-plugin-react-pug/test/integration/fixture-diagnostics.test.ts @@ -98,7 +98,7 @@ describe('eslint diagnostics for example-unformatted fixture', () => { expect(startupjsUiPrompt?.messages.some(message => message.ruleId === '@stylistic/indent')).toBe(false) const startupjsUiMdxComponents = results.find(result => result.filePath.endsWith('/src/StartupjsUiMdxComponents.js')) - expect(startupjsUiMdxComponents?.messages.some(message => message.ruleId === '@stylistic/indent')).toBe(false) + expect(startupjsUiMdxComponents?.messages.some(message => message.ruleId === 'no-undef')).toBe(false) const startupjsUiMultiSelect = results.find(result => result.filePath.endsWith('/src/StartupjsUiMultiSelect.tsx')) expect(startupjsUiMultiSelect?.messages.some(message => message.ruleId === '@stylistic/indent')).toBe(false) diff --git a/packages/eslint-plugin-react-pug/test/integration/startupjs-ui-regressions.test.ts b/packages/eslint-plugin-react-pug/test/integration/startupjs-ui-regressions.test.ts index e5ab2ee..02891d6 100644 --- a/packages/eslint-plugin-react-pug/test/integration/startupjs-ui-regressions.test.ts +++ b/packages/eslint-plugin-react-pug/test/integration/startupjs-ui-regressions.test.ts @@ -89,7 +89,9 @@ describe('startupjs-ui regressions', () => { })) )) - expect(messages).toEqual([]) + expect(messages.every(message => String(message.ruleId).startsWith('@stylistic/'))).toBe(true) + expect(messages.some(message => message.ruleId === '@stylistic/indent')).toBe(true) + expect(messages.some(message => message.ruleId === '@stylistic/arrow-spacing')).toBe(true) }) it('still reports jsx-boolean-value for intrinsic boolean attrs inside pug', async () => { diff --git a/packages/eslint-plugin-react-pug/test/unit/processor.test.ts b/packages/eslint-plugin-react-pug/test/unit/processor.test.ts index 1afdd6a..68a43f9 100644 --- a/packages/eslint-plugin-react-pug/test/unit/processor.test.ts +++ b/packages/eslint-plugin-react-pug/test/unit/processor.test.ts @@ -618,6 +618,25 @@ describe('eslint-plugin-react-pug processor', () => { `); }); + it('emits dedicated embedded-JS lint blocks for expression and statement sites', () => { + const processor = createReactPugProcessor(); + const input = [ + 'const view = pug`', + ' Button(onClick=() => run()) Save', + ' - const visible = ready', + '`', + ].join('\n'); + + const blocks = processor.preprocess(input, 'file.jsx'); + expect(blocks).toHaveLength(3); + expect(blocks[1]).toMatchObject({ + filename: '../../../pug-react-embedded-expression.jsx', + }); + expect(blocks[2]).toMatchObject({ + filename: '../../../pug-react-embedded-statement.jsx', + }); + }); + it('suppresses legacy styl warnings without hiding normal linting', () => { const processor = createReactPugProcessor(); const input = [ diff --git a/packages/react-pug-core/src/language/extractRegions.ts b/packages/react-pug-core/src/language/extractRegions.ts index b46bd15..8960562 100644 --- a/packages/react-pug-core/src/language/extractRegions.ts +++ b/packages/react-pug-core/src/language/extractRegions.ts @@ -360,6 +360,7 @@ function extractWithRegex(text: string, tagName: string = 'pug'): PugRegion[] { parseError: null, transformError: null, styleBlock: null, + embeddedJsLintSites: [], }); } @@ -486,6 +487,7 @@ export function extractPugAnalysis( parseError: null, transformError: null, styleBlock: null, + embeddedJsLintSites: [], }; regions.push(region); diff --git a/packages/react-pug-core/src/language/lintTransform.ts b/packages/react-pug-core/src/language/lintTransform.ts index 4e885fd..a349602 100644 --- a/packages/react-pug-core/src/language/lintTransform.ts +++ b/packages/react-pug-core/src/language/lintTransform.ts @@ -1,9 +1,10 @@ import generate from '@babel/generator'; import { parse, parseExpression } from '@babel/parser'; import * as t from '@babel/types'; -import type { ShadowInsertion, ShadowMappedRegion } from './mapping'; +import type { EmbeddedJsLintSite, ShadowInsertion, ShadowMappedRegion } from './mapping'; import type { SourceTransformOptions, SourceTransformResult } from './sourceTransform'; import { transformSourceFile } from './sourceTransform'; +import { strippedToRawOffset } from './regionOffsetMapping'; export interface RewrittenCopySegment { rewrittenStart: number; @@ -45,10 +46,19 @@ export interface BoundaryMappedExpression { export interface LintTransformResult extends RewrittenPugRegionsResult { baseTransform: SourceTransformResult; + embeddedJsLintSites: MappedEmbeddedJsLintSite[]; mapGeneratedOffsetToOriginal: (offset: number) => number | null; mapBaseOffsetToOriginal: (offset: number) => number | null; } +export interface MappedEmbeddedJsLintSite { + kind: EmbeddedJsLintSite['kind']; + originalStart: number; + originalEnd: number; + code: string; + boundaryMap: number[]; +} + export type RegionContainerKind = | 'standalone' | 'return-value' @@ -907,6 +917,46 @@ export function collectMappedInsertionRangesByKind( return ranges; } +function mapEmbeddedJsLintSitesToOriginal(baseTransform: SourceTransformResult): MappedEmbeddedJsLintSite[] { + const sites: MappedEmbeddedJsLintSite[] = []; + + for (const region of baseTransform.regions) { + for (const site of region.embeddedJsLintSites) { + const boundaryMap = site.boundaryMap.map((offset) => ( + region.pugTextStart + strippedToRawOffset( + region.pugText, + offset, + region.commonIndent, + ) + )); + const originalStart = boundaryMap[0] ?? ( + region.pugTextStart + strippedToRawOffset( + region.pugText, + site.sourceStart, + region.commonIndent, + ) + ); + const originalEnd = boundaryMap[boundaryMap.length - 1] ?? ( + region.pugTextStart + strippedToRawOffset( + region.pugText, + site.sourceEnd, + region.commonIndent, + ) + ); + + sites.push({ + kind: site.kind, + originalStart, + originalEnd, + code: site.code, + boundaryMap, + }); + } + } + + return sites; +} + export function createLintTransform( sourceText: string, fileName: string, @@ -919,10 +969,12 @@ export function createLintTransform( const rewritten = rewriteMappedPugRegions(baseTransform, fileName, (expr, _region, currentFileName) => ( normalizePugExpressionForLint(expr, currentFileName) )); + const embeddedJsLintSites = mapEmbeddedJsLintSitesToOriginal(baseTransform); return { ...rewritten, baseTransform, + embeddedJsLintSites, mapGeneratedOffsetToOriginal: (offset: number) => { const baseOffset = rewritten.mapRewrittenOffsetToBase(offset); return baseOffset == null ? null : baseTransform.mapGeneratedOffsetToOriginal(baseOffset); diff --git a/packages/react-pug-core/src/language/mapping.ts b/packages/react-pug-core/src/language/mapping.ts index ed452b9..aa0b503 100644 --- a/packages/react-pug-core/src/language/mapping.ts +++ b/packages/react-pug-core/src/language/mapping.ts @@ -103,6 +103,24 @@ export interface ExtractedStyleBlock { column: number; } +export type EmbeddedJsLintSiteKind = 'expression' | 'statement'; + +export interface EmbeddedJsLintSite { + /** Whether the original embedded JS must parse as an expression or statement list */ + kind: EmbeddedJsLintSiteKind; + /** Start offset within stripped pug text */ + sourceStart: number; + /** End offset within stripped pug text */ + sourceEnd: number; + /** Normalized JS source to lint for this embedded site */ + code: string; + /** + * Boundary map from normalized code offsets back into stripped pug text offsets. + * Length is always `code.length + 1`. + */ + boundaryMap: number[]; +} + // ── PugToken ──────────────────────────────────────────────────── /** Minimal pug lexer token shape (retained for sub-expression position resolution) */ @@ -204,6 +222,9 @@ export interface PugRegion { /** Extracted terminal style block, if present */ styleBlock: ExtractedStyleBlock | null; + + /** Embedded JS sites that can be linted directly against original source */ + embeddedJsLintSites: EmbeddedJsLintSite[]; } // ── PugDocument ───────────────────────────────────────────────── diff --git a/packages/react-pug-core/src/language/pugToTsx.ts b/packages/react-pug-core/src/language/pugToTsx.ts index 235d70b..81297a2 100644 --- a/packages/react-pug-core/src/language/pugToTsx.ts +++ b/packages/react-pug-core/src/language/pugToTsx.ts @@ -1,6 +1,8 @@ import type { CodeMapping, CodeInformation, + EmbeddedJsLintSite, + EmbeddedJsLintSiteKind, ExtractedStyleBlock, PugParseError, PugToken, @@ -315,6 +317,7 @@ interface InterpolationContext { } const interpolationContextStack: InterpolationContext[] = []; +const embeddedJsLintSiteStack: EmbeddedJsLintSite[][] = []; interface CompileContext { mode: CompileMode; classAttribute: ClassAttributeName; @@ -329,6 +332,12 @@ function currentInterpolationContext(): InterpolationContext | null { : null; } +function currentEmbeddedJsLintSites(): EmbeddedJsLintSite[] | null { + return embeddedJsLintSiteStack.length > 0 + ? embeddedJsLintSiteStack[embeddedJsLintSiteStack.length - 1] + : null; +} + function currentCompileMode(): CompileMode { return compileContextStack.length > 0 ? compileContextStack[compileContextStack.length - 1].mode @@ -540,6 +549,111 @@ function findNextInterpolationOccurrence( return { index: bestIdx, interpolation: bestInterpolation }; } +interface MappedSourceBuilder { + code: string; + boundaryMap: number[]; + previousSourceEnd: number | null; +} + +function appendMappedSourceChar( + state: MappedSourceBuilder, + ch: string, + sourceStart: number, + sourceEnd: number, +): void { + if (state.code.length === 0) { + state.boundaryMap.push(sourceStart); + } else if (state.previousSourceEnd !== sourceStart) { + state.boundaryMap[state.boundaryMap.length - 1] = sourceStart; + } + state.code += ch; + state.boundaryMap.push(sourceEnd); + state.previousSourceEnd = sourceEnd; +} + +function appendMappedSourceSegment( + state: MappedSourceBuilder, + segment: string, + sourceStart: number, +): void { + for (let i = 0; i < segment.length; i += 1) { + appendMappedSourceChar(state, segment[i], sourceStart + i, sourceStart + i + 1); + } +} + +function resolveTemplateInterpolatedJavaScript( + text: string, + sourceStart: number, + context: InterpolationContext | null, +): { code: string; boundaryMap: number[] } { + const state: MappedSourceBuilder = { + code: '', + boundaryMap: [], + previousSourceEnd: null, + }; + + let cursor = 0; + while (cursor < text.length) { + const hit = findNextInterpolationOccurrence(text, cursor, context); + if (!hit) { + appendMappedSourceSegment(state, text.slice(cursor), sourceStart + cursor); + break; + } + + if (hit.index > cursor) { + appendMappedSourceSegment( + state, + text.slice(cursor, hit.index), + sourceStart + cursor, + ); + } + + const interpolation = hit.interpolation; + appendMappedSourceSegment( + state, + interpolation.expression, + interpolation.exprStart, + ); + cursor = hit.index + interpolation.marker.length; + } + + if (state.boundaryMap.length === 0) { + state.boundaryMap.push(sourceStart); + } + + return { + code: state.code, + boundaryMap: state.boundaryMap, + }; +} + +function recordEmbeddedJsLintSite( + kind: EmbeddedJsLintSiteKind, + text: string, + sourceStart: number, +): void { + const sites = currentEmbeddedJsLintSites(); + if (!sites) return; + + const resolved = resolveTemplateInterpolatedJavaScript( + text, + sourceStart, + currentInterpolationContext(), + ); + const trimmedLength = resolved.code.replace(/[ \t\r\n]+$/u, '').length; + if (trimmedLength === 0) return; + const trimmedCode = resolved.code.slice(0, trimmedLength); + const trimmedBoundaryMap = resolved.boundaryMap.slice(0, trimmedLength + 1); + + sites.push({ + kind, + sourceStart, + sourceEnd: sourceStart + text.length, + code: trimmedCode, + boundaryMap: trimmedBoundaryMap, + }); +} + function countIndent(line: string): number { return line.match(/^(\s*)/)?.[1].length ?? 0; } @@ -865,7 +979,11 @@ function emitExpressionWithTemplateInterpolations( expressionOffset: number, emitter: TsxEmitter, info: CodeInformation = FULL_FEATURES, + lintSiteKind: EmbeddedJsLintSiteKind | null = 'expression', ): void { + if (lintSiteKind) { + recordEmbeddedJsLintSite(lintSiteKind, expression, expressionOffset); + } const context = currentInterpolationContext(); let cursor = 0; @@ -1283,6 +1401,7 @@ function emitText( if (interpolation.expression.trim().length === 0) { emitter.emitSynthetic('undefined'); } else { + recordEmbeddedJsLintSite('expression', interpolation.expression, interpolation.exprStart); emitJsExpressionWithNestedPug(interpolation.expression, interpolation.exprStart, emitter); } emitter.emitSynthetic('}'); @@ -1318,7 +1437,7 @@ function emitCode( } else { // Unbuffered code block: - const x = 10 // Emitted as a statement; IIFE wrapping is handled by emitNodesWithCodeBlocks - emitExpressionWithTemplateInterpolations(node.val, valueOffset, emitter, FULL_FEATURES); + emitExpressionWithTemplateInterpolations(node.val, valueOffset, emitter, FULL_FEATURES, 'statement'); emitter.emitSynthetic(';'); } } @@ -1781,6 +1900,7 @@ export interface CompileResult { parseError: PugParseError | null; styleBlock: ExtractedStyleBlock | null; transformError: PugTransformError | null; + embeddedJsLintSites: EmbeddedJsLintSite[]; } export type CompileMode = 'languageService' | 'runtime'; @@ -1816,7 +1936,9 @@ export function compilePugToTsx(pugText: string, options: CompileOptions = {}): const extractedStyle = extractTerminalStyleBlock(pugText); const prepared = prepareTemplateInterpolations(extractedStyle.pugTextWithoutStyle); const pugTextForParse = prepared.sanitizedText; + const embeddedJsLintSites: EmbeddedJsLintSite[] = []; interpolationContextStack.push(prepared.context); + embeddedJsLintSiteStack.push(embeddedJsLintSites); compileContextStack.push({ mode, classAttribute, @@ -1833,6 +1955,7 @@ export function compilePugToTsx(pugText: string, options: CompileOptions = {}): parseError: null, styleBlock: null, transformError: extractedStyle.transformError, + embeddedJsLintSites, }; } @@ -1860,6 +1983,7 @@ export function compilePugToTsx(pugText: string, options: CompileOptions = {}): parseError, styleBlock: extractedStyle.styleBlock, transformError: null, + embeddedJsLintSites, }; } } else { @@ -1870,6 +1994,7 @@ export function compilePugToTsx(pugText: string, options: CompileOptions = {}): parseError, styleBlock: extractedStyle.styleBlock, transformError: null, + embeddedJsLintSites, }; } } @@ -1916,6 +2041,7 @@ export function compilePugToTsx(pugText: string, options: CompileOptions = {}): parseError, styleBlock: extractedStyle.styleBlock, transformError: null, + embeddedJsLintSites, }; } } @@ -1938,9 +2064,11 @@ export function compilePugToTsx(pugText: string, options: CompileOptions = {}): parseError, styleBlock: extractedStyle.styleBlock, transformError: null, + embeddedJsLintSites, }; } finally { compileContextStack.pop(); + embeddedJsLintSiteStack.pop(); interpolationContextStack.pop(); } } diff --git a/packages/react-pug-core/src/language/shadowDocument.ts b/packages/react-pug-core/src/language/shadowDocument.ts index 8c3cd38..41e5344 100644 --- a/packages/react-pug-core/src/language/shadowDocument.ts +++ b/packages/react-pug-core/src/language/shadowDocument.ts @@ -387,6 +387,7 @@ export function buildShadowDocument( region.parseError = compiled.parseError; region.transformError = compiled.transformError; region.styleBlock = compiled.styleBlock; + region.embeddedJsLintSites = compiled.embeddedJsLintSites; if (region.styleBlock && region.transformError == null) { if (!analysis.tagImportSource) { diff --git a/packages/react-pug-core/test/unit/lintTransform.test.ts b/packages/react-pug-core/test/unit/lintTransform.test.ts index 2ba68ea..7f8b20a 100644 --- a/packages/react-pug-core/test/unit/lintTransform.test.ts +++ b/packages/react-pug-core/test/unit/lintTransform.test.ts @@ -256,4 +256,22 @@ describe('lintTransform', () => { expect(styleCallText).toContain('styl`') expect(styleCallText).toContain('.root') }) + + it('maps embedded JS lint sites back to original file offsets', () => { + const source = [ + "import { pug } from 'startupjs'", + 'const view = pug`', + ' Button(', + " label='Show' + title + ' today'", + ' onClick=() => run(item.id)', + ' ) Save', + '`', + ].join('\n') + + const result = createLintTransform(source, 'file.jsx') + expect(result.embeddedJsLintSites.map(site => source.slice(site.originalStart, site.originalEnd).trimEnd())).toEqual([ + "'Show' + title + ' today'", + '() => run(item.id)', + ]) + }) }) diff --git a/packages/react-pug-core/test/unit/pugToTsx.test.ts b/packages/react-pug-core/test/unit/pugToTsx.test.ts index 25e9eb2..abe9e1f 100644 --- a/packages/react-pug-core/test/unit/pugToTsx.test.ts +++ b/packages/react-pug-core/test/unit/pugToTsx.test.ts @@ -1262,6 +1262,41 @@ describe('code blocks', () => { expect(result.tsx).toContain('return '); }); + it('collects embedded expression lint sites for attr values and #{}/${} interpolation bodies', () => { + const pug = [ + 'Button(', + " label='Show' + title + ' today'", + ' onClick=() => {', + ' if (ready) {', + ' run()', + ' }', + ' }', + ') Save', + 'Span.text= ${count != null', + " ? format(count)", + " : fallback('n/a')", + '}', + 'p Hello #{title + suffix}', + ].join('\n'); + + const result = compilePugToTsx(pug, { mode: 'runtime' }); + expect(result.embeddedJsLintSites.filter(site => site.kind === 'expression').map(site => site.code)).toEqual([ + "'Show' + title + ' today'", + "() => {\n if (ready) {\n run()\n }\n }", + "count != null\n ? format(count)\n : fallback('n/a')", + 'title + suffix', + ]); + }); + + it('collects embedded statement lint sites for unbuffered code blocks', () => { + const pug = '- const visible = ready\nDiv Done'; + + const result = compilePugToTsx(pug, { mode: 'runtime' }); + expect(result.embeddedJsLintSites.filter(site => site.kind === 'statement').map(site => site.code)).toEqual([ + 'const visible = ready', + ]); + }); + it('code-only block (no JSX) wraps in IIFE returning null', () => { const pug = '- console.log("hello")'; const result = compilePugToTsx(pug); diff --git a/test/fixtures/example-unformatted/snapshots/diagnostics/src/App.tsx.txt b/test/fixtures/example-unformatted/snapshots/diagnostics/src/App.tsx.txt index 69e487c..ca9ca1e 100644 --- a/test/fixtures/example-unformatted/snapshots/diagnostics/src/App.tsx.txt +++ b/test/fixtures/example-unformatted/snapshots/diagnostics/src/App.tsx.txt @@ -1 +1,5 @@ -No diagnostics. +44:39 error @stylistic/quotes Strings must use singlequote. +50:8 error @stylistic/space-infix-ops Operator '===' must be spaced. +54:73 error @stylistic/arrow-spacing Missing space before =>. +58:6 error @stylistic/space-infix-ops Operator '>' must be spaced. +61:87 error @stylistic/arrow-spacing Missing space before =>. diff --git a/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiMdxComponents.js.txt b/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiMdxComponents.js.txt index 69e487c..4ffcb7c 100644 --- a/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiMdxComponents.js.txt +++ b/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiMdxComponents.js.txt @@ -1 +1,3 @@ -No diagnostics. +269:9 error @stylistic/indent Expected indentation of 4 spaces but found 6. +270:16 error @stylistic/indent Expected indentation of 2 spaces but found 4. +304:40 error @stylistic/arrow-spacing Missing space before =>. diff --git a/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiTextInput.tsx.txt b/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiTextInput.tsx.txt index 69e487c..ff357fd 100644 --- a/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiTextInput.tsx.txt +++ b/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiTextInput.tsx.txt @@ -1 +1,3 @@ -No diagnostics. +213:5 error @stylistic/indent Expected indentation of 4 spaces but found 6. +214:5 error @stylistic/indent Expected indentation of 4 spaces but found 6. +216:4 error @stylistic/indent Expected indentation of 2 spaces but found 4. diff --git a/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiWrapInput.tsx.txt b/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiWrapInput.tsx.txt index 69e487c..b2aae6f 100644 --- a/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiWrapInput.tsx.txt +++ b/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiWrapInput.tsx.txt @@ -1 +1,8 @@ -No diagnostics. +166:11 error @stylistic/indent Expected indentation of 4 spaces but found 6. +180:19 error @stylistic/indent Expected indentation of 4 spaces but found 8. +181:13 error @stylistic/indent Expected indentation of 4 spaces but found 8. +182:18 error @stylistic/indent Expected indentation of 4 spaces but found 8. +182:41 error @stylistic/indent Expected indentation of 2 spaces but found 6. +228:13 error @stylistic/indent Expected indentation of 4 spaces but found 8. +229:7 error @stylistic/indent Expected indentation of 4 spaces but found 8. +231:15 error @stylistic/indent Expected indentation of 2 spaces but found 6. diff --git a/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptErrorsInPug.tsx.txt b/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptErrorsInPug.tsx.txt index 69e487c..106b00b 100644 --- a/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptErrorsInPug.tsx.txt +++ b/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptErrorsInPug.tsx.txt @@ -1 +1,2 @@ -No diagnostics. +23:24 error @stylistic/no-extra-parens Unnecessary parentheses around expression. +26:3 error @stylistic/no-extra-parens Unnecessary parentheses around expression. diff --git a/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptInPug.tsx.txt b/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptInPug.tsx.txt index 69e487c..2e5f4e3 100644 --- a/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptInPug.tsx.txt +++ b/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptInPug.tsx.txt @@ -1 +1,2 @@ -No diagnostics. +49:16 error @stylistic/indent Expected indentation of 2 spaces but found 3. +51:21 error @stylistic/no-extra-parens Unnecessary parentheses around expression. diff --git a/test/fixtures/example-unformatted/snapshots/post-fix-diagnostics.json b/test/fixtures/example-unformatted/snapshots/post-fix-diagnostics.json new file mode 100644 index 0000000..c59a962 --- /dev/null +++ b/test/fixtures/example-unformatted/snapshots/post-fix-diagnostics.json @@ -0,0 +1,163 @@ +[ + { + "filePath": "src/App.tsx", + "ruleId": "@stylistic/quotes", + "line": 44, + "column": 39, + "message": "Strings must use singlequote." + }, + { + "filePath": "src/App.tsx", + "ruleId": "@stylistic/space-infix-ops", + "line": 50, + "column": 8, + "message": "Operator '===' must be spaced." + }, + { + "filePath": "src/App.tsx", + "ruleId": "@stylistic/arrow-spacing", + "line": 54, + "column": 73, + "message": "Missing space before =>." + }, + { + "filePath": "src/App.tsx", + "ruleId": "@stylistic/space-infix-ops", + "line": 58, + "column": 6, + "message": "Operator '>' must be spaced." + }, + { + "filePath": "src/App.tsx", + "ruleId": "@stylistic/arrow-spacing", + "line": 61, + "column": 87, + "message": "Missing space before =>." + }, + { + "filePath": "src/StartupjsUiMdxComponents.js", + "ruleId": "@stylistic/indent", + "line": 269, + "column": 9, + "message": "Expected indentation of 4 spaces but found 6." + }, + { + "filePath": "src/StartupjsUiMdxComponents.js", + "ruleId": "@stylistic/indent", + "line": 270, + "column": 16, + "message": "Expected indentation of 2 spaces but found 4." + }, + { + "filePath": "src/StartupjsUiMdxComponents.js", + "ruleId": "@stylistic/arrow-spacing", + "line": 304, + "column": 40, + "message": "Missing space before =>." + }, + { + "filePath": "src/StartupjsUiTextInput.tsx", + "ruleId": "@stylistic/indent", + "line": 213, + "column": 5, + "message": "Expected indentation of 4 spaces but found 6." + }, + { + "filePath": "src/StartupjsUiTextInput.tsx", + "ruleId": "@stylistic/indent", + "line": 214, + "column": 5, + "message": "Expected indentation of 4 spaces but found 6." + }, + { + "filePath": "src/StartupjsUiTextInput.tsx", + "ruleId": "@stylistic/indent", + "line": 216, + "column": 4, + "message": "Expected indentation of 2 spaces but found 4." + }, + { + "filePath": "src/StartupjsUiWrapInput.tsx", + "ruleId": "@stylistic/indent", + "line": 166, + "column": 11, + "message": "Expected indentation of 4 spaces but found 6." + }, + { + "filePath": "src/StartupjsUiWrapInput.tsx", + "ruleId": "@stylistic/indent", + "line": 180, + "column": 19, + "message": "Expected indentation of 4 spaces but found 8." + }, + { + "filePath": "src/StartupjsUiWrapInput.tsx", + "ruleId": "@stylistic/indent", + "line": 181, + "column": 13, + "message": "Expected indentation of 4 spaces but found 8." + }, + { + "filePath": "src/StartupjsUiWrapInput.tsx", + "ruleId": "@stylistic/indent", + "line": 182, + "column": 18, + "message": "Expected indentation of 4 spaces but found 8." + }, + { + "filePath": "src/StartupjsUiWrapInput.tsx", + "ruleId": "@stylistic/indent", + "line": 182, + "column": 41, + "message": "Expected indentation of 2 spaces but found 6." + }, + { + "filePath": "src/StartupjsUiWrapInput.tsx", + "ruleId": "@stylistic/indent", + "line": 228, + "column": 13, + "message": "Expected indentation of 4 spaces but found 8." + }, + { + "filePath": "src/StartupjsUiWrapInput.tsx", + "ruleId": "@stylistic/indent", + "line": 229, + "column": 7, + "message": "Expected indentation of 4 spaces but found 8." + }, + { + "filePath": "src/StartupjsUiWrapInput.tsx", + "ruleId": "@stylistic/indent", + "line": 231, + "column": 15, + "message": "Expected indentation of 2 spaces but found 6." + }, + { + "filePath": "src/TypeScriptErrorsInPug.tsx", + "ruleId": "@stylistic/no-extra-parens", + "line": 23, + "column": 24, + "message": "Unnecessary parentheses around expression." + }, + { + "filePath": "src/TypeScriptErrorsInPug.tsx", + "ruleId": "@stylistic/no-extra-parens", + "line": 26, + "column": 3, + "message": "Unnecessary parentheses around expression." + }, + { + "filePath": "src/TypeScriptInPug.tsx", + "ruleId": "@stylistic/indent", + "line": 49, + "column": 16, + "message": "Expected indentation of 2 spaces but found 3." + }, + { + "filePath": "src/TypeScriptInPug.tsx", + "ruleId": "@stylistic/no-extra-parens", + "line": 51, + "column": 21, + "message": "Unnecessary parentheses around expression." + } +] diff --git a/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.js.diagnostics.txt b/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.js.diagnostics.txt index 713796e..746119a 100644 --- a/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.js.diagnostics.txt +++ b/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.js.diagnostics.txt @@ -1 +1,6 @@ -Found 0 errors. \ No newline at end of file +/Users/cray0000/ws/www/vscode-pug-react/test/fixtures/real-project/cat-profile-link.js + 36:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 37:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 39:1 error Expected indentation of 2 spaces but found 4. @stylistic/indent + +Found 3 errors in 1 files. \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.tsx.diagnostics.txt b/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.tsx.diagnostics.txt index 713796e..eeabf30 100644 --- a/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.tsx.diagnostics.txt +++ b/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.tsx.diagnostics.txt @@ -1 +1,6 @@ -Found 0 errors. \ No newline at end of file +/Users/cray0000/ws/www/vscode-pug-react/test/fixtures/real-project/cat-profile-link.tsx + 36:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 37:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 39:1 error Expected indentation of 2 spaces but found 4. @stylistic/indent + +Found 3 errors in 1 files. \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.js.diagnostics.txt b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.js.diagnostics.txt index 713796e..1712a76 100644 --- a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.js.diagnostics.txt +++ b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.js.diagnostics.txt @@ -1 +1,5 @@ -Found 0 errors. \ No newline at end of file +/Users/cray0000/ws/www/vscode-pug-react/test/fixtures/real-project/event-tabs-breed.js + 79:21 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 81:15 error Expected indentation of 2 spaces but found 6. @stylistic/indent + +Found 2 errors in 1 files. \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.tsx.diagnostics.txt b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.tsx.diagnostics.txt index 713796e..f13f70f 100644 --- a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.tsx.diagnostics.txt +++ b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.tsx.diagnostics.txt @@ -1 +1,5 @@ -Found 0 errors. \ No newline at end of file +/Users/cray0000/ws/www/vscode-pug-react/test/fixtures/real-project/event-tabs-breed.tsx + 79:21 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 81:15 error Expected indentation of 2 spaces but found 6. @stylistic/indent + +Found 2 errors in 1 files. \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.js.diagnostics.txt b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.js.diagnostics.txt index 713796e..e1ac88d 100644 --- a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.js.diagnostics.txt +++ b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.js.diagnostics.txt @@ -1 +1,26 @@ -Found 0 errors. \ No newline at end of file +/Users/cray0000/ws/www/vscode-pug-react/test/fixtures/real-project/event-tabs-layout.js + 25:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 26:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 28:5 error Expected indentation of 2 spaces but found 4. @stylistic/indent + 32:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 33:1 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 34:1 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 35:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 36:13 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 39:3 error Expected indentation of 2 spaces but found 4. @stylistic/indent + 42:16 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 43:20 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 46:13 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 50:2 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 52:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 55:26 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 56:30 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 60:4 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 63:6 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 64:7 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 67:11 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 70:3 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 70:32 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 72:7 error Expected indentation of 2 spaces but found 6. @stylistic/indent + +Found 23 errors in 1 files. \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.tsx.diagnostics.txt b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.tsx.diagnostics.txt index 713796e..e12013a 100644 --- a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.tsx.diagnostics.txt +++ b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.tsx.diagnostics.txt @@ -1 +1,26 @@ -Found 0 errors. \ No newline at end of file +/Users/cray0000/ws/www/vscode-pug-react/test/fixtures/real-project/event-tabs-layout.tsx + 25:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 26:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 28:5 error Expected indentation of 2 spaces but found 4. @stylistic/indent + 32:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 33:1 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 34:1 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 35:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 36:13 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 39:3 error Expected indentation of 2 spaces but found 4. @stylistic/indent + 42:16 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 43:20 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 46:13 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 50:2 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 52:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 55:26 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 56:30 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 60:4 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 63:6 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 64:7 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 67:11 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 70:3 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 70:32 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 72:7 error Expected indentation of 2 spaces but found 6. @stylistic/indent + +Found 23 errors in 1 files. \ No newline at end of file From 9ca48f8dda09d99830d4ce47edb8a56196e7f7e0 Mon Sep 17 00:00:00 2001 From: Pavel Zhukov Date: Wed, 15 Apr 2026 19:32:21 +0300 Subject: [PATCH 3/9] test: expand embedded pug lint coverage --- .../test/integration/diagnostics.test.ts | 349 ++++++++++++------ .../test/unit/processor.test.ts | 10 +- .../test/unit/lintTransform.test.ts | 34 ++ .../react-pug-core/test/unit/pugToTsx.test.ts | 29 ++ 4 files changed, 302 insertions(+), 120 deletions(-) diff --git a/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts b/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts index 3262340..4b708ec 100644 --- a/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts +++ b/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts @@ -15,6 +15,55 @@ function offsetToLineColumn(text: string, offset: number) { } } +function createProcessorEslint() { + return new ESLint({ + cwd: repoRoot, + fix: false, + ignore: false, + overrideConfigFile: true, + overrideConfig: [ + ...neostandard({ + ts: true, + }), + { + plugins: { + 'react-pug': reactPugPlugin as any, + }, + processor: 'react-pug/react-pug', + }, + ] as any, + }) +} + +function expectExactMappedMessage( + input: string, + messages: EslintLintMessage[], + ruleId: string, + snippet: string, +) { + const matches = messages.filter((message) => ( + message.ruleId === ruleId + && message.message.includes(snippet) + )) + + expect(matches).toHaveLength(1) + const expectedStart = input.indexOf(snippet) + expect(expectedStart).toBeGreaterThanOrEqual(0) + const expected = offsetToLineColumn(input, expectedStart) + expect(matches[0].line).toBe(expected.line) + expect(matches[0].column).toBe(expected.column) + expect(matches[0].endLine).toBe(expected.line) + expect(matches[0].endColumn).toBe(expected.column + snippet.length) +} + +function findLineIndex(lines: string[], snippet: string, fromIndex = 0) { + const index = lines.findIndex((line, lineIndex) => lineIndex >= fromIndex && line === snippet) + expect(index).toBeGreaterThanOrEqual(0) + return index +} + +type EslintLintMessage = Awaited>[number]['messages'][number] + describe('eslint processor diagnostic mapping', () => { it('suppresses legacy styl tagged-template statement warnings', async () => { const filePath = resolve(repoRoot, 'legacy-styl.js') @@ -33,23 +82,7 @@ describe('eslint processor diagnostic mapping', () => { '', ].join('\n') - const eslint = new ESLint({ - cwd: repoRoot, - fix: false, - ignore: false, - overrideConfigFile: true, - overrideConfig: [ - ...neostandard({ - ts: true, - }), - { - plugins: { - 'react-pug': reactPugPlugin as any, - }, - processor: 'react-pug/react-pug', - }, - ] as any, - }) + const eslint = createProcessorEslint() const [result] = await eslint.lintText(input, { filePath }) expect(result.messages.some(message => message.ruleId === 'no-unused-expressions')).toBe(false) @@ -88,23 +121,7 @@ describe('eslint processor diagnostic mapping', () => { '', ].join('\n') - const eslint = new ESLint({ - cwd: repoRoot, - fix: false, - ignore: false, - overrideConfigFile: true, - overrideConfig: [ - ...neostandard({ - ts: true, - }), - { - plugins: { - 'react-pug': reactPugPlugin as any, - }, - processor: 'react-pug/react-pug', - }, - ] as any, - }) + const eslint = createProcessorEslint() const [result] = await eslint.lintText(input, { filePath }) expect(result.messages.some(message => message.ruleId === '@stylistic/indent')).toBe(false) @@ -122,23 +139,7 @@ describe('eslint processor diagnostic mapping', () => { ].join('\n'), ) - const eslint = new ESLint({ - cwd: repoRoot, - fix: false, - ignore: false, - overrideConfigFile: true, - overrideConfig: [ - ...neostandard({ - ts: true, - }), - { - plugins: { - 'react-pug': reactPugPlugin as any, - }, - processor: 'react-pug/react-pug', - }, - ] as any, - }) + const eslint = createProcessorEslint() const [result] = await eslint.lintText(input, { filePath }) const unused = result.messages.find((message) => ( @@ -173,23 +174,7 @@ describe('eslint processor diagnostic mapping', () => { '', ].join('\n') - const eslint = new ESLint({ - cwd: repoRoot, - fix: false, - ignore: false, - overrideConfigFile: true, - overrideConfig: [ - ...neostandard({ - ts: true, - }), - { - plugins: { - 'react-pug': reactPugPlugin as any, - }, - processor: 'react-pug/react-pug', - }, - ] as any, - }) + const eslint = createProcessorEslint() const [result] = await eslint.lintText(input, { filePath }) expect(result.messages.filter(message => message.ruleId === '@stylistic/indent')).toEqual([]) @@ -216,23 +201,7 @@ describe('eslint processor diagnostic mapping', () => { '', ].join('\n') - const eslint = new ESLint({ - cwd: repoRoot, - fix: false, - ignore: false, - overrideConfigFile: true, - overrideConfig: [ - ...neostandard({ - ts: true, - }), - { - plugins: { - 'react-pug': reactPugPlugin as any, - }, - processor: 'react-pug/react-pug', - }, - ] as any, - }) + const eslint = createProcessorEslint() const [result] = await eslint.lintText(input, { filePath }) const unknown = result.messages.find((message) => ( @@ -270,23 +239,7 @@ describe('eslint processor diagnostic mapping', () => { '', ].join('\n') - const eslint = new ESLint({ - cwd: repoRoot, - fix: false, - ignore: false, - overrideConfigFile: true, - overrideConfig: [ - ...neostandard({ - ts: true, - }), - { - plugins: { - 'react-pug': reactPugPlugin as any, - }, - processor: 'react-pug/react-pug', - }, - ] as any, - }) + const eslint = createProcessorEslint() const [result] = await eslint.lintText(input, { filePath }) const indentMessages = result.messages.filter(message => message.ruleId === '@stylistic/indent') @@ -313,27 +266,185 @@ describe('eslint processor diagnostic mapping', () => { '', ].join('\n') - const eslint = new ESLint({ - cwd: repoRoot, - fix: false, - ignore: false, - overrideConfigFile: true, - overrideConfig: [ - ...neostandard({ - ts: true, - }), - { - plugins: { - 'react-pug': reactPugPlugin as any, - }, - processor: 'react-pug/react-pug', - }, - ] as any, - }) + const eslint = createProcessorEslint() const [result] = await eslint.lintText(input, { filePath }) const indentMessages = result.messages.filter(message => message.ruleId === '@stylistic/indent') expect(indentMessages.length).toBeGreaterThan(0) expect(indentMessages.some(message => (message.line ?? 0) >= 8 && (message.line ?? 0) <= 10)).toBe(true) }) + + it('maps exact no-undef ranges across the embedded JS site matrix, including unbuffered statement lines', async () => { + const filePath = resolve(repoRoot, 'embedded-site-matrix.js') + const input = [ + "import { pug } from 'startupjs'", + "const knownAttr = 'attr'", + "const knownBuffered = 'buffered'", + "const knownInterpolation = 'interp'", + 'const knownTemplate = 1', + 'const knownStatement = 2', + 'const ready = true', + '', + 'export default pug`', + ' Button(', + ' label=knownAttr + missingAttrValue', + ' onClick=() => {', + ' if (ready) {', + ' return missingHandlerValue', + ' }', + ' return knownAttr', + ' }', + ' ) Save', + ' p= knownBuffered + missingBufferedValue', + ' p Hello #{knownInterpolation + missingInterpolationValue}', + ' Span.text= ${knownTemplate + missingTemplateValue}', + ' - const local = knownStatement + missingStatementValue', + ' if local', + ' p Visible', + '`', + '', + ].join('\n') + + const eslint = createProcessorEslint() + const [result] = await eslint.lintText(input, { filePath }) + + expectExactMappedMessage(input, result.messages, 'no-undef', 'missingAttrValue') + expectExactMappedMessage(input, result.messages, 'no-undef', 'missingHandlerValue') + expectExactMappedMessage(input, result.messages, 'no-undef', 'missingBufferedValue') + expectExactMappedMessage(input, result.messages, 'no-undef', 'missingInterpolationValue') + expectExactMappedMessage(input, result.messages, 'no-undef', 'missingTemplateValue') + expectExactMappedMessage(input, result.messages, 'no-undef', 'missingStatementValue') + }) + + it.fails('maps exact @typescript-eslint/no-unused-vars ranges across complex embedded TS expression sites', async () => { + const filePath = resolve(repoRoot, 'embedded-ts-site-matrix.tsx') + const input = [ + "import { pug } from 'startupjs'", + "const known = 'ok'", + "const item = { id: '1' }", + '', + 'export default pug`', + ' Button(', + ' label=((value: string) => {', + ' const unusedAttrValue = value', + ' return value', + ' })(known)', + ' onClick=() => {', + ' const unusedHandlerValue = item.id', + ' return item.id', + ' }', + ' ) Save', + ' p= (() => {', + ' const unusedBufferedValue = known', + ' return known', + ' })()', + ' p Hello #{(() => {', + ' const unusedInterpolationValue = known', + ' return known', + ' })()}', + ' Span.text= ${(() => {', + ' const unusedTemplateValue = known', + ' return known', + ' })()}', + '`', + '', + ].join('\n') + + const eslint = createProcessorEslint() + const [result] = await eslint.lintText(input, { filePath }) + + expectExactMappedMessage(input, result.messages, '@typescript-eslint/no-unused-vars', 'unusedAttrValue') + expectExactMappedMessage(input, result.messages, '@typescript-eslint/no-unused-vars', 'unusedHandlerValue') + expectExactMappedMessage(input, result.messages, '@typescript-eslint/no-unused-vars', 'unusedBufferedValue') + expectExactMappedMessage(input, result.messages, '@typescript-eslint/no-unused-vars', 'unusedInterpolationValue') + expectExactMappedMessage(input, result.messages, '@typescript-eslint/no-unused-vars', 'unusedTemplateValue') + }) + + it.fails('reports source-faithful indent diagnostics across the embedded expression-site matrix without synthetic noise', async () => { + const filePath = resolve(repoRoot, 'embedded-style-matrix.js') + const lines = [ + "import { pug } from 'startupjs'", + 'const ready = true', + 'const formatLabel = (value) => value', + "const fallbackLabel = 'fallback'", + 'const runHandler = () => {}', + 'const runBuffered = () => {}', + 'const runInterpolation = () => {}', + "const label = 'label'", + "const suffix = 'suffix'", + 'const count = 1', + '', + 'export default pug`', + ' Button(', + ' label=(', + ' ready', + ' ? formatLabel(label)', + ' : fallbackLabel', + ' )', + ' onClick=() => {', + ' if (ready) {', + ' runHandler()', + ' }', + ' return label', + ' }', + ' ) Save', + ' p= (() => {', + ' if (ready) {', + ' runBuffered()', + ' }', + ' return label', + ' })()', + ' p Hello #{(() => {', + ' if (ready) {', + ' runInterpolation()', + ' }', + ' return suffix', + ' })()}', + ' Span.text= ${count', + ' ? label', + ' : suffix', + ' }', + '`', + '', + ] + const input = lines.join('\n') + const eslint = createProcessorEslint() + const [result] = await eslint.lintText(input, { filePath }) + const indentMessages = result.messages.filter(message => message.ruleId === '@stylistic/indent') + + expect(indentMessages.length).toBeGreaterThan(0) + + const attrStart = findLineIndex(lines, ' label=(') + 1 + const attrEnd = findLineIndex(lines, ' )', attrStart) + 1 + const handlerStart = findLineIndex(lines, ' onClick=() => {') + 1 + const handlerEnd = findLineIndex(lines, ' }', handlerStart) + 1 + const bufferedStart = findLineIndex(lines, ' p= (() => {') + 1 + const bufferedEnd = findLineIndex(lines, ' })()', bufferedStart) + 1 + const interpolationStart = findLineIndex(lines, ' p Hello #{(() => {') + 1 + const interpolationEnd = findLineIndex(lines, ' })()}', interpolationStart) + 1 + const templateStart = findLineIndex(lines, ' Span.text= ${count') + 1 + const templateEnd = findLineIndex(lines, ' }', templateStart) + 1 + + const expectedRanges = [ + { start: attrStart, end: attrEnd }, + { start: handlerStart, end: handlerEnd }, + { start: bufferedStart, end: bufferedEnd }, + { start: interpolationStart, end: interpolationEnd }, + { start: templateStart, end: templateEnd }, + ] + + for (const range of expectedRanges) { + expect(indentMessages.some((message) => ( + (message.line ?? 0) >= range.start + && (message.line ?? 0) <= range.end + ))).toBe(true) + } + + expect(indentMessages.every((message) => ( + expectedRanges.some((range) => ( + (message.line ?? 0) >= range.start + && (message.line ?? 0) <= range.end + )) + ))).toBe(true) + }) }) diff --git a/packages/eslint-plugin-react-pug/test/unit/processor.test.ts b/packages/eslint-plugin-react-pug/test/unit/processor.test.ts index 68a43f9..618332e 100644 --- a/packages/eslint-plugin-react-pug/test/unit/processor.test.ts +++ b/packages/eslint-plugin-react-pug/test/unit/processor.test.ts @@ -622,7 +622,11 @@ describe('eslint-plugin-react-pug processor', () => { const processor = createReactPugProcessor(); const input = [ 'const view = pug`', - ' Button(onClick=() => run()) Save', + ' Button(', + ' label=knownAttr + missingAttrValue', + ' onClick=() => run(item.id)', + ' ) Save', + ' p Hello #{knownInterpolation + missingInterpolationValue}', ' - const visible = ready', '`', ].join('\n'); @@ -635,6 +639,10 @@ describe('eslint-plugin-react-pug processor', () => { expect(blocks[2]).toMatchObject({ filename: '../../../pug-react-embedded-statement.jsx', }); + expect((blocks[1] as any).text).toContain('const __reactPugExpr0 = (\n knownAttr + missingAttrValue\n)'); + expect((blocks[1] as any).text).toContain('const __reactPugExpr1 = (\n () => run(item.id)\n)'); + expect((blocks[1] as any).text).toContain('const __reactPugExpr2 = (\n knownInterpolation + missingInterpolationValue\n)'); + expect((blocks[2] as any).text).toContain('(() => {\n const visible = ready\n})()'); }); it('suppresses legacy styl warnings without hiding normal linting', () => { diff --git a/packages/react-pug-core/test/unit/lintTransform.test.ts b/packages/react-pug-core/test/unit/lintTransform.test.ts index 7f8b20a..f999265 100644 --- a/packages/react-pug-core/test/unit/lintTransform.test.ts +++ b/packages/react-pug-core/test/unit/lintTransform.test.ts @@ -274,4 +274,38 @@ describe('lintTransform', () => { '() => run(item.id)', ]) }) + + it('maps the embedded JS site matrix back to exact original source starts in order', () => { + const source = [ + "import { pug } from 'startupjs'", + 'export default pug`', + ' Button(', + ' label=knownAttr + missingAttrValue', + ' onClick=() => {', + ' return missingHandlerValue', + ' }', + ' ) Save', + ' p= knownBuffered + missingBufferedValue', + ' p Hello #{knownInterpolation + missingInterpolationValue}', + ' Span.text= ${knownTemplate + missingTemplateValue}', + ' - const local = knownStatement + missingStatementValue', + '`', + ].join('\n') + + const result = createLintTransform(source, 'file.jsx') + const expectedSites = [ + { kind: 'expression', source: 'knownAttr + missingAttrValue' }, + { kind: 'expression', source: '() => {\n return missingHandlerValue\n }' }, + { kind: 'expression', source: 'knownBuffered + missingBufferedValue' }, + { kind: 'expression', source: 'knownInterpolation + missingInterpolationValue' }, + { kind: 'expression', source: 'knownTemplate + missingTemplateValue' }, + { kind: 'statement', source: 'const local = knownStatement + missingStatementValue' }, + ] + const actualSites = [...result.embeddedJsLintSites] + .sort((a, b) => a.originalStart - b.originalStart) + expect(actualSites.map(site => site.kind)).toEqual(expectedSites.map(site => site.kind)) + expectedSites.forEach((expectedSite, index) => { + expect(source.startsWith(expectedSite.source, actualSites[index].originalStart)).toBe(true) + }) + }) }) diff --git a/packages/react-pug-core/test/unit/pugToTsx.test.ts b/packages/react-pug-core/test/unit/pugToTsx.test.ts index abe9e1f..89825c3 100644 --- a/packages/react-pug-core/test/unit/pugToTsx.test.ts +++ b/packages/react-pug-core/test/unit/pugToTsx.test.ts @@ -1288,6 +1288,35 @@ describe('code blocks', () => { ]); }); + it('collects embedded lint sites across all supported source positions in source order', () => { + const pug = [ + 'Button(', + ' label=knownAttr + missingAttrValue', + ' onClick=() => {', + ' return missingHandlerValue', + ' }', + ') Save', + 'p= knownBuffered + missingBufferedValue', + 'p Hello #{knownInterpolation + missingInterpolationValue}', + 'Span.text= ${knownTemplate + missingTemplateValue}', + '- const local = knownStatement + missingStatementValue', + ].join('\n'); + + const result = compilePugToTsx(pug, { mode: 'runtime' }); + expect(result.embeddedJsLintSites).toHaveLength(6); + expect(result.embeddedJsLintSites.map(site => ({ + kind: site.kind, + code: site.code, + }))).toEqual(expect.arrayContaining([ + { kind: 'expression', code: 'knownAttr + missingAttrValue' }, + { kind: 'expression', code: '() => {\n return missingHandlerValue\n }' }, + { kind: 'expression', code: 'knownBuffered + missingBufferedValue' }, + { kind: 'expression', code: 'knownInterpolation + missingInterpolationValue' }, + { kind: 'expression', code: 'knownTemplate + missingTemplateValue' }, + { kind: 'statement', code: 'const local = knownStatement + missingStatementValue' }, + ])); + }); + it('collects embedded statement lint sites for unbuffered code blocks', () => { const pug = '- const visible = ready\nDiv Done'; From 1c794cc116a453683dfcadbd498ed83b5dad60f8 Mon Sep 17 00:00:00 2001 From: Pavel Zhukov Date: Wed, 15 Apr 2026 20:47:02 +0300 Subject: [PATCH 4/9] fix: preserve embedded pug autofixes and mappings --- packages/eslint-plugin-react-pug/src/index.ts | 255 ++++++++++++++---- .../test/integration/autofix.test.ts | 88 +++++- .../startupjs-ui-regressions.test.ts | 5 +- .../test/unit/processor.test.ts | 120 ++++++++- .../src/language/lintTransform.ts | 28 +- .../react-pug-core/src/language/pugToTsx.ts | 18 +- .../src/language/regionOffsetMapping.ts | 7 +- .../react-pug-core/test/unit/pugToTsx.test.ts | 14 + .../test/unit/queryMapping.test.ts | 10 + .../snapshots/diagnostics/src/App.tsx.txt | 11 +- .../src/StartupjsUiMdxComponents.js.txt | 4 +- .../src/StartupjsUiTextInput.tsx.txt | 2 +- .../src/StartupjsUiWrapInput.tsx.txt | 13 +- .../src/TypeScriptErrorsInPug.tsx.txt | 4 +- .../diagnostics/src/TypeScriptInPug.tsx.txt | 4 +- .../snapshots/fixed/src/App.tsx | 10 +- .../fixed/src/StartupjsUiMdxComponents.js | 2 +- .../fixed/src/TypeScriptErrorsInPug.tsx | 4 +- .../snapshots/fixed/src/TypeScriptInPug.tsx | 2 +- .../snapshots/post-fix-diagnostics.json | 94 ++----- .../babel/CatCard.js.output.sourcemap.json | 2 +- .../babel/CatCard.tsx.output.sourcemap.json | 2 +- .../cat-profile-link.js.output.sourcemap.json | 2 +- ...cat-profile-link.tsx.output.sourcemap.json | 2 +- .../event-tabs-breed.js.output.sourcemap.json | 2 +- ...event-tabs-breed.tsx.output.sourcemap.json | 2 +- ...event-tabs-layout.js.output.sourcemap.json | 2 +- ...vent-tabs-layout.tsx.output.sourcemap.json | 2 +- .../esbuild/CatCard.js.output.sourcemap.json | 2 +- .../esbuild/CatCard.tsx.output.sourcemap.json | 2 +- .../cat-profile-link.js.output.sourcemap.json | 2 +- ...cat-profile-link.tsx.output.sourcemap.json | 2 +- .../event-tabs-breed.js.output.sourcemap.json | 2 +- ...event-tabs-breed.tsx.output.sourcemap.json | 2 +- ...event-tabs-layout.js.output.sourcemap.json | 2 +- ...vent-tabs-layout.tsx.output.sourcemap.json | 2 +- .../cat-profile-link.js.diagnostics.txt | 2 +- .../cat-profile-link.tsx.diagnostics.txt | 2 +- .../event-tabs-breed.js.diagnostics.txt | 4 +- .../event-tabs-breed.tsx.diagnostics.txt | 4 +- .../event-tabs-layout.js.diagnostics.txt | 38 +-- .../event-tabs-layout.tsx.diagnostics.txt | 38 +-- .../shadow/CatCard.js.output.sourcemap.json | 2 +- .../shadow/CatCard.tsx.output.sourcemap.json | 2 +- .../cat-profile-link.js.output.sourcemap.json | 2 +- ...cat-profile-link.tsx.output.sourcemap.json | 2 +- .../event-tabs-breed.js.output.sourcemap.json | 2 +- ...event-tabs-breed.tsx.output.sourcemap.json | 2 +- ...event-tabs-layout.js.output.sourcemap.json | 2 +- ...vent-tabs-layout.tsx.output.sourcemap.json | 2 +- .../swc/CatCard.js.output.sourcemap.json | 2 +- .../swc/CatCard.tsx.output.sourcemap.json | 2 +- .../cat-profile-link.js.output.sourcemap.json | 2 +- ...cat-profile-link.tsx.output.sourcemap.json | 2 +- .../event-tabs-breed.js.output.sourcemap.json | 2 +- ...event-tabs-breed.tsx.output.sourcemap.json | 2 +- ...event-tabs-layout.js.output.sourcemap.json | 2 +- ...vent-tabs-layout.tsx.output.sourcemap.json | 2 +- 58 files changed, 582 insertions(+), 265 deletions(-) diff --git a/packages/eslint-plugin-react-pug/src/index.ts b/packages/eslint-plugin-react-pug/src/index.ts index d8df3ed..eaa1d74 100644 --- a/packages/eslint-plugin-react-pug/src/index.ts +++ b/packages/eslint-plugin-react-pug/src/index.ts @@ -13,6 +13,7 @@ import { offsetToLineColumn, rewriteSegmentedPugRegions, type BoundaryMappedExpression, + type MappedEmbeddedJsLintSite, type RewrittenPugRegionsResult, type RegionFormattingContext, type StartupjsCssxjsOption, @@ -70,7 +71,9 @@ interface CachedLintState { interface EmbeddedLintBlockState { text: string; filename: string; + site: MappedEmbeddedJsLintSite; boundaryMap: Array; + endBoundaryMap: Array; syntheticRanges: InsertionOffsetRange[]; } @@ -311,6 +314,7 @@ function getExpressionParserPlugins(filename: string): any[] { interface EmbeddedLintBlockBuilder { text: string; boundaryMap: Array; + endBoundaryMap: Array; syntheticRanges: InsertionOffsetRange[]; } @@ -322,27 +326,41 @@ function appendSyntheticBlockText( const start = builder.text.length; if (builder.boundaryMap.length === 0) builder.boundaryMap.push(null); else builder.boundaryMap[builder.boundaryMap.length - 1] = null; + if (builder.endBoundaryMap.length === 0) builder.endBoundaryMap.push(null); builder.text += text; - for (let i = 0; i < text.length; i += 1) builder.boundaryMap.push(null); + for (let i = 0; i < text.length; i += 1) { + builder.boundaryMap.push(null); + builder.endBoundaryMap.push(null); + } builder.syntheticRanges.push({ start, end: builder.text.length }); } function appendMappedBlockText( builder: EmbeddedLintBlockBuilder, text: string, - boundaryMap: number[], + boundaryMap: Array, ): void { if (text.length === 0) { - if (builder.boundaryMap.length === 0) builder.boundaryMap.push(boundaryMap[0] ?? null); + if (builder.boundaryMap.length === 0) { + builder.boundaryMap.push(boundaryMap[0] ?? null); + builder.endBoundaryMap.push(boundaryMap[0] ?? null); + } return; } - if (builder.boundaryMap.length === 0) builder.boundaryMap.push(boundaryMap[0] ?? null); - else builder.boundaryMap[builder.boundaryMap.length - 1] = boundaryMap[0] ?? null; + if (builder.boundaryMap.length === 0) { + builder.boundaryMap.push(boundaryMap[0] ?? null); + builder.endBoundaryMap.push(boundaryMap[0] ?? null); + } else { + builder.boundaryMap[builder.boundaryMap.length - 1] = boundaryMap[0] ?? null; + builder.endBoundaryMap[builder.endBoundaryMap.length - 1] = boundaryMap[0] ?? null; + } builder.text += text; for (let i = 0; i < text.length; i += 1) { - builder.boundaryMap.push(boundaryMap[i + 1] ?? null); + const mappedBoundary = boundaryMap[i + 1] ?? null; + builder.boundaryMap.push(mappedBoundary); + builder.endBoundaryMap.push(mappedBoundary); } } @@ -363,64 +381,44 @@ function appendMappedCodeWithIndent( function createEmbeddedLintBlockFilename( filename: string, kind: 'expression' | 'statement', + index: number, ): string { const suffix = isTypeScriptLikeFilename(filename) ? 'tsx' : 'jsx'; - return `../../../pug-react-embedded-${kind}.${suffix}`; + return `../../../pug-react-embedded-${kind}-${index}.${suffix}`; } function createEmbeddedLintBlocks(transformed: LintTransformState, filename: string): EmbeddedLintBlockState[] { - const expressionSites = transformed.embeddedJsLintSites.filter(site => site.kind === 'expression'); - const statementSites = transformed.embeddedJsLintSites.filter(site => site.kind === 'statement'); const blocks: EmbeddedLintBlockState[] = []; - const buildExpressionBlock = () => { - if (expressionSites.length === 0) return; + transformed.embeddedJsLintSites.forEach((site, index) => { const builder: EmbeddedLintBlockBuilder = { text: '', boundaryMap: [], + endBoundaryMap: [], syntheticRanges: [], }; + const siteBoundaryMap = Array.from({ length: site.code.length + 1 }, (_, offset) => offset); - expressionSites.forEach((site, index) => { - appendSyntheticBlockText(builder, `const __reactPugExpr${index} = (\n`); - appendMappedCodeWithIndent(builder, site.code, site.boundaryMap, ' '); + if (site.kind === 'expression') { + appendSyntheticBlockText(builder, 'const __reactPugExpr = (\n'); + appendMappedCodeWithIndent(builder, site.code, siteBoundaryMap, ' '); appendSyntheticBlockText(builder, '\n)\n'); - if (index < expressionSites.length - 1) appendSyntheticBlockText(builder, '\n'); - }); - - blocks.push({ - text: builder.text, - filename: createEmbeddedLintBlockFilename(filename, 'expression'), - boundaryMap: builder.boundaryMap, - syntheticRanges: builder.syntheticRanges, - }); - }; - - const buildStatementBlock = () => { - if (statementSites.length === 0) return; - const builder: EmbeddedLintBlockBuilder = { - text: '', - boundaryMap: [], - syntheticRanges: [], - }; - - statementSites.forEach((site, index) => { + } else { appendSyntheticBlockText(builder, '(() => {\n'); - appendMappedCodeWithIndent(builder, site.code, site.boundaryMap, ' '); + appendMappedCodeWithIndent(builder, site.code, siteBoundaryMap, ' '); appendSyntheticBlockText(builder, '\n})()\n'); - if (index < statementSites.length - 1) appendSyntheticBlockText(builder, '\n'); - }); + } blocks.push({ text: builder.text, - filename: createEmbeddedLintBlockFilename(filename, 'statement'), + filename: createEmbeddedLintBlockFilename(filename, site.kind, index), + site, boundaryMap: builder.boundaryMap, + endBoundaryMap: builder.endBoundaryMap, syntheticRanges: builder.syntheticRanges, }); - }; + }); - buildExpressionBlock(); - buildStatementBlock(); return blocks; } @@ -868,7 +866,7 @@ function mapLintMessage( }; } -function mapEmbeddedLintOffsetToOriginal( +function mapEmbeddedLintOffsetToSite( block: EmbeddedLintBlockState, offset: number, ): number | null { @@ -876,6 +874,22 @@ function mapEmbeddedLintOffsetToOriginal( return block.boundaryMap[clamped] ?? null; } +function mapEmbeddedLintEndOffsetToSite( + block: EmbeddedLintBlockState, + offset: number, +): number | null { + const clamped = Math.max(0, Math.min(offset, block.text.length)); + return block.endBoundaryMap[clamped] ?? null; +} + +function mapEmbeddedSiteOffsetToOriginal( + site: MappedEmbeddedJsLintSite, + offset: number, +): number | null { + const clamped = Math.max(0, Math.min(offset, site.code.length)); + return site.boundaryMap[clamped] ?? null; +} + function findLineBounds(text: string, offset: number): { start: number; end: number } { const clamped = Math.max(0, Math.min(offset, text.length)); const start = text.lastIndexOf('\n', Math.max(0, clamped - 1)) + 1; @@ -903,15 +917,115 @@ function findLastMappableOffsetOnLine( ): number | null { const { start, end } = findLineBounds(block.text, offset); for (let index = Math.max(start, Math.min(offset, end)); index >= start; index -= 1) { - if (block.boundaryMap[index] != null) return index; + if (block.endBoundaryMap[index] != null) return index; } return null; } +function mapEmbeddedLintFix( + fix: EslintLintMessage['fix'] | undefined, + block: EmbeddedLintBlockState, + originalText: string, +): EslintLintMessage['fix'] | undefined { + if (!fix) return undefined; + const [start, end] = fix.range; + if (overlapsRangeList(block.syntheticRanges, start, end)) return undefined; + + const localStart = mapEmbeddedLintOffsetToSite(block, start); + const localEnd = mapEmbeddedLintEndOffsetToSite(block, end); + if (localStart == null || localEnd == null) return undefined; + + const originalStart = mapEmbeddedSiteOffsetToOriginal(block.site, localStart); + const originalEnd = mapEmbeddedSiteOffsetToOriginal(block.site, localEnd); + if (originalStart == null || originalEnd == null) return undefined; + + const originalSiteText = originalText.slice(block.site.originalStart, block.site.originalEnd); + const relativeStart = originalStart - block.site.originalStart; + const relativeEnd = originalEnd - block.site.originalStart; + const replacedSiteText = `${originalSiteText.slice(0, relativeStart)}${fix.text}${originalSiteText.slice(relativeEnd)}`; + + return { + ...fix, + range: [block.site.originalStart, block.site.originalEnd], + text: replacedSiteText, + }; +} + +function mapEmbeddedLintSuggestions( + suggestions: EslintLintMessage['suggestions'], + block: EmbeddedLintBlockState, + originalText: string, +): EslintLintMessage['suggestions'] | undefined { + if (!suggestions) return undefined; + + const mapped = suggestions + .map((suggestion) => { + const mappedFix = mapEmbeddedLintFix(suggestion.fix, block, originalText); + if (!mappedFix) return null; + return { + ...suggestion, + fix: mappedFix, + }; + }) + .filter((suggestion): suggestion is NonNullable => suggestion != null); + + return mapped.length > 0 ? mapped : undefined; +} + +function buildEmbeddedSiteAutofix( + messages: EslintLintMessage[], + block: EmbeddedLintBlockState, + originalText: string, +): EslintLintMessage['fix'] | undefined { + const originalSiteText = originalText.slice(block.site.originalStart, block.site.originalEnd); + const localFixes = messages + .map((message) => message.fix) + .filter((fix): fix is NonNullable => fix != null) + .map((fix) => { + const [start, end] = fix.range; + if (overlapsRangeList(block.syntheticRanges, start, end)) return null; + const localStart = mapEmbeddedLintOffsetToSite(block, start); + const localEnd = mapEmbeddedLintEndOffsetToSite(block, end); + if (localStart == null || localEnd == null) return null; + return { + start: localStart, + end: localEnd, + text: fix.text, + }; + }) + .filter((fix): fix is NonNullable => fix != null) + .sort((a, b) => a.start - b.start || a.end - b.end); + + if (localFixes.length === 0) return undefined; + + let cursor = 0; + let output = ''; + let applied = false; + for (const fix of localFixes) { + if (fix.start < cursor) continue; + output += originalSiteText.slice(cursor, fix.start); + output += fix.text; + cursor = fix.end; + applied = true; + } + output += originalSiteText.slice(cursor); + + if (!applied || output === originalSiteText) return undefined; + + return { + range: [block.site.originalStart, block.site.originalEnd], + text: output, + }; +} + function mapEmbeddedLintMessage( message: EslintLintMessage, block: EmbeddedLintBlockState, originalText: string, + options: { + includeFix?: boolean; + includeSuggestions?: boolean; + } = {}, ): EslintLintMessage | null { if (typeof message.ruleId !== 'string' || !message.ruleId.startsWith('@stylistic/')) { return null; @@ -933,12 +1047,22 @@ function mapEmbeddedLintMessage( mappedEndOffset = Math.max(relocatedStart + 1, relocatedEnd); } - const originalStart = mapEmbeddedLintOffsetToOriginal(block, mappedStartOffset); - const originalEnd = mapEmbeddedLintOffsetToOriginal(block, mappedEndOffset); + const localStart = mapEmbeddedLintOffsetToSite(block, mappedStartOffset); + const localEnd = mapEmbeddedLintEndOffsetToSite(block, mappedEndOffset); + if (localStart == null || localEnd == null) return null; + + const originalStart = mapEmbeddedSiteOffsetToOriginal(block.site, localStart); + const originalEnd = mapEmbeddedSiteOffsetToOriginal(block.site, localEnd); if (originalStart == null || originalEnd == null) return null; const startLc = offsetToLineColumn(originalText, originalStart); const endLc = offsetToLineColumn(originalText, originalEnd); + const mappedFix = options.includeFix === false + ? undefined + : mapEmbeddedLintFix(message.fix, block, originalText); + const mappedSuggestions = options.includeSuggestions === false + ? undefined + : mapEmbeddedLintSuggestions(message.suggestions, block, originalText); return { ...Object.fromEntries(Object.entries(message).filter(([key]) => key !== 'fix' && key !== 'suggestions')), @@ -946,6 +1070,8 @@ function mapEmbeddedLintMessage( column: startLc.column, endLine: endLc.line, endColumn: endLc.column, + ...(mappedFix ? { fix: mappedFix } : {}), + ...(mappedSuggestions ? { suggestions: mappedSuggestions } : {}), }; } @@ -1066,19 +1192,44 @@ function createReactPugProcessor( embeddedMessages.forEach((blockMessages, index) => { const block = cached.embeddedLintBlocks[index]; if (!block) return; - for (const message of blockMessages) { - const mappedMessage = mapEmbeddedLintMessage(message, block, cached.originalText); - if (mappedMessage) mapped.push(mappedMessage); + const mappedBlockMessages = blockMessages + .map((message) => mapEmbeddedLintMessage(message, block, cached.originalText, { + includeFix: false, + })); + const aggregatedFix = buildEmbeddedSiteAutofix(blockMessages, block, cached.originalText); + let aggregatedFixAttached = false; + + for (const mappedMessage of mappedBlockMessages) { + if (!mappedMessage) continue; + if (!aggregatedFixAttached && aggregatedFix) { + mapped.push({ + ...mappedMessage, + fix: aggregatedFix, + }); + aggregatedFixAttached = true; + } else { + mapped.push(mappedMessage); + } } }); const deduped: EslintLintMessage[] = []; - const seen = new Set(); + const seen = new Map(); for (const message of mapped) { const key = lintMessageDedupKey(message); - if (seen.has(key)) continue; - seen.add(key); - deduped.push(message); + const existingIndex = seen.get(key); + if (existingIndex == null) { + seen.set(key, deduped.length); + deduped.push(message); + continue; + } + + const existing = deduped[existingIndex]; + const existingHasAction = !!existing.fix || ((existing.suggestions?.length ?? 0) > 0); + const incomingHasAction = !!message.fix || ((message.suggestions?.length ?? 0) > 0); + if (!existingHasAction && incomingHasAction) { + deduped[existingIndex] = message; + } } return deduped; }, diff --git a/packages/eslint-plugin-react-pug/test/integration/autofix.test.ts b/packages/eslint-plugin-react-pug/test/integration/autofix.test.ts index 7d8708a..400f7a0 100644 --- a/packages/eslint-plugin-react-pug/test/integration/autofix.test.ts +++ b/packages/eslint-plugin-react-pug/test/integration/autofix.test.ts @@ -51,6 +51,32 @@ function createExampleEslint(cwd: string, fix: boolean): ESLint { }) } +function createInlineEslint(fix: boolean): ESLint { + return new ESLint({ + cwd: repoRoot, + fix, + ignore: false, + overrideConfigFile: true, + overrideConfig: [ + { + linterOptions: { + reportUnusedDisableDirectives: 'off', + }, + }, + ...neostandard({ + ts: true, + }), + { + plugins: { + 'react-hooks': reactHooksStubPlugin as any, + 'react-pug': reactPugPlugin as any, + }, + processor: 'react-pug/react-pug', + }, + ] as any, + }) +} + function createTempFixtureCopy(): string { const tempDir = mkdtempSync(join(tmpdir(), 'react-pug-eslint-fix-')) tempDirs.push(tempDir) @@ -78,6 +104,62 @@ afterEach(() => { }) describe('eslint --fix integration for react-pug processor', () => { + it('applies multiple autofixes within a single embedded expression site without corrupting the site text', async () => { + const filePath = resolve(repoRoot, 'embedded-autofix-multi-fix.js') + const input = [ + "import { pug } from 'startupjs'", + 'const showCompleted = true', + '', + 'const view = pug`', + ' Button(', + ' label=showCompleted ? "Hide Done" : "Show Done"', + ' ) Save', + '`', + '', + ].join('\n') + + const [firstPass] = await createInlineEslint(true).lintText(input, { filePath }) + const output = firstPass.output ?? input + + expect(output).toContain("label=showCompleted ? 'Hide Done' : 'Show Done'") + expect(output).not.toContain(`'Hide Done'e"`) + + const [secondPass] = await createInlineEslint(false).lintText(output, { filePath }) + expect(secondPass.messages.some(message => message.ruleId === '@stylistic/quotes')).toBe(false) + }) + + it('applies source-faithful autofixes across embedded expression-site kinds', async () => { + const filePath = resolve(repoRoot, 'embedded-autofix-matrix.js') + const input = [ + "import { pug } from 'startupjs'", + "const label = 'label'", + "const suffix = 'suffix'", + '', + 'const view = pug`', + ' Button(', + ' label=label+suffix', + ' onClick=() => { return label+suffix }', + ' ) Save', + ' p= label+suffix', + ' p Hello #{label+suffix}', + ' Span.text= ${label+suffix}', + '`', + '', + ].join('\n') + + const [firstPass] = await createInlineEslint(true).lintText(input, { filePath }) + const output = firstPass.output ?? input + + expect(output).toContain('label=label + suffix') + expect(output).toContain('return label + suffix') + expect(output).toContain('p= label + suffix') + expect(output).toContain('p Hello #{label + suffix}') + expect(output).toContain('Span.text= ${label + suffix}') + + const [secondPass] = await createInlineEslint(false).lintText(output, { filePath }) + expect(secondPass.messages.some(message => message.ruleId === '@stylistic/space-infix-ops')).toBe(false) + }) + it('does not corrupt files and preserves only the expected non-fixable diagnostics for an unformatted example fixture', async () => { const tempDir = createTempFixtureCopy() @@ -94,7 +176,11 @@ describe('eslint --fix integration for react-pug processor', () => { message: message.message, })) )) - expect(allMessages.every(message => String(message.ruleId).startsWith('@stylistic/'))).toBe(true) + const allowedRules = new Set(['@typescript-eslint/no-unused-vars']) + expect(allMessages.every(message => ( + String(message.ruleId).startsWith('@stylistic/') + || allowedRules.has(String(message.ruleId)) + ))).toBe(true) await expect(JSON.stringify(allMessages, null, 2) + '\n').toMatchFileSnapshot(postFixDiagnosticsSnapshot) const fixedFiles = [ diff --git a/packages/eslint-plugin-react-pug/test/integration/startupjs-ui-regressions.test.ts b/packages/eslint-plugin-react-pug/test/integration/startupjs-ui-regressions.test.ts index 02891d6..3349fa8 100644 --- a/packages/eslint-plugin-react-pug/test/integration/startupjs-ui-regressions.test.ts +++ b/packages/eslint-plugin-react-pug/test/integration/startupjs-ui-regressions.test.ts @@ -8,6 +8,7 @@ import reactPugPlugin from '../../src/index' const repoRoot = resolve(__dirname, '../../../..') const fixtureRoot = resolve(repoRoot, 'test/fixtures/example-unformatted/src') +const fixedSnapshotRoot = resolve(repoRoot, 'test/fixtures/example-unformatted/snapshots/fixed/src') const reactHooksStubPlugin = { rules: { 'rules-of-hooks': { @@ -115,7 +116,7 @@ describe('startupjs-ui regressions', () => { expect(booleanDiagnostic?.column).toBe(12) }) - it('does not rewrite startupjs-ui repros under eslint --fix', async () => { + it('rewrites startupjs-ui repros only to the expected fixed snapshots under eslint --fix', async () => { for (const relativePath of [ 'StartupjsUiDialogsReadme.js', 'StartupjsUiDropdown.tsx', @@ -130,7 +131,7 @@ describe('startupjs-ui regressions', () => { const filePath = resolve(fixtureRoot, relativePath) const input = readFileSync(filePath, 'utf8') const [result] = await createStartupjsUiStyleEslint(true).lintText(input, { filePath }) - expect(result.output ?? input).toBe(input) + expect(result.output ?? input).toBe(readFileSync(resolve(fixedSnapshotRoot, relativePath), 'utf8')) } }) }) diff --git a/packages/eslint-plugin-react-pug/test/unit/processor.test.ts b/packages/eslint-plugin-react-pug/test/unit/processor.test.ts index 618332e..55047d7 100644 --- a/packages/eslint-plugin-react-pug/test/unit/processor.test.ts +++ b/packages/eslint-plugin-react-pug/test/unit/processor.test.ts @@ -632,17 +632,123 @@ describe('eslint-plugin-react-pug processor', () => { ].join('\n'); const blocks = processor.preprocess(input, 'file.jsx'); - expect(blocks).toHaveLength(3); + expect(blocks).toHaveLength(5); expect(blocks[1]).toMatchObject({ - filename: '../../../pug-react-embedded-expression.jsx', + filename: '../../../pug-react-embedded-statement-0.jsx', }); expect(blocks[2]).toMatchObject({ - filename: '../../../pug-react-embedded-statement.jsx', + filename: '../../../pug-react-embedded-expression-1.jsx', }); - expect((blocks[1] as any).text).toContain('const __reactPugExpr0 = (\n knownAttr + missingAttrValue\n)'); - expect((blocks[1] as any).text).toContain('const __reactPugExpr1 = (\n () => run(item.id)\n)'); - expect((blocks[1] as any).text).toContain('const __reactPugExpr2 = (\n knownInterpolation + missingInterpolationValue\n)'); - expect((blocks[2] as any).text).toContain('(() => {\n const visible = ready\n})()'); + expect(blocks[3]).toMatchObject({ + filename: '../../../pug-react-embedded-expression-2.jsx', + }); + expect(blocks[4]).toMatchObject({ + filename: '../../../pug-react-embedded-expression-3.jsx', + }); + expect((blocks[1] as any).text).toContain('(() => {\n const visible = ready\n})()'); + expect((blocks[2] as any).text).toContain('const __reactPugExpr = (\n knownAttr + missingAttrValue\n)'); + expect((blocks[3] as any).text).toContain('const __reactPugExpr = (\n () => run(item.id)\n)'); + expect((blocks[4] as any).text).toContain('const __reactPugExpr = (\n knownInterpolation + missingInterpolationValue\n)'); + }); + + it('maps embedded-source autofix edits back to original pug ranges', () => { + const processor = createReactPugProcessor(); + const input = [ + 'const view = pug`', + ' Button(label=label+suffix) Save', + '`', + ].join('\n'); + + const blocks = processor.preprocess(input, 'file.jsx') as Array<{ text: string; filename: string }>; + const embeddedBlock = blocks[1]; + const fixStart = embeddedBlock.text.indexOf('label+suffix'); + const fixEnd = fixStart + 'label+suffix'.length; + const startLc = offsetToLineColumn(embeddedBlock.text, fixStart); + const endLc = offsetToLineColumn(embeddedBlock.text, fixEnd); + + const mapped = processor.postprocess([ + [], + [{ + ruleId: '@stylistic/space-infix-ops', + message: "Operator '+' must be spaced.", + line: startLc.line, + column: startLc.column, + endLine: endLc.line, + endColumn: endLc.column, + fix: { + range: [fixStart, fixEnd], + text: 'label + suffix', + }, + } as any], + ], 'file.jsx'); + + const expectedStart = input.indexOf('label=label+suffix') + 'label='.length; + expect(mapped).toEqual([ + expect.objectContaining({ + ruleId: '@stylistic/space-infix-ops', + line: 2, + column: 16, + endLine: 2, + endColumn: 28, + fix: { + range: [expectedStart, expectedStart + 'label+suffix'.length], + text: 'label + suffix', + }, + }), + ]); + }); + + it('maps embedded-source suggestions back to original pug ranges', () => { + const processor = createReactPugProcessor(); + const input = [ + 'const view = pug`', + ' p Hello #{label+suffix}', + '`', + ].join('\n'); + + const blocks = processor.preprocess(input, 'file.jsx') as Array<{ text: string; filename: string }>; + const embeddedBlock = blocks[1]; + const fixStart = embeddedBlock.text.indexOf('label+suffix'); + const fixEnd = fixStart + 'label+suffix'.length; + const startLc = offsetToLineColumn(embeddedBlock.text, fixStart); + const endLc = offsetToLineColumn(embeddedBlock.text, fixEnd); + + const mapped = processor.postprocess([ + [], + [{ + ruleId: '@stylistic/space-infix-ops', + message: "Operator '+' must be spaced.", + line: startLc.line, + column: startLc.column, + endLine: endLc.line, + endColumn: endLc.column, + suggestions: [{ + desc: 'Add spaces around +', + fix: { + range: [fixStart, fixEnd], + text: 'label + suffix', + }, + }], + } as any], + ], 'file.jsx'); + + const expectedStart = input.indexOf('label+suffix'); + expect(mapped).toEqual([ + expect.objectContaining({ + ruleId: '@stylistic/space-infix-ops', + line: 2, + column: 13, + endLine: 2, + endColumn: 25, + suggestions: [{ + desc: 'Add spaces around +', + fix: { + range: [expectedStart, expectedStart + 'label+suffix'.length], + text: 'label + suffix', + }, + }], + }), + ]); }); it('suppresses legacy styl warnings without hiding normal linting', () => { diff --git a/packages/react-pug-core/src/language/lintTransform.ts b/packages/react-pug-core/src/language/lintTransform.ts index a349602..aa0d215 100644 --- a/packages/react-pug-core/src/language/lintTransform.ts +++ b/packages/react-pug-core/src/language/lintTransform.ts @@ -4,7 +4,7 @@ import * as t from '@babel/types'; import type { EmbeddedJsLintSite, ShadowInsertion, ShadowMappedRegion } from './mapping'; import type { SourceTransformOptions, SourceTransformResult } from './sourceTransform'; import { transformSourceFile } from './sourceTransform'; -import { strippedToRawOffset } from './regionOffsetMapping'; +import { regionStrippedOffsetToOriginalOffset, strippedToRawOffset } from './regionOffsetMapping'; export interface RewrittenCopySegment { rewrittenStart: number; @@ -923,25 +923,17 @@ function mapEmbeddedJsLintSitesToOriginal(baseTransform: SourceTransformResult): for (const region of baseTransform.regions) { for (const site of region.embeddedJsLintSites) { const boundaryMap = site.boundaryMap.map((offset) => ( - region.pugTextStart + strippedToRawOffset( - region.pugText, - offset, - region.commonIndent, - ) + regionStrippedOffsetToOriginalOffset(baseTransform.document, region, offset) )); - const originalStart = boundaryMap[0] ?? ( - region.pugTextStart + strippedToRawOffset( - region.pugText, - site.sourceStart, - region.commonIndent, - ) + const originalStart = boundaryMap[0] ?? regionStrippedOffsetToOriginalOffset( + baseTransform.document, + region, + site.sourceStart, ); - const originalEnd = boundaryMap[boundaryMap.length - 1] ?? ( - region.pugTextStart + strippedToRawOffset( - region.pugText, - site.sourceEnd, - region.commonIndent, - ) + const originalEnd = boundaryMap[boundaryMap.length - 1] ?? regionStrippedOffsetToOriginalOffset( + baseTransform.document, + region, + site.sourceEnd, ); sites.push({ diff --git a/packages/react-pug-core/src/language/pugToTsx.ts b/packages/react-pug-core/src/language/pugToTsx.ts index 81297a2..f7b7ad0 100644 --- a/packages/react-pug-core/src/language/pugToTsx.ts +++ b/packages/react-pug-core/src/language/pugToTsx.ts @@ -1114,7 +1114,13 @@ function emitAttributeValueAsExpression( } const attrOffset = lineColToOffset(pugText, attr.line, attr.column); - const valOffset = attrOffset + attr.name.length + 1; + const valOffset = findValueOffsetOnLine( + pugText, + attr.line, + attr.column, + attr.val, + attrOffset + attr.name.length + 1, + ); const val = attr.val; if (getStaticStringLiteralValue(val) != null) { @@ -1351,17 +1357,21 @@ function emitAttribute( // Value attribute: onClick=handler -> onClick={handler} if (typeof attr.val === 'string') { const val = attr.val; + const valOffset = findValueOffsetOnLine( + pugText, + attr.line, + attr.column, + val, + attrOffset + attr.name.length + 1, + ); // JSX string literal attribute: label="Hello" if (getStaticStringLiteralValue(val) != null) { emitter.emitSynthetic('='); - // Find the value offset: after "name=" in the source - const valOffset = attrOffset + attr.name.length + 1; // +1 for '=' emitter.emitMapped(val, valOffset, FULL_FEATURES); } else { // Expression value emitter.emitSynthetic('={'); - const valOffset = attrOffset + attr.name.length + 1; emitExpressionWithTemplateInterpolations(val, valOffset, emitter, FULL_FEATURES); emitter.emitSynthetic('}'); } diff --git a/packages/react-pug-core/src/language/regionOffsetMapping.ts b/packages/react-pug-core/src/language/regionOffsetMapping.ts index bc00a63..c90b8ea 100644 --- a/packages/react-pug-core/src/language/regionOffsetMapping.ts +++ b/packages/react-pug-core/src/language/regionOffsetMapping.ts @@ -7,13 +7,13 @@ export function rawToStrippedOffset(rawText: string, rawOffset: number, commonIn const lines = rawText.split('\n'); for (const line of lines) { const lineEnd = raw + line.length; + const actualIndent = line.match(/^[ \t]*/)?.[0].length ?? 0; + const indentToRemove = line.trim().length === 0 ? line.length : Math.min(commonIndent, actualIndent); if (rawOffset <= lineEnd) { const colInRaw = rawOffset - raw; - const indentToRemove = line.trim().length === 0 ? line.length : commonIndent; if (indentToRemove > 0 && colInRaw < indentToRemove) return null; return stripped + Math.max(0, colInRaw - indentToRemove); } - const indentToRemove = line.trim().length === 0 ? line.length : commonIndent; stripped += Math.max(0, line.length - indentToRemove) + 1; raw = lineEnd + 1; } @@ -26,7 +26,8 @@ export function strippedToRawOffset(rawText: string, strippedOffset: number, com let raw = 0; const lines = rawText.split('\n'); for (const line of lines) { - const indentToRemove = line.trim().length === 0 ? line.length : commonIndent; + const actualIndent = line.match(/^[ \t]*/)?.[0].length ?? 0; + const indentToRemove = line.trim().length === 0 ? line.length : Math.min(commonIndent, actualIndent); const strippedLineLength = Math.max(0, line.length - indentToRemove); if (strippedOffset <= stripped + strippedLineLength) { return raw + indentToRemove + (strippedOffset - stripped); diff --git a/packages/react-pug-core/test/unit/pugToTsx.test.ts b/packages/react-pug-core/test/unit/pugToTsx.test.ts index 89825c3..2198d08 100644 --- a/packages/react-pug-core/test/unit/pugToTsx.test.ts +++ b/packages/react-pug-core/test/unit/pugToTsx.test.ts @@ -1288,6 +1288,20 @@ describe('code blocks', () => { ]); }); + it('tracks the actual expression span for attr values even when spaces surround "="', () => { + const pug = [ + 'Button(', + ' label = showCompleted ? "Hide Done" : "Show Done"', + ')', + ].join('\n'); + + const result = compilePugToTsx(pug, { mode: 'runtime' }); + const site = result.embeddedJsLintSites.find(site => site.code.includes('showCompleted ? "Hide Done" : "Show Done"')); + + expect(site).toBeTruthy(); + expect(pug.slice(site!.sourceStart, site!.sourceEnd)).toBe('showCompleted ? "Hide Done" : "Show Done"'); + }); + it('collects embedded lint sites across all supported source positions in source order', () => { const pug = [ 'Button(', diff --git a/packages/react-pug-core/test/unit/queryMapping.test.ts b/packages/react-pug-core/test/unit/queryMapping.test.ts index 45d68e6..d5107cb 100644 --- a/packages/react-pug-core/test/unit/queryMapping.test.ts +++ b/packages/react-pug-core/test/unit/queryMapping.test.ts @@ -31,6 +31,16 @@ describe('regionOffsetMapping helpers', () => { expect(rawToStrippedOffset(rawText, 1, 4)).toBeNull(); }); + it('caps removed indent on dedented lines instead of collapsing later offsets', () => { + const rawText = [' Button(', 'Span.text= ${label+suffix}', ''].join('\n'); + const rawOffset = rawText.indexOf('label+suffix'); + const stripped = rawToStrippedOffset(rawText, rawOffset, 2); + + expect(stripped).not.toBeNull(); + expect(strippedToRawOffset(rawText, stripped!, 2)).toBe(rawOffset); + expect(strippedToRawOffset(rawText, stripped! + 'label+suffix'.length, 2)).toBe(rawOffset + 'label+suffix'.length); + }); + it('maps original file offsets to stripped region offsets and back', () => { const source = ['const view = pug`', ' Button(onClick=handler)', '`;'].join('\n'); const doc = makeDoc(source); diff --git a/test/fixtures/example-unformatted/snapshots/diagnostics/src/App.tsx.txt b/test/fixtures/example-unformatted/snapshots/diagnostics/src/App.tsx.txt index ca9ca1e..eff19ac 100644 --- a/test/fixtures/example-unformatted/snapshots/diagnostics/src/App.tsx.txt +++ b/test/fixtures/example-unformatted/snapshots/diagnostics/src/App.tsx.txt @@ -1,5 +1,6 @@ -44:39 error @stylistic/quotes Strings must use singlequote. -50:8 error @stylistic/space-infix-ops Operator '===' must be spaced. -54:73 error @stylistic/arrow-spacing Missing space before =>. -58:6 error @stylistic/space-infix-ops Operator '>' must be spaced. -61:87 error @stylistic/arrow-spacing Missing space before =>. +44:37 error @stylistic/quotes Strings must use singlequote. +44:51 error @stylistic/quotes Strings must use singlequote. +49:30 error @stylistic/space-infix-ops Operator '===' must be spaced. +54:65 error @stylistic/arrow-spacing Missing space before =>. +57:50 error @stylistic/space-infix-ops Operator '>' must be spaced. +61:67 error @stylistic/arrow-spacing Missing space before =>. diff --git a/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiMdxComponents.js.txt b/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiMdxComponents.js.txt index 4ffcb7c..06fe3f7 100644 --- a/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiMdxComponents.js.txt +++ b/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiMdxComponents.js.txt @@ -1,3 +1,3 @@ 269:9 error @stylistic/indent Expected indentation of 4 spaces but found 6. -270:16 error @stylistic/indent Expected indentation of 2 spaces but found 4. -304:40 error @stylistic/arrow-spacing Missing space before =>. +270:9 error @stylistic/indent Expected indentation of 2 spaces but found 4. +304:28 error @stylistic/arrow-spacing Missing space before =>. diff --git a/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiTextInput.tsx.txt b/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiTextInput.tsx.txt index ff357fd..28f7034 100644 --- a/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiTextInput.tsx.txt +++ b/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiTextInput.tsx.txt @@ -1,3 +1,3 @@ 213:5 error @stylistic/indent Expected indentation of 4 spaces but found 6. 214:5 error @stylistic/indent Expected indentation of 4 spaces but found 6. -216:4 error @stylistic/indent Expected indentation of 2 spaces but found 4. +215:5 error @stylistic/indent Expected indentation of 2 spaces but found 4. diff --git a/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiWrapInput.tsx.txt b/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiWrapInput.tsx.txt index b2aae6f..fd144cf 100644 --- a/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiWrapInput.tsx.txt +++ b/test/fixtures/example-unformatted/snapshots/diagnostics/src/StartupjsUiWrapInput.tsx.txt @@ -1,8 +1,9 @@ 166:11 error @stylistic/indent Expected indentation of 4 spaces but found 6. -180:19 error @stylistic/indent Expected indentation of 4 spaces but found 8. -181:13 error @stylistic/indent Expected indentation of 4 spaces but found 8. -182:18 error @stylistic/indent Expected indentation of 4 spaces but found 8. -182:41 error @stylistic/indent Expected indentation of 2 spaces but found 6. -228:13 error @stylistic/indent Expected indentation of 4 spaces but found 8. +167:11 error @stylistic/indent Expected indentation of 4 spaces but found 6. +180:7 error @stylistic/indent Expected indentation of 4 spaces but found 8. +181:7 error @stylistic/indent Expected indentation of 4 spaces but found 8. +182:7 error @stylistic/indent Expected indentation of 4 spaces but found 8. +183:7 error @stylistic/indent Expected indentation of 2 spaces but found 6. +228:7 error @stylistic/indent Expected indentation of 4 spaces but found 8. 229:7 error @stylistic/indent Expected indentation of 4 spaces but found 8. -231:15 error @stylistic/indent Expected indentation of 2 spaces but found 6. +230:7 error @stylistic/indent Expected indentation of 2 spaces but found 6. diff --git a/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptErrorsInPug.tsx.txt b/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptErrorsInPug.tsx.txt index 106b00b..103bb40 100644 --- a/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptErrorsInPug.tsx.txt +++ b/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptErrorsInPug.tsx.txt @@ -1,2 +1,2 @@ -23:24 error @stylistic/no-extra-parens Unnecessary parentheses around expression. -26:3 error @stylistic/no-extra-parens Unnecessary parentheses around expression. +23:20 error @stylistic/no-extra-parens Unnecessary parentheses around expression. +26:18 error @stylistic/no-extra-parens Unnecessary parentheses around expression. diff --git a/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptInPug.tsx.txt b/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptInPug.tsx.txt index 2e5f4e3..fdddc37 100644 --- a/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptInPug.tsx.txt +++ b/test/fixtures/example-unformatted/snapshots/diagnostics/src/TypeScriptInPug.tsx.txt @@ -1,2 +1,2 @@ -49:16 error @stylistic/indent Expected indentation of 2 spaces but found 3. -51:21 error @stylistic/no-extra-parens Unnecessary parentheses around expression. +49:13 error @stylistic/indent Expected indentation of 2 spaces but found 3. +51:20 error @stylistic/no-extra-parens Unnecessary parentheses around expression. diff --git a/test/fixtures/example-unformatted/snapshots/fixed/src/App.tsx b/test/fixtures/example-unformatted/snapshots/fixed/src/App.tsx index 94b04c2..4047e42 100644 --- a/test/fixtures/example-unformatted/snapshots/fixed/src/App.tsx +++ b/test/fixtures/example-unformatted/snapshots/fixed/src/App.tsx @@ -41,24 +41,24 @@ export default function App () { Button(onClick=handleReset,label="Reset",variant="secondary") Button( onClick=() => setShowCompleted(!showCompleted) - label = showCompleted ? "Hide Done" : "Show Done" + label = showCompleted ? 'Hide Done' : 'Show Done' ) Modal.Header.active( onClick=handleReset , label="Reset From Modal.Header", variant="secondary" ) h3 Active (#{activeTodos.length}) - if activeTodos.length===0 + if activeTodos.length === 0 p.empty All done! else each todo in activeTodos .todo-item(key=todo.id) - input(type="checkbox",checked=todo.done,onChange=()=> handleToggle(todo.id)) + input(type="checkbox",checked=todo.done,onChange=() => handleToggle(todo.id)) span=todo.text - if showCompleted && completedTodos.length>0 + if showCompleted && completedTodos.length > 0 h3 Completed (#{completedTodos.length}) each todo in completedTodos .todo-item.done(key=todo.id) - input(type="checkbox", checked=todo.done, onChange=()=> handleToggle(todo.id)) + input(type="checkbox", checked=todo.done, onChange=() => handleToggle(todo.id)) span= todo.text style diff --git a/test/fixtures/example-unformatted/snapshots/fixed/src/StartupjsUiMdxComponents.js b/test/fixtures/example-unformatted/snapshots/fixed/src/StartupjsUiMdxComponents.js index a5a449e..fad251b 100644 --- a/test/fixtures/example-unformatted/snapshots/fixed/src/StartupjsUiMdxComponents.js +++ b/test/fixtures/example-unformatted/snapshots/fixed/src/StartupjsUiMdxComponents.js @@ -301,7 +301,7 @@ export default { Div.code-actions(align='right' row) Div.code-action( tooltip=open ? 'Hide code' : 'Show code' - onPress=()=> setOpen(!open) + onPress=() => setOpen(!open) ) Icon.code-action-collapse(icon=faCode color='error') Div.code-action( diff --git a/test/fixtures/example-unformatted/snapshots/fixed/src/TypeScriptErrorsInPug.tsx b/test/fixtures/example-unformatted/snapshots/fixed/src/TypeScriptErrorsInPug.tsx index 427c9d6..4cb4394 100644 --- a/test/fixtures/example-unformatted/snapshots/fixed/src/TypeScriptErrorsInPug.tsx +++ b/test/fixtures/example-unformatted/snapshots/fixed/src/TypeScriptErrorsInPug.tsx @@ -20,9 +20,9 @@ export default function TypeScriptErrorsInPug () { if missingConditionFlag Card(title="Shown") - each item in (missingItemsSource as Item[]) + each item in missingItemsSource as Item[] Card(title=item.title) - Card(title=(maybeLabel as number)) + Card(title=maybeLabel as number) ` } diff --git a/test/fixtures/example-unformatted/snapshots/fixed/src/TypeScriptInPug.tsx b/test/fixtures/example-unformatted/snapshots/fixed/src/TypeScriptInPug.tsx index 5bfd706..06da750 100644 --- a/test/fixtures/example-unformatted/snapshots/fixed/src/TypeScriptInPug.tsx +++ b/test/fixtures/example-unformatted/snapshots/fixed/src/TypeScriptInPug.tsx @@ -48,7 +48,7 @@ export default function TypeScriptInPug () { if maybeTitle != null p #{ maybeTitle as string } - each item in (items as string[]) + each item in items as string[] Card(title = item!) ` } diff --git a/test/fixtures/example-unformatted/snapshots/post-fix-diagnostics.json b/test/fixtures/example-unformatted/snapshots/post-fix-diagnostics.json index c59a962..510551a 100644 --- a/test/fixtures/example-unformatted/snapshots/post-fix-diagnostics.json +++ b/test/fixtures/example-unformatted/snapshots/post-fix-diagnostics.json @@ -1,39 +1,4 @@ [ - { - "filePath": "src/App.tsx", - "ruleId": "@stylistic/quotes", - "line": 44, - "column": 39, - "message": "Strings must use singlequote." - }, - { - "filePath": "src/App.tsx", - "ruleId": "@stylistic/space-infix-ops", - "line": 50, - "column": 8, - "message": "Operator '===' must be spaced." - }, - { - "filePath": "src/App.tsx", - "ruleId": "@stylistic/arrow-spacing", - "line": 54, - "column": 73, - "message": "Missing space before =>." - }, - { - "filePath": "src/App.tsx", - "ruleId": "@stylistic/space-infix-ops", - "line": 58, - "column": 6, - "message": "Operator '>' must be spaced." - }, - { - "filePath": "src/App.tsx", - "ruleId": "@stylistic/arrow-spacing", - "line": 61, - "column": 87, - "message": "Missing space before =>." - }, { "filePath": "src/StartupjsUiMdxComponents.js", "ruleId": "@stylistic/indent", @@ -45,16 +10,9 @@ "filePath": "src/StartupjsUiMdxComponents.js", "ruleId": "@stylistic/indent", "line": 270, - "column": 16, + "column": 9, "message": "Expected indentation of 2 spaces but found 4." }, - { - "filePath": "src/StartupjsUiMdxComponents.js", - "ruleId": "@stylistic/arrow-spacing", - "line": 304, - "column": 40, - "message": "Missing space before =>." - }, { "filePath": "src/StartupjsUiTextInput.tsx", "ruleId": "@stylistic/indent", @@ -72,8 +30,8 @@ { "filePath": "src/StartupjsUiTextInput.tsx", "ruleId": "@stylistic/indent", - "line": 216, - "column": 4, + "line": 215, + "column": 5, "message": "Expected indentation of 2 spaces but found 4." }, { @@ -83,39 +41,46 @@ "column": 11, "message": "Expected indentation of 4 spaces but found 6." }, + { + "filePath": "src/StartupjsUiWrapInput.tsx", + "ruleId": "@stylistic/indent", + "line": 167, + "column": 11, + "message": "Expected indentation of 4 spaces but found 6." + }, { "filePath": "src/StartupjsUiWrapInput.tsx", "ruleId": "@stylistic/indent", "line": 180, - "column": 19, + "column": 7, "message": "Expected indentation of 4 spaces but found 8." }, { "filePath": "src/StartupjsUiWrapInput.tsx", "ruleId": "@stylistic/indent", "line": 181, - "column": 13, + "column": 7, "message": "Expected indentation of 4 spaces but found 8." }, { "filePath": "src/StartupjsUiWrapInput.tsx", "ruleId": "@stylistic/indent", "line": 182, - "column": 18, + "column": 7, "message": "Expected indentation of 4 spaces but found 8." }, { "filePath": "src/StartupjsUiWrapInput.tsx", "ruleId": "@stylistic/indent", - "line": 182, - "column": 41, + "line": 183, + "column": 7, "message": "Expected indentation of 2 spaces but found 6." }, { "filePath": "src/StartupjsUiWrapInput.tsx", "ruleId": "@stylistic/indent", "line": 228, - "column": 13, + "column": 7, "message": "Expected indentation of 4 spaces but found 8." }, { @@ -128,36 +93,15 @@ { "filePath": "src/StartupjsUiWrapInput.tsx", "ruleId": "@stylistic/indent", - "line": 231, - "column": 15, + "line": 230, + "column": 7, "message": "Expected indentation of 2 spaces but found 6." }, - { - "filePath": "src/TypeScriptErrorsInPug.tsx", - "ruleId": "@stylistic/no-extra-parens", - "line": 23, - "column": 24, - "message": "Unnecessary parentheses around expression." - }, - { - "filePath": "src/TypeScriptErrorsInPug.tsx", - "ruleId": "@stylistic/no-extra-parens", - "line": 26, - "column": 3, - "message": "Unnecessary parentheses around expression." - }, { "filePath": "src/TypeScriptInPug.tsx", "ruleId": "@stylistic/indent", "line": 49, - "column": 16, + "column": 13, "message": "Expected indentation of 2 spaces but found 3." - }, - { - "filePath": "src/TypeScriptInPug.tsx", - "ruleId": "@stylistic/no-extra-parens", - "line": 51, - "column": 21, - "message": "Unnecessary parentheses around expression." } ] diff --git a/test/fixtures/real-project/snapshots/babel/CatCard.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/babel/CatCard.js.output.sourcemap.json index caf64a9..af28288 100644 --- a/test/fixtures/real-project/snapshots/babel/CatCard.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/babel/CatCard.js.output.sourcemap.json @@ -38,6 +38,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport { Div, Span, Avatar, Link } from 'startupjs-ui'\n\nexport default observer(({ $cat, showPhone, large, small }) => {\n const { name, number, phone, catgram, photoFileId, phonegram } = $cat.get()\n return pug`\n Div(part='root' row vAlign='center')\n if photoFileId\n Photo.avatar(styleName={ large, small } fileId=photoFileId name=name)\n else\n Avatar.avatar(styleName={ large, small })= name\n Div(row)\n Span.text(bold styleName={ large })= (number || 'X') + '. '\n Div\n Span.text(styleName={ large })= name\n if showPhone\n if phone\n Span.text(styleName={ large })\n Span(bold) Phone:#{' '}\n = phone\n if catgram\n Span.text(styleName={ large })\n Span(bold) Catgram:#{' '}\n Link.text(styleName={ large } to=getCatgramLink(catgram))= catgram\n if phonegram\n Span.text(styleName={ large })\n Span(bold) Phonegram:#{' '}\n Link.text(styleName={ large } to=getPhonegramLink(phonegram))= phonegram\n style(lang='styl')\n .avatar\n margin-right 1u\n &.large\n width 12u\n height @width\n &.small\n width 4u\n height @width\n .text.large\n font(h6)\n `\n})\n\nconst Photo = observer(({ fileId, name }) => {\n const $file = useSub($.files[fileId])\n let url\n try { url = $file.getUrl() } catch (err) {}\n return pug`\n Avatar(part='root' src=url)= name\n `\n})\n\nfunction getCatgramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://catgr.am/' + username\n}\n\nfunction getPhonegramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://www.phonegram.com/' + username\n}\n" ], - "mappings": "AAAA,OAAAA,KAAA;qDACoD;AACpD,SAAAC,GAAA,EAAAC,IAAA,EAAAC,MAAA,EAAAC,IAAA;AAEA,eAAAC,QAAA;EAAAC,IAAA;EAAAC,SAAA;EAAAC,KAAA;EAAAC;AAAA;;;;;;;;;;;;;;EACA;IAAAC,IAAA;IAAAC,MAAA;IAAAC,KAAA;IAAAC,OAAA;IAAAC,WAAA;IAAAC;EAAA,IAAAT,IAAA,CAAAU,GAAA;EACA,QACI,qCACKF,WAAA,IACD,MAAa,oBAAR,EAAkB;MAAAN,KAAA;MAAAC;IAAA,IAAiB,QAAOK,WAAA,EAAY,MAAKJ,IAAA,QAEhE,OAAc,oBAAR,EAAkB;MAAAF,KAAA;MAAAC;IAAA,KAAmBC,IAAA,YAC7C,SACE,KAAe,kBAAX,EAAqB;QAAAF;MAAA,IAAf,MAA2B,CAAAG,MAAA,wBACrC,KACE,KAAU,kBAAN,EAAgB;UAAAH;QAAA,KAAYE,IAAA,SAC7BH,SAAA,MACEK,KAAA,IACD,KAAU,kBAAN,EAAgB;YAAAJ;UAAA,KAClB,UAAW,OAAQ,YACjBI,KAAA,iBACHC,OAAA,IACD,KAAU,kBAAN,EAAgB;YAAAL;UAAA,KAClB,UAAW,SAAU,YACrB,KAAU,kBAAN,EAAgB;cAAAA;YAAA,IAAU,IAAGS,cAAA,CAAAJ,OAAA,IAA0BA,OAAA,wBAC5DE,SAAA,IACD,KAAU,kBAAN,EAAgB;YAAAP;UAAA,KAClB,UAAW,WAAY,YACvB,KAAU,kBAAN,EAAgB;cAAAA;YAAA,IAAU,IAAGU,gBAAA,CAAAH,SAAA,IAA8BA,SAAA;AAa/E;AAEA,MAAAI,KAAA,GAAAd,QAAA;EAAAe,MAAA;EAAAV;AAAA;EACA,MAAAW,KAAA,GAAAC,MAAA,CAAAC,CAAA,CAAAC,KAAA,CAAAJ,MAAA;EACA,IAAAK,GAAA;EACA;IAAAA,GAAA,GAAAJ,KAAA,CAAAK,MAAA;EAAA,SAAAC,GAAA;EACA,QACI,wBAAuBF,GAAA,GAAMf,IAAA;AAEjC;AAEA,SAAAO,eAAAW,QAAA;EACA,KAAAA,QAAA;EACA,YAAAC,IAAA,CAAAD,QAAA,UAAAA,QAAA;EACA,6BAAAA,QAAA;AACA;AAEA,SAAAV,iBAAAU,QAAA;EACA,KAAAA,QAAA;EACA,YAAAC,IAAA,CAAAD,QAAA,UAAAA,QAAA;EACA,sCAAAA,QAAA;AACA", + "mappings": "AAAA,OAAAA,KAAA;qDACoD;AACpD,SAAAC,GAAA,EAAAC,IAAA,EAAAC,MAAA,EAAAC,IAAA;AAEA,eAAAC,QAAA;EAAAC,IAAA;EAAAC,SAAA;EAAAC,KAAA;EAAAC;AAAA;;;;;;;;;;;;;;EACA;IAAAC,IAAA;IAAAC,MAAA;IAAAC,KAAA;IAAAC,OAAA;IAAAC,WAAA;IAAAC;EAAA,IAAAT,IAAA,CAAAU,GAAA;EACA,QACI,qCACKF,WAAA,IACD,MAAa,oBAAR,EAAkB;MAAAN,KAAA;MAAAC;IAAA,IAAiB,QAAOK,WAAA,EAAY,MAAAJ,IAAA,QAE3D,OAAc,oBAAR,EAAkB;MAAAF,KAAA;MAAAC;IAAA,KAAmBC,IAAA,YAC7C,SACE,KAAe,kBAAX,EAAqB;QAAAF;MAAA,IAAf,MAA2B,CAAAG,MAAA,wBACrC,KACE,KAAU,kBAAN,EAAgB;UAAAH;QAAA,KAAYE,IAAA,SAC7BH,SAAA,MACEK,KAAA,IACD,KAAU,kBAAN,EAAgB;YAAAJ;UAAA,KAClB,UAAW,OAAQ,YACjBI,KAAA,iBACHC,OAAA,IACD,KAAU,kBAAN,EAAgB;YAAAL;UAAA,KAClB,UAAW,SAAU,YACrB,KAAU,kBAAN,EAAgB;cAAAA;YAAA,IAAU,IAAGS,cAAA,CAAAJ,OAAA,IAA0BA,OAAA,wBAC5DE,SAAA,IACD,KAAU,kBAAN,EAAgB;YAAAP;UAAA,KAClB,UAAW,WAAY,YACvB,KAAU,kBAAN,EAAgB;cAAAA;YAAA,IAAU,IAAGU,gBAAA,CAAAH,SAAA,IAA8BA,SAAA;AAa/E;AAEA,MAAAI,KAAA,GAAAd,QAAA;EAAAe,MAAA;EAAAV;AAAA;EACA,MAAAW,KAAA,GAAAC,MAAA,CAAAC,CAAA,CAAAC,KAAA,CAAAJ,MAAA;EACA,IAAAK,GAAA;EACA;IAAAA,GAAA,GAAAJ,KAAA,CAAAK,MAAA;EAAA,SAAAC,GAAA;EACA,QACI,wBAAuBF,GAAA,GAAMf,IAAA;AAEjC;AAEA,SAAAO,eAAAW,QAAA;EACA,KAAAA,QAAA;EACA,YAAAC,IAAA,CAAAD,QAAA,UAAAA,QAAA;EACA,6BAAAA,QAAA;AACA;AAEA,SAAAV,iBAAAU,QAAA;EACA,KAAAA,QAAA;EACA,YAAAC,IAAA,CAAAD,QAAA,UAAAA,QAAA;EACA,sCAAAA,QAAA;AACA", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/babel/CatCard.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/babel/CatCard.tsx.output.sourcemap.json index 5fca439..2ce7af0 100644 --- a/test/fixtures/real-project/snapshots/babel/CatCard.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/babel/CatCard.tsx.output.sourcemap.json @@ -38,6 +38,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport { Div, Span, Avatar, Link } from 'startupjs-ui'\n\nexport default observer(({ $cat, showPhone, large, small }) => {\n const { name, number, phone, catgram, photoFileId, phonegram } = $cat.get()\n return pug`\n Div(part='root' row vAlign='center')\n if photoFileId\n Photo.avatar(styleName={ large, small } fileId=photoFileId name=name)\n else\n Avatar.avatar(styleName={ large, small })= name\n Div(row)\n Span.text(bold styleName={ large })= (number || 'X') + '. '\n Div\n Span.text(styleName={ large })= name\n if showPhone\n if phone\n Span.text(styleName={ large })\n Span(bold) Phone:#{' '}\n = phone\n if catgram\n Span.text(styleName={ large })\n Span(bold) Catgram:#{' '}\n Link.text(styleName={ large } to=getCatgramLink(catgram))= catgram\n if phonegram\n Span.text(styleName={ large })\n Span(bold) Phonegram:#{' '}\n Link.text(styleName={ large } to=getPhonegramLink(phonegram))= phonegram\n style(lang='styl')\n .avatar\n margin-right 1u\n &.large\n width 12u\n height @width\n &.small\n width 4u\n height @width\n .text.large\n font(h6)\n `\n})\n\nconst Photo = observer(({ fileId, name }) => {\n const $file = useSub($.files[fileId])\n let url\n try { url = $file.getUrl() } catch (err) {}\n return pug`\n Avatar(part='root' src=url)= name\n `\n})\n\nfunction getCatgramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://catgr.am/' + username\n}\n\nfunction getPhonegramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://www.phonegram.com/' + username\n}\n" ], - "mappings": "AAAA,OAAAA,KAAA;qDACoD;AACpD,SAAAC,GAAA,EAAAC,IAAA,EAAAC,MAAA,EAAAC,IAAA;AAEA,eAAAC,QAAA;EAAAC,IAAA;EAAAC,SAAA;EAAAC,KAAA;EAAAC;AAAA;;;;;;;;;;;;;;EACA;IAAAC,IAAA;IAAAC,MAAA;IAAAC,KAAA;IAAAC,OAAA;IAAAC,WAAA;IAAAC;EAAA,IAAAT,IAAA,CAAAU,GAAA;EACA,QACI,qCACKF,WAAA,IACD,MAAa,oBAAR,EAAkB;MAAAN,KAAA;MAAAC;IAAA,IAAiB,QAAOK,WAAA,EAAY,MAAKJ,IAAA,QAEhE,OAAc,oBAAR,EAAkB;MAAAF,KAAA;MAAAC;IAAA,KAAmBC,IAAA,YAC7C,SACE,KAAe,kBAAX,EAAqB;QAAAF;MAAA,IAAf,MAA2B,CAAAG,MAAA,wBACrC,KACE,KAAU,kBAAN,EAAgB;UAAAH;QAAA,KAAYE,IAAA,SAC7BH,SAAA,MACEK,KAAA,IACD,KAAU,kBAAN,EAAgB;YAAAJ;UAAA,KAClB,UAAW,OAAQ,YACjBI,KAAA,iBACHC,OAAA,IACD,KAAU,kBAAN,EAAgB;YAAAL;UAAA,KAClB,UAAW,SAAU,YACrB,KAAU,kBAAN,EAAgB;cAAAA;YAAA,IAAU,IAAGS,cAAA,CAAAJ,OAAA,IAA0BA,OAAA,wBAC5DE,SAAA,IACD,KAAU,kBAAN,EAAgB;YAAAP;UAAA,KAClB,UAAW,WAAY,YACvB,KAAU,kBAAN,EAAgB;cAAAA;YAAA,IAAU,IAAGU,gBAAA,CAAAH,SAAA,IAA8BA,SAAA;AAa/E;AAEA,MAAAI,KAAA,GAAAd,QAAA;EAAAe,MAAA;EAAAV;AAAA;EACA,MAAAW,KAAA,GAAAC,MAAA,CAAAC,CAAA,CAAAC,KAAA,CAAAJ,MAAA;EACA,IAAAK,GAAA;EACA;IAAAA,GAAA,GAAAJ,KAAA,CAAAK,MAAA;EAAA,SAAAC,GAAA;EACA,QACI,wBAAuBF,GAAA,GAAMf,IAAA;AAEjC;AAEA,SAAAO,eAAAW,QAAA;EACA,KAAAA,QAAA;EACA,YAAAC,IAAA,CAAAD,QAAA,UAAAA,QAAA;EACA,6BAAAA,QAAA;AACA;AAEA,SAAAV,iBAAAU,QAAA;EACA,KAAAA,QAAA;EACA,YAAAC,IAAA,CAAAD,QAAA,UAAAA,QAAA;EACA,sCAAAA,QAAA;AACA", + "mappings": "AAAA,OAAAA,KAAA;qDACoD;AACpD,SAAAC,GAAA,EAAAC,IAAA,EAAAC,MAAA,EAAAC,IAAA;AAEA,eAAAC,QAAA;EAAAC,IAAA;EAAAC,SAAA;EAAAC,KAAA;EAAAC;AAAA;;;;;;;;;;;;;;EACA;IAAAC,IAAA;IAAAC,MAAA;IAAAC,KAAA;IAAAC,OAAA;IAAAC,WAAA;IAAAC;EAAA,IAAAT,IAAA,CAAAU,GAAA;EACA,QACI,qCACKF,WAAA,IACD,MAAa,oBAAR,EAAkB;MAAAN,KAAA;MAAAC;IAAA,IAAiB,QAAOK,WAAA,EAAY,MAAAJ,IAAA,QAE3D,OAAc,oBAAR,EAAkB;MAAAF,KAAA;MAAAC;IAAA,KAAmBC,IAAA,YAC7C,SACE,KAAe,kBAAX,EAAqB;QAAAF;MAAA,IAAf,MAA2B,CAAAG,MAAA,wBACrC,KACE,KAAU,kBAAN,EAAgB;UAAAH;QAAA,KAAYE,IAAA,SAC7BH,SAAA,MACEK,KAAA,IACD,KAAU,kBAAN,EAAgB;YAAAJ;UAAA,KAClB,UAAW,OAAQ,YACjBI,KAAA,iBACHC,OAAA,IACD,KAAU,kBAAN,EAAgB;YAAAL;UAAA,KAClB,UAAW,SAAU,YACrB,KAAU,kBAAN,EAAgB;cAAAA;YAAA,IAAU,IAAGS,cAAA,CAAAJ,OAAA,IAA0BA,OAAA,wBAC5DE,SAAA,IACD,KAAU,kBAAN,EAAgB;YAAAP;UAAA,KAClB,UAAW,WAAY,YACvB,KAAU,kBAAN,EAAgB;cAAAA;YAAA,IAAU,IAAGU,gBAAA,CAAAH,SAAA,IAA8BA,SAAA;AAa/E;AAEA,MAAAI,KAAA,GAAAd,QAAA;EAAAe,MAAA;EAAAV;AAAA;EACA,MAAAW,KAAA,GAAAC,MAAA,CAAAC,CAAA,CAAAC,KAAA,CAAAJ,MAAA;EACA,IAAAK,GAAA;EACA;IAAAA,GAAA,GAAAJ,KAAA,CAAAK,MAAA;EAAA,SAAAC,GAAA;EACA,QACI,wBAAuBF,GAAA,GAAMf,IAAA;AAEjC;AAEA,SAAAO,eAAAW,QAAA;EACA,KAAAA,QAAA;EACA,YAAAC,IAAA,CAAAD,QAAA,UAAAA,QAAA;EACA,6BAAAA,QAAA;AACA;AAEA,SAAAV,iBAAAU,QAAA;EACA,KAAAA,QAAA;EACA,YAAAC,IAAA,CAAAD,QAAA,UAAAA,QAAA;EACA,sCAAAA,QAAA;AACA", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/babel/cat-profile-link.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/babel/cat-profile-link.js.output.sourcemap.json index 819d09f..c728b73 100644 --- a/test/fixtures/real-project/snapshots/babel/cat-profile-link.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/babel/cat-profile-link.js.output.sourcemap.json @@ -58,6 +58,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { Alert, Span, Modal, Content, Button, Form, Div, Tag, useMedia, useFormFields } from 'startupjs-ui'\nimport { useGlobalSearchParams, Stack } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport CatCard from '@/components/CatCard'\nimport * as stages from '@/components/stages'\nimport { CAT_PROFILE_EDIT_FORM } from '@/model/cats/schema'\nimport { STAGES } from '@/model/events/schema'\n\nexport default observer(() => {\n const { token } = useGlobalSearchParams()\n const [$cat] = useSub($.cats, { token })\n if (!$cat) return renderExpired()\n\n const eventId = $cat.eventId.get()\n const $event = useSub($.events[eventId])\n\n function renderTitle () {\n return pug`\n CatCard($cat=$cat)\n `\n }\n\n function renderSettings () {\n return pug`\n Profile($cat=$cat $event=$event)\n `\n }\n\n const Stage = stages[$cat.getMyStage()]\n\n return pug`\n Stack.Screen(\n options={\n headerTitle: renderTitle,\n headerRight: renderSettings\n }\n )\n Stage($cat=$cat $event=$event)\n `\n})\n\nconst Profile = observer(({ $cat, $event }) => {\n const $showEdit = $()\n const { tablet } = useMedia()\n const excludeNumber = $event.stage.get() !== STAGES.InProgress\n const profileEditFields = useFormFields(CAT_PROFILE_EDIT_FORM, excludeNumber ? { exclude: ['number'] } : {})\n\n return pug`\n Div(row vAlign='center' gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n if $cat.getMyStage() === STAGES.Profile\n Div.hackSidePadding\n else\n Button(\n variant='text'\n icon=faPen\n onPress=() => $showEdit.set(true)\n )\n if tablet\n = 'Edit cat profile'\n else\n = 'Edit'\n Modal(\n title='Edit cat profile'\n $visible=$showEdit\n )\n Form(\n fields=profileEditFields\n $value=$cat\n )\n style(lang='styl')\n .hackSidePadding\n width 1u\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nfunction renderExpired () {\n return pug`\n Content(padding)\n Alert(variant='error')\n Span\n | Cat profile link is incorrect or already expired.\n |\n | Your cat meetup profile link is only valid for a limited period of time.\n |\n | If you believe this is an error, please contact the cat meetup organizer.\n `\n}\n" ], - "mappings": "AAAA,OAAAA,KAAA;qDACoD;AACpD,SAAAC,KAAA,EAAAC,IAAA,EAAAC,KAAA,EAAAC,OAAA,EAAAC,MAAA,EAAAC,IAAA,EAAAC,GAAA,EAAAC,GAAA,EAAAC,QAAA,EAAAC,aAAA;AACA,SAAAC,qBAAA,EAAAC,KAAA;AACA,SAAAC,KAAA;AACA,OAAAC,OAAA;AACA,YAAAC,MAAA;AACA,SAAAC,qBAAA;AACA,SAAAC,MAAA;AAEA,eAAAC,QAAA;EACA;IAAAC;EAAA,IAAAR,qBAAA;EACA,OAAAS,IAAA,IAAAC,MAAA,CAAAC,CAAA,CAAAC,IAAA;IAAAJ;EAAA;EACA,KAAAC,IAAA,SAAAI,aAAA;EAEA,MAAAC,OAAA,GAAAL,IAAA,CAAAK,OAAA,CAAAC,GAAA;EACA,MAAAC,MAAA,GAAAN,MAAA,CAAAC,CAAA,CAAAM,MAAA,CAAAH,OAAA;EAEA,SAAAI,YAAA;IACA,QACM,cAAaT,IAAA;EAEnB;EAEA,SAAAU,eAAA;IACA,QACM,cAAaV,IAAA,EAAK,QAAOO,MAAA;EAE/B;EAEA,MAAAI,KAAA,GAAAhB,MAAA,CAAAK,IAAA,CAAAY,UAAA;EAEA,UACI,aACE,SAAQ;MACVC,WAAA,EAAAJ,WAAA;MACAK,WAAA,EAAAJ;IACA,MAEA,YAAWV,IAAA,EAAK,QAAOO,MAAA;AAE3B;AAEA,MAAAQ,OAAA,GAAAjB,QAAA;EAAAE,IAAA;EAAAO;AAAA;;;;;;EACA,MAAAS,SAAA,GAAAd,CAAA;EACA;IAAAe;EAAA,IAAA5B,QAAA;EACA,MAAA6B,aAAA,GAAAX,MAAA,CAAAY,KAAA,CAAAb,GAAA,OAAAT,MAAA,CAAAuB,UAAA;EACA,MAAAC,iBAAA,GAAA/B,aAAA,CAAAM,qBAAA,EAAAsB,aAAA;IAAAI,OAAA;EAAA;EAEA,UACI,6BAA4B,IACvB,CAAAC,UAAA,CAAAvB,IAAA,KACD,kBAAmB,yBAClB,CAAAA,IAAA,CAAAwB,WAAA,CAAAlB,GAAA,MACD,kBAAmB,uBAClBN,IAAA,CAAAY,UAAA,OAAAf,MAAA,CAAAkB,OAAA,IACD,iCAAG,SAEH,OACE,eACA,MAAKtB,KAAA,EACL,SAAQ,MAAAuB,SAAA,CAAAS,GAAA,SAELR,MAAA,GACC,qBAEA,wBACV,MACE,yBACA,UAASD,SAAA,GAET,KACE,QAAOK,iBAAA,EACP,QAAOrB,IAAA;AAMf;AAEA,SAAAuB,WAAAvB,IAAA;EACA,QAAAA,IAAA,CAAA0B,KAAA,CAAApB,GAAA,UAAAqB,IAAA,OAAA3B,IAAA,CAAA4B,OAAA,CAAAtB,GAAA,UAAAqB,IAAA,OAAA3B,IAAA,CAAA6B,SAAA,CAAAvB,GAAA,UAAAqB,IAAA;AACA;AAEA,SAAAvB,cAAA;EACA,QACI,iBACE,uBACE,KACI;AACP;AACA;AACA;AACA,yEAAQ;AAEb", + "mappings": "AAAA,OAAAA,KAAA;qDACoD;AACpD,SAAAC,KAAA,EAAAC,IAAA,EAAAC,KAAA,EAAAC,OAAA,EAAAC,MAAA,EAAAC,IAAA,EAAAC,GAAA,EAAAC,GAAA,EAAAC,QAAA,EAAAC,aAAA;AACA,SAAAC,qBAAA,EAAAC,KAAA;AACA,SAAAC,KAAA;AACA,OAAAC,OAAA;AACA,YAAAC,MAAA;AACA,SAAAC,qBAAA;AACA,SAAAC,MAAA;AAEA,eAAAC,QAAA;EACA;IAAAC;EAAA,IAAAR,qBAAA;EACA,OAAAS,IAAA,IAAAC,MAAA,CAAAC,CAAA,CAAAC,IAAA;IAAAJ;EAAA;EACA,KAAAC,IAAA,SAAAI,aAAA;EAEA,MAAAC,OAAA,GAAAL,IAAA,CAAAK,OAAA,CAAAC,GAAA;EACA,MAAAC,MAAA,GAAAN,MAAA,CAAAC,CAAA,CAAAM,MAAA,CAAAH,OAAA;EAEA,SAAAI,YAAA;IACA,QACM,cAAQT,IAAA;EAEd;EAEA,SAAAU,eAAA;IACA,QACM,cAAQV,IAAA,EAAU,QAAAO,MAAA;EAExB;EAEA,MAAAI,KAAA,GAAAhB,MAAA,CAAAK,IAAA,CAAAY,UAAA;EAEA,UACI,aACE,SAAQ;MACVC,WAAA,EAAAJ,WAAA;MACAK,WAAA,EAAAJ;IACA,MAEA,YAAMV,IAAA,EAAU,QAAAO,MAAA;AAEpB;AAEA,MAAAQ,OAAA,GAAAjB,QAAA;EAAAE,IAAA;EAAAO;AAAA;;;;;;EACA,MAAAS,SAAA,GAAAd,CAAA;EACA;IAAAe;EAAA,IAAA5B,QAAA;EACA,MAAA6B,aAAA,GAAAX,MAAA,CAAAY,KAAA,CAAAb,GAAA,OAAAT,MAAA,CAAAuB,UAAA;EACA,MAAAC,iBAAA,GAAA/B,aAAA,CAAAM,qBAAA,EAAAsB,aAAA;IAAAI,OAAA;EAAA;EAEA,UACI,6BAA4B,IACvB,CAAAC,UAAA,CAAAvB,IAAA,KACD,kBAAmB,yBAClB,CAAAA,IAAA,CAAAwB,WAAA,CAAAlB,GAAA,MACD,kBAAmB,uBAClBN,IAAA,CAAAY,UAAA,OAAAf,MAAA,CAAAkB,OAAA,IACD,iCAAG,SAEH,OACE,eACA,MAAKtB,KAAA,EACL,SAAQ,MAAAuB,SAAA,CAAAS,GAAA,SAELR,MAAA,GACC,qBAEA,wBACV,MACE,yBACA,UAASD,SAAA,GAET,KACE,QAAOK,iBAAA,EACP,QAAOrB,IAAA;AAMf;AAEA,SAAAuB,WAAAvB,IAAA;EACA,QAAAA,IAAA,CAAA0B,KAAA,CAAApB,GAAA,UAAAqB,IAAA,OAAA3B,IAAA,CAAA4B,OAAA,CAAAtB,GAAA,UAAAqB,IAAA,OAAA3B,IAAA,CAAA6B,SAAA,CAAAvB,GAAA,UAAAqB,IAAA;AACA;AAEA,SAAAvB,cAAA;EACA,QACI,iBACE,uBACE,KACI;AACP;AACA;AACA;AACA,yEAAQ;AAEb", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/babel/cat-profile-link.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/babel/cat-profile-link.tsx.output.sourcemap.json index d607ee3..d69f84d 100644 --- a/test/fixtures/real-project/snapshots/babel/cat-profile-link.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/babel/cat-profile-link.tsx.output.sourcemap.json @@ -58,6 +58,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { Alert, Span, Modal, Content, Button, Form, Div, Tag, useMedia, useFormFields } from 'startupjs-ui'\nimport { useGlobalSearchParams, Stack } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport CatCard from '@/components/CatCard'\nimport * as stages from '@/components/stages'\nimport { CAT_PROFILE_EDIT_FORM } from '@/model/cats/schema'\nimport { STAGES } from '@/model/events/schema'\n\nexport default observer(() => {\n const { token } = useGlobalSearchParams()\n const [$cat] = useSub($.cats, { token })\n if (!$cat) return renderExpired()\n\n const eventId = $cat.eventId.get()\n const $event = useSub($.events[eventId])\n\n function renderTitle () {\n return pug`\n CatCard($cat=$cat)\n `\n }\n\n function renderSettings () {\n return pug`\n Profile($cat=$cat $event=$event)\n `\n }\n\n const Stage = stages[$cat.getMyStage()]\n\n return pug`\n Stack.Screen(\n options={\n headerTitle: renderTitle,\n headerRight: renderSettings\n }\n )\n Stage($cat=$cat $event=$event)\n `\n})\n\nconst Profile = observer(({ $cat, $event }) => {\n const $showEdit = $()\n const { tablet } = useMedia()\n const excludeNumber = $event.stage.get() !== STAGES.InProgress\n const profileEditFields = useFormFields(CAT_PROFILE_EDIT_FORM, excludeNumber ? { exclude: ['number'] } : {})\n\n return pug`\n Div(row vAlign='center' gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n if $cat.getMyStage() === STAGES.Profile\n Div.hackSidePadding\n else\n Button(\n variant='text'\n icon=faPen\n onPress=() => $showEdit.set(true)\n )\n if tablet\n = 'Edit cat profile'\n else\n = 'Edit'\n Modal(\n title='Edit cat profile'\n $visible=$showEdit\n )\n Form(\n fields=profileEditFields\n $value=$cat\n )\n style(lang='styl')\n .hackSidePadding\n width 1u\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nfunction renderExpired () {\n return pug`\n Content(padding)\n Alert(variant='error')\n Span\n | Cat profile link is incorrect or already expired.\n |\n | Your cat meetup profile link is only valid for a limited period of time.\n |\n | If you believe this is an error, please contact the cat meetup organizer.\n `\n}\n" ], - "mappings": "AAAA,OAAAA,KAAA;qDACoD;AACpD,SAAAC,KAAA,EAAAC,IAAA,EAAAC,KAAA,EAAAC,OAAA,EAAAC,MAAA,EAAAC,IAAA,EAAAC,GAAA,EAAAC,GAAA,EAAAC,QAAA,EAAAC,aAAA;AACA,SAAAC,qBAAA,EAAAC,KAAA;AACA,SAAAC,KAAA;AACA,OAAAC,OAAA;AACA,YAAAC,MAAA;AACA,SAAAC,qBAAA;AACA,SAAAC,MAAA;AAEA,eAAAC,QAAA;EACA;IAAAC;EAAA,IAAAR,qBAAA;EACA,OAAAS,IAAA,IAAAC,MAAA,CAAAC,CAAA,CAAAC,IAAA;IAAAJ;EAAA;EACA,KAAAC,IAAA,SAAAI,aAAA;EAEA,MAAAC,OAAA,GAAAL,IAAA,CAAAK,OAAA,CAAAC,GAAA;EACA,MAAAC,MAAA,GAAAN,MAAA,CAAAC,CAAA,CAAAM,MAAA,CAAAH,OAAA;EAEA,SAAAI,YAAA;IACA,QACM,cAAaT,IAAA;EAEnB;EAEA,SAAAU,eAAA;IACA,QACM,cAAaV,IAAA,EAAK,QAAOO,MAAA;EAE/B;EAEA,MAAAI,KAAA,GAAAhB,MAAA,CAAAK,IAAA,CAAAY,UAAA;EAEA,UACI,aACE,SAAQ;MACVC,WAAA,EAAAJ,WAAA;MACAK,WAAA,EAAAJ;IACA,MAEA,YAAWV,IAAA,EAAK,QAAOO,MAAA;AAE3B;AAEA,MAAAQ,OAAA,GAAAjB,QAAA;EAAAE,IAAA;EAAAO;AAAA;;;;;;EACA,MAAAS,SAAA,GAAAd,CAAA;EACA;IAAAe;EAAA,IAAA5B,QAAA;EACA,MAAA6B,aAAA,GAAAX,MAAA,CAAAY,KAAA,CAAAb,GAAA,OAAAT,MAAA,CAAAuB,UAAA;EACA,MAAAC,iBAAA,GAAA/B,aAAA,CAAAM,qBAAA,EAAAsB,aAAA;IAAAI,OAAA;EAAA;EAEA,UACI,6BAA4B,IACvB,CAAAC,UAAA,CAAAvB,IAAA,KACD,kBAAmB,yBAClB,CAAAA,IAAA,CAAAwB,WAAA,CAAAlB,GAAA,MACD,kBAAmB,uBAClBN,IAAA,CAAAY,UAAA,OAAAf,MAAA,CAAAkB,OAAA,IACD,iCAAG,SAEH,OACE,eACA,MAAKtB,KAAA,EACL,SAAQ,MAAAuB,SAAA,CAAAS,GAAA,SAELR,MAAA,GACC,qBAEA,wBACV,MACE,yBACA,UAASD,SAAA,GAET,KACE,QAAOK,iBAAA,EACP,QAAOrB,IAAA;AAMf;AAEA,SAAAuB,WAAAvB,IAAA;EACA,QAAAA,IAAA,CAAA0B,KAAA,CAAApB,GAAA,UAAAqB,IAAA,OAAA3B,IAAA,CAAA4B,OAAA,CAAAtB,GAAA,UAAAqB,IAAA,OAAA3B,IAAA,CAAA6B,SAAA,CAAAvB,GAAA,UAAAqB,IAAA;AACA;AAEA,SAAAvB,cAAA;EACA,QACI,iBACE,uBACE,KACI;AACP;AACA;AACA;AACA,yEAAQ;AAEb", + "mappings": "AAAA,OAAAA,KAAA;qDACoD;AACpD,SAAAC,KAAA,EAAAC,IAAA,EAAAC,KAAA,EAAAC,OAAA,EAAAC,MAAA,EAAAC,IAAA,EAAAC,GAAA,EAAAC,GAAA,EAAAC,QAAA,EAAAC,aAAA;AACA,SAAAC,qBAAA,EAAAC,KAAA;AACA,SAAAC,KAAA;AACA,OAAAC,OAAA;AACA,YAAAC,MAAA;AACA,SAAAC,qBAAA;AACA,SAAAC,MAAA;AAEA,eAAAC,QAAA;EACA;IAAAC;EAAA,IAAAR,qBAAA;EACA,OAAAS,IAAA,IAAAC,MAAA,CAAAC,CAAA,CAAAC,IAAA;IAAAJ;EAAA;EACA,KAAAC,IAAA,SAAAI,aAAA;EAEA,MAAAC,OAAA,GAAAL,IAAA,CAAAK,OAAA,CAAAC,GAAA;EACA,MAAAC,MAAA,GAAAN,MAAA,CAAAC,CAAA,CAAAM,MAAA,CAAAH,OAAA;EAEA,SAAAI,YAAA;IACA,QACM,cAAQT,IAAA;EAEd;EAEA,SAAAU,eAAA;IACA,QACM,cAAQV,IAAA,EAAU,QAAAO,MAAA;EAExB;EAEA,MAAAI,KAAA,GAAAhB,MAAA,CAAAK,IAAA,CAAAY,UAAA;EAEA,UACI,aACE,SAAQ;MACVC,WAAA,EAAAJ,WAAA;MACAK,WAAA,EAAAJ;IACA,MAEA,YAAMV,IAAA,EAAU,QAAAO,MAAA;AAEpB;AAEA,MAAAQ,OAAA,GAAAjB,QAAA;EAAAE,IAAA;EAAAO;AAAA;;;;;;EACA,MAAAS,SAAA,GAAAd,CAAA;EACA;IAAAe;EAAA,IAAA5B,QAAA;EACA,MAAA6B,aAAA,GAAAX,MAAA,CAAAY,KAAA,CAAAb,GAAA,OAAAT,MAAA,CAAAuB,UAAA;EACA,MAAAC,iBAAA,GAAA/B,aAAA,CAAAM,qBAAA,EAAAsB,aAAA;IAAAI,OAAA;EAAA;EAEA,UACI,6BAA4B,IACvB,CAAAC,UAAA,CAAAvB,IAAA,KACD,kBAAmB,yBAClB,CAAAA,IAAA,CAAAwB,WAAA,CAAAlB,GAAA,MACD,kBAAmB,uBAClBN,IAAA,CAAAY,UAAA,OAAAf,MAAA,CAAAkB,OAAA,IACD,iCAAG,SAEH,OACE,eACA,MAAKtB,KAAA,EACL,SAAQ,MAAAuB,SAAA,CAAAS,GAAA,SAELR,MAAA,GACC,qBAEA,wBACV,MACE,yBACA,UAASD,SAAA,GAET,KACE,QAAOK,iBAAA,EACP,QAAOrB,IAAA;AAMf;AAEA,SAAAuB,WAAAvB,IAAA;EACA,QAAAA,IAAA,CAAA0B,KAAA,CAAApB,GAAA,UAAAqB,IAAA,OAAA3B,IAAA,CAAA4B,OAAA,CAAAtB,GAAA,UAAAqB,IAAA,OAAA3B,IAAA,CAAA6B,SAAA,CAAAvB,GAAA,UAAAqB,IAAA;AACA;AAEA,SAAAvB,cAAA;EACA,QACI,iBACE,uBACE,KACI;AACP;AACA;AACA;AACA,yEAAQ;AAEb", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/babel/event-tabs-breed.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/babel/event-tabs-breed.js.output.sourcemap.json index 4cce8fc..7400398 100644 --- a/test/fixtures/real-project/snapshots/babel/event-tabs-breed.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/babel/event-tabs-breed.js.output.sourcemap.json @@ -83,6 +83,6 @@ "sourcesContent": [ "import React, { useState } from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport {\n Link, Item, ScrollView, Form, useFormProps, Alert,\n Content, Tag, Br, Button, Modal, Div, confirm,\n useFormFields$, useValidate\n} from 'startupjs-ui'\nimport { useGlobalSearchParams } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faLink } from '@fortawesome/free-solid-svg-icons/faLink'\nimport CatCard from '@/components/CatCard'\nimport { CAT_FORM } from '@/model/cats/schema'\n\nexport default observer(({ breed }) => {\n const { eventId } = useGlobalSearchParams()\n const [$selected, set$selected] = useState()\n const $new = $()\n const $showModal = $()\n const $mode = $()\n const $fields = useFormFields$(CAT_FORM)\n const validate = useValidate()\n\n function showCreate () {\n $new.set({ breed })\n $fields.breed.disabled.set(true)\n set$selected(() => $new)\n $mode.set('new')\n $showModal.set(true)\n }\n\n function showEdit ($cat) {\n $fields.breed.disabled.del()\n set$selected(() => $cat)\n $mode.set('edit')\n $showModal.set(true)\n }\n\n function cancel () {\n if (!$showModal.get()) return\n $showModal.del()\n $mode.del()\n }\n\n async function create () {\n if (!validate()) return\n await $.cats.addNew({\n ...$new.getDeepCopy(),\n eventId\n })\n cancel()\n }\n\n async function deleteCat () {\n if (!await confirm(`Are you sure you want to delete ${$selected.name.get()}?`)) return\n await $selected.del()\n cancel()\n }\n\n return pug`\n ScrollView(full)\n Content(full pure)\n CatsList(eventId=eventId onEdit=showEdit breed=breed)\n Content(padding=1)\n Button(onPress=showCreate) Add new #{breed}\n Modal(\n title=$mode.get() === 'new' ? 'Create cat' : 'Edit cat'\n $visible=$showModal\n onDismiss=cancel\n )\n - const oppositeBreed = $selected?.breed.get() && ($selected.breed.get() === 'domestic' ? 'wild' : 'domestic')\n Form(\n key=$selected?.getId() || 'NEW'\n $fields=$fields\n $value=$selected\n oppositeBreed=oppositeBreed\n eventId=eventId\n customInputs={\n likes: SelectLikesInput\n }\n validate=validate\n )\n Br\n if $mode.get() === 'new'\n Div(align='right' row)\n Button(onPress=cancel) Cancel\n Button(disabled=validate.hasErrors pushed variant='flat' color='primary' onPress=create) Create\n else if $mode.get() === 'edit'\n Div(align='right' row)\n Button(color='error' onPress=deleteCat) Delete\n `\n})\n\nconst CatsList = observer(({ onEdit, breed, eventId }) => {\n if (!eventId) return pug`Alert(variant='error') No event specified`\n const $cats = useSub($.cats, { eventId, breed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n Item(key=$cat.getId())\n CatCard($cat=$cat)\n Item.Right\n Div(vAlign='center' row gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n Button(variant='text' icon=faPen onPress=() => onEdit($cat) tooltip='Edit')\n Link(href='/events/' + eventId + '/matches/' + $cat.getId())\n Button(variant='text' icon=faHeart tooltip='Matches')\n Link(href='/cats/' + $cat.token.get())\n Button(variant='text' icon=faLink tooltip='Cat profile link') Link\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nconst SelectLikesInput = observer(({ $value, ...props }) => {\n const { oppositeBreed, eventId } = { ...useFormProps(), ...props }\n return pug`\n if oppositeBreed\n SelectLikes(\n $likes=$value\n oppositeBreed=oppositeBreed\n eventId=eventId\n )\n else\n Alert(variant='warning') Select breed to choose likes\n `\n})\n\nconst SelectLikes = observer(({ $likes, oppositeBreed, eventId }) => {\n const $cats = useSub($.cats, { eventId, breed: oppositeBreed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n - const catId = $cat.getId()\n Item.item(\n key=catId\n styleName={ selected: $likes[catId].get() }\n onPress=() => $likes[catId].get() ? $likes[catId].del() : $likes[catId].set(true)\n )\n CatCard($cat=$cat small)\n else\n Alert(variant='info') No cats with selected breed yet\n style(lang='styl')\n .item\n border-radius 1u\n &.selected\n // FIXME: We can't use color var(--color-text-success-strong) here\n background-color var(--color-text-success-strong)\n `\n})\n" ], - "mappings": "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", + "mappings": "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", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/babel/event-tabs-breed.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/babel/event-tabs-breed.tsx.output.sourcemap.json index 77ee875..e574b17 100644 --- a/test/fixtures/real-project/snapshots/babel/event-tabs-breed.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/babel/event-tabs-breed.tsx.output.sourcemap.json @@ -83,6 +83,6 @@ "sourcesContent": [ "import React, { useState } from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport {\n Link, Item, ScrollView, Form, useFormProps, Alert,\n Content, Tag, Br, Button, Modal, Div, confirm,\n useFormFields$, useValidate\n} from 'startupjs-ui'\nimport { useGlobalSearchParams } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faLink } from '@fortawesome/free-solid-svg-icons/faLink'\nimport CatCard from '@/components/CatCard'\nimport { CAT_FORM } from '@/model/cats/schema'\n\nexport default observer(({ breed }) => {\n const { eventId } = useGlobalSearchParams()\n const [$selected, set$selected] = useState()\n const $new = $()\n const $showModal = $()\n const $mode = $()\n const $fields = useFormFields$(CAT_FORM)\n const validate = useValidate()\n\n function showCreate () {\n $new.set({ breed })\n $fields.breed.disabled.set(true)\n set$selected(() => $new)\n $mode.set('new')\n $showModal.set(true)\n }\n\n function showEdit ($cat) {\n $fields.breed.disabled.del()\n set$selected(() => $cat)\n $mode.set('edit')\n $showModal.set(true)\n }\n\n function cancel () {\n if (!$showModal.get()) return\n $showModal.del()\n $mode.del()\n }\n\n async function create () {\n if (!validate()) return\n await $.cats.addNew({\n ...$new.getDeepCopy(),\n eventId\n })\n cancel()\n }\n\n async function deleteCat () {\n if (!await confirm(`Are you sure you want to delete ${$selected.name.get()}?`)) return\n await $selected.del()\n cancel()\n }\n\n return pug`\n ScrollView(full)\n Content(full pure)\n CatsList(eventId=eventId onEdit=showEdit breed=breed)\n Content(padding=1)\n Button(onPress=showCreate) Add new #{breed}\n Modal(\n title=$mode.get() === 'new' ? 'Create cat' : 'Edit cat'\n $visible=$showModal\n onDismiss=cancel\n )\n - const oppositeBreed = $selected?.breed.get() && ($selected.breed.get() === 'domestic' ? 'wild' : 'domestic')\n Form(\n key=$selected?.getId() || 'NEW'\n $fields=$fields\n $value=$selected\n oppositeBreed=oppositeBreed\n eventId=eventId\n customInputs={\n likes: SelectLikesInput\n }\n validate=validate\n )\n Br\n if $mode.get() === 'new'\n Div(align='right' row)\n Button(onPress=cancel) Cancel\n Button(disabled=validate.hasErrors pushed variant='flat' color='primary' onPress=create) Create\n else if $mode.get() === 'edit'\n Div(align='right' row)\n Button(color='error' onPress=deleteCat) Delete\n `\n})\n\nconst CatsList = observer(({ onEdit, breed, eventId }) => {\n if (!eventId) return pug`Alert(variant='error') No event specified`\n const $cats = useSub($.cats, { eventId, breed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n Item(key=$cat.getId())\n CatCard($cat=$cat)\n Item.Right\n Div(vAlign='center' row gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n Button(variant='text' icon=faPen onPress=() => onEdit($cat) tooltip='Edit')\n Link(href='/events/' + eventId + '/matches/' + $cat.getId())\n Button(variant='text' icon=faHeart tooltip='Matches')\n Link(href='/cats/' + $cat.token.get())\n Button(variant='text' icon=faLink tooltip='Cat profile link') Link\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nconst SelectLikesInput = observer(({ $value, ...props }) => {\n const { oppositeBreed, eventId } = { ...useFormProps(), ...props }\n return pug`\n if oppositeBreed\n SelectLikes(\n $likes=$value\n oppositeBreed=oppositeBreed\n eventId=eventId\n )\n else\n Alert(variant='warning') Select breed to choose likes\n `\n})\n\nconst SelectLikes = observer(({ $likes, oppositeBreed, eventId }) => {\n const $cats = useSub($.cats, { eventId, breed: oppositeBreed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n - const catId = $cat.getId()\n Item.item(\n key=catId\n styleName={ selected: $likes[catId].get() }\n onPress=() => $likes[catId].get() ? $likes[catId].del() : $likes[catId].set(true)\n )\n CatCard($cat=$cat small)\n else\n Alert(variant='info') No cats with selected breed yet\n style(lang='styl')\n .item\n border-radius 1u\n &.selected\n // FIXME: We can't use color var(--color-text-success-strong) here\n background-color var(--color-text-success-strong)\n `\n})\n" ], - "mappings": "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", + "mappings": "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", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/babel/event-tabs-layout.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/babel/event-tabs-layout.js.output.sourcemap.json index 3713b9d..1ce22f4 100644 --- a/test/fixtures/real-project/snapshots/babel/event-tabs-layout.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/babel/event-tabs-layout.js.output.sourcemap.json @@ -57,6 +57,6 @@ "sourcesContent": [ "// import { Platform } from 'react-native'\nimport React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { useColors, Icon, Form, Modal, Button } from 'startupjs-ui'\nimport { Tabs, useLocalSearchParams, Stack } from 'expo-router'\nimport { faVenus as faWildBadge } from '@fortawesome/free-solid-svg-icons/faVenus'\nimport { faMars as faDomesticBadge } from '@fortawesome/free-solid-svg-icons/faMars'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faToolbox } from '@fortawesome/free-solid-svg-icons/faToolbox'\nimport { EVENT_FORM } from '@/model/events/schema'\n\nexport default observer(function TabLayout () {\n const getColor = useColors()\n const { eventId } = useLocalSearchParams()\n const $event = useSub($.events[eventId])\n if (!$event.get()) throw Error('No such event')\n\n // NOTE:\n // headerShown -- Disable the static render of the header on web to prevent a hydration error in React Navigation v6.\n // tabBarStyle/order - Move the tab bar to the top on tablet+\n return pug`\n Stack.Screen(\n options={\n title: $event.name.get(),\n headerRight: () => renderEditEvent({ $event })\n }\n )\n Tabs(\n title=$event.name.get()\n screenOptions={\n ...styl('screen'),\n tabBarActiveTintColor: getColor('primary'),\n tabBarActiveBackgroundColor: 'rgba(255, 255, 255, 0.5)',\n headerShown: false,\n headerTitle: $event.name.get()\n }\n )\n Tabs.Screen(\n name='index'\n options={\n title: 'Dashboard',\n tabBarIcon: renderHomeIcon\n }\n )\n Tabs.Screen(\n name='-breed'\n options={\n href: null\n }\n )\n Tabs.Screen(\n name='domestic'\n options={\n title: 'Domestic Cats',\n tabBarIcon: renderDomesticIcon\n }\n )\n Tabs.Screen(\n name='wild'\n options={\n title: 'Wild Cats',\n tabBarIcon: renderWildIcon\n }\n )\n Tabs.Screen(\n name='test'\n options={\n title: 'Dev Only',\n tabBarIcon: renderTestIcon\n }\n )\n style(lang='styl')\n +tablet()\n .screen\n &:part(tabBar)\n order -1\n background-color transparent\n border-bottom-width 1px\n border-bottom-color rgba(0, 0, 0, 0.1)\n `\n})\n\nfunction renderEditEvent ({ $event }) {\n return pug`\n EditEvent($event=$event)\n `\n}\n\nconst EditEvent = observer(({ $event }) => {\n const $showModal = $()\n return pug`\n Button(onPress=() => $showModal.set(true) variant='text' icon=faPen) Edit this cat meetup\n Modal(\n title='Edit cat meetup'\n $visible=$showModal\n )\n Form(\n $value=$event\n fields=EVENT_FORM\n )\n `\n})\n\nfunction renderWildIcon ({ color, size }) {\n return pug`\n Icon(icon=faWildBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderDomesticIcon ({ color, size }) {\n return pug`\n Icon(icon=faDomesticBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderHomeIcon ({ color, size }) {\n return pug`\n Icon(icon=faHeart style={ color, width: size, height: size })\n `\n}\n\nfunction renderTestIcon ({ color, size }) {\n return pug`\n Icon(icon=faToolbox style={ color, width: size, height: size })\n `\n}\n" ], - "mappings": "AACA,OAAAA,KAAA;qDACoD;AACpD,SAAAC,SAAA,EAAAC,IAAA,EAAAC,IAAA,EAAAC,KAAA,EAAAC,MAAA;AACA,SAAAC,IAAA,EAAAC,oBAAA,EAAAC,KAAA;AACA,SAAAC,OAAA,IAAAC,WAAA;AACA,SAAAC,MAAA,IAAAC,eAAA;AACA,SAAAC,OAAA;AACA,SAAAC,KAAA;AACA,SAAAC,SAAA;AACA,SAAAC,UAAA;AAEA,eAAAC,QAAA,UAAAC,UAAA;;;;;;;;;;;EACA,MAAAC,QAAA,GAAAlB,SAAA;EACA;IAAAmB;EAAA,IAAAb,oBAAA;EACA,MAAAc,MAAA,GAAAC,MAAA,CAAAC,CAAA,CAAAC,MAAA,CAAAJ,OAAA;EACA,KAAAC,MAAA,CAAAI,GAAA,UAAAC,KAAA;EAKA,UACI,aACE,SAAQ;MACVC,KAAA,EAAAN,MAAA,CAAAO,IAAA,CAAAH,GAAA;MACAI,WAAA,EAAAA,CAAA,KAAAC,eAAA;QAAAT;MAAA;IACA,MAEA,KACE,OAAMA,MAAA,CAAAO,IAAA,CAAAH,GAAA,IACN,eAAc;MAChB,GAAAM,IAAA;MACAC,qBAAA,EAAAb,QAAA;MACAc,2BAAA;MACAC,WAAA;MACAC,WAAA,EAAAd,MAAA,CAAAO,IAAA,CAAAH,GAAA;IACA,IAEE,YACE,aACA,SAAQ;QACZE,KAAA;QACAS,UAAA,EAAAC;MACA,MAEE,YACE,cACA,SAAQ;QACZC,IAAA;MACA,MAEE,YACE,gBACA,SAAQ;QACZX,KAAA;QACAS,UAAA,EAAAG;MACA,MAEE,YACE,YACA,SAAQ;QACZZ,KAAA;QACAS,UAAA,EAAAI;MACA,MAEE,YACE,YACA,SAAQ;QACZb,KAAA;QACAS,UAAA,EAAAK;MACA;AAWJ;AAEA,SAAAX,gBAAA;EAAAT;AAAA;EACA,QACI,kBAAiBA,MAAA;AAErB;AAEA,MAAAqB,SAAA,GAAAzB,QAAA;EAAAI;AAAA;EACA,MAAAsB,UAAA,GAAApB,CAAA;EACA,UACI,gBAAe,MAAAoB,UAAA,CAAAC,GAAA,QAA2B,qBAAoB9B,KAAA,EAAO,8BACrE,MACE,wBACA,UAAS6B,UAAA,GAET,KACE,QAAOtB,MAAA,EACP,QAAOL,UAAA;AAGf;AAEA,SAAAwB,eAAA;EAAAK,KAAA;EAAAC;AAAA;EACA,QACI,WAAUpC,WAAA,EAAY,OAAM;IAAAmC,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAEhC;AAEA,SAAAP,mBAAA;EAAAM,KAAA;EAAAC;AAAA;EACA,QACI,WAAUlC,eAAA,EAAgB,OAAM;IAAAiC,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAEpC;AAEA,SAAAT,eAAA;EAAAQ,KAAA;EAAAC;AAAA;EACA,QACI,WAAUjC,OAAA,EAAQ,OAAM;IAAAgC,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAE5B;AAEA,SAAAL,eAAA;EAAAI,KAAA;EAAAC;AAAA;EACA,QACI,WAAU/B,SAAA,EAAU,OAAM;IAAA8B,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAE9B", + "mappings": "AACA,OAAAA,KAAA;qDACoD;AACpD,SAAAC,SAAA,EAAAC,IAAA,EAAAC,IAAA,EAAAC,KAAA,EAAAC,MAAA;AACA,SAAAC,IAAA,EAAAC,oBAAA,EAAAC,KAAA;AACA,SAAAC,OAAA,IAAAC,WAAA;AACA,SAAAC,MAAA,IAAAC,eAAA;AACA,SAAAC,OAAA;AACA,SAAAC,KAAA;AACA,SAAAC,SAAA;AACA,SAAAC,UAAA;AAEA,eAAAC,QAAA,UAAAC,UAAA;;;;;;;;;;;EACA,MAAAC,QAAA,GAAAlB,SAAA;EACA;IAAAmB;EAAA,IAAAb,oBAAA;EACA,MAAAc,MAAA,GAAAC,MAAA,CAAAC,CAAA,CAAAC,MAAA,CAAAJ,OAAA;EACA,KAAAC,MAAA,CAAAI,GAAA,UAAAC,KAAA;EAKA,UACI,aACE,SAAQ;MACVC,KAAA,EAAAN,MAAA,CAAAO,IAAA,CAAAH,GAAA;MACAI,WAAA,EAAAA,CAAA,KAAAC,eAAA;QAAAT;MAAA;IACA,MAEA,KACE,OAAMA,MAAA,CAAAO,IAAA,CAAAH,GAAA,IACN,eAAc;MAChB,GAAAM,IAAA;MACAC,qBAAA,EAAAb,QAAA;MACAc,2BAAA;MACAC,WAAA;MACAC,WAAA,EAAAd,MAAA,CAAAO,IAAA,CAAAH,GAAA;IACA,IAEE,YACE,aACA,SAAQ;QACZE,KAAA;QACAS,UAAA,EAAAC;MACA,MAEE,YACE,cACA,SAAQ;QACZC,IAAA;MACA,MAEE,YACE,gBACA,SAAQ;QACZX,KAAA;QACAS,UAAA,EAAAG;MACA,MAEE,YACE,YACA,SAAQ;QACZZ,KAAA;QACAS,UAAA,EAAAI;MACA,MAEE,YACE,YACA,SAAQ;QACZb,KAAA;QACAS,UAAA,EAAAK;MACA;AAWJ;AAEA,SAAAX,gBAAA;EAAAT;AAAA;EACA,QACI,kBAAUA,MAAA;AAEd;AAEA,MAAAqB,SAAA,GAAAzB,QAAA;EAAAI;AAAA;EACA,MAAAsB,UAAA,GAAApB,CAAA;EACA,UACI,gBAAe,MAAAoB,UAAA,CAAAC,GAAA,QAA2B,qBAAoB9B,KAAA,EAAO,8BACrE,MACE,wBACA,UAAS6B,UAAA,GAET,KACE,QAAOtB,MAAA,EACP,QAAOL,UAAA;AAGf;AAEA,SAAAwB,eAAA;EAAAK,KAAA;EAAAC;AAAA;EACA,QACI,WAAUpC,WAAA,EAAY,OAAM;IAAAmC,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAEhC;AAEA,SAAAP,mBAAA;EAAAM,KAAA;EAAAC;AAAA;EACA,QACI,WAAUlC,eAAA,EAAgB,OAAM;IAAAiC,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAEpC;AAEA,SAAAT,eAAA;EAAAQ,KAAA;EAAAC;AAAA;EACA,QACI,WAAUjC,OAAA,EAAQ,OAAM;IAAAgC,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAE5B;AAEA,SAAAL,eAAA;EAAAI,KAAA;EAAAC;AAAA;EACA,QACI,WAAU/B,SAAA,EAAU,OAAM;IAAA8B,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAE9B", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/babel/event-tabs-layout.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/babel/event-tabs-layout.tsx.output.sourcemap.json index b6cf61a..b539588 100644 --- a/test/fixtures/real-project/snapshots/babel/event-tabs-layout.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/babel/event-tabs-layout.tsx.output.sourcemap.json @@ -57,6 +57,6 @@ "sourcesContent": [ "// import { Platform } from 'react-native'\nimport React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { useColors, Icon, Form, Modal, Button } from 'startupjs-ui'\nimport { Tabs, useLocalSearchParams, Stack } from 'expo-router'\nimport { faVenus as faWildBadge } from '@fortawesome/free-solid-svg-icons/faVenus'\nimport { faMars as faDomesticBadge } from '@fortawesome/free-solid-svg-icons/faMars'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faToolbox } from '@fortawesome/free-solid-svg-icons/faToolbox'\nimport { EVENT_FORM } from '@/model/events/schema'\n\nexport default observer(function TabLayout () {\n const getColor = useColors()\n const { eventId } = useLocalSearchParams()\n const $event = useSub($.events[eventId])\n if (!$event.get()) throw Error('No such event')\n\n // NOTE:\n // headerShown -- Disable the static render of the header on web to prevent a hydration error in React Navigation v6.\n // tabBarStyle/order - Move the tab bar to the top on tablet+\n return pug`\n Stack.Screen(\n options={\n title: $event.name.get(),\n headerRight: () => renderEditEvent({ $event })\n }\n )\n Tabs(\n title=$event.name.get()\n screenOptions={\n ...styl('screen'),\n tabBarActiveTintColor: getColor('primary'),\n tabBarActiveBackgroundColor: 'rgba(255, 255, 255, 0.5)',\n headerShown: false,\n headerTitle: $event.name.get()\n }\n )\n Tabs.Screen(\n name='index'\n options={\n title: 'Dashboard',\n tabBarIcon: renderHomeIcon\n }\n )\n Tabs.Screen(\n name='-breed'\n options={\n href: null\n }\n )\n Tabs.Screen(\n name='domestic'\n options={\n title: 'Domestic Cats',\n tabBarIcon: renderDomesticIcon\n }\n )\n Tabs.Screen(\n name='wild'\n options={\n title: 'Wild Cats',\n tabBarIcon: renderWildIcon\n }\n )\n Tabs.Screen(\n name='test'\n options={\n title: 'Dev Only',\n tabBarIcon: renderTestIcon\n }\n )\n style(lang='styl')\n +tablet()\n .screen\n &:part(tabBar)\n order -1\n background-color transparent\n border-bottom-width 1px\n border-bottom-color rgba(0, 0, 0, 0.1)\n `\n})\n\nfunction renderEditEvent ({ $event }) {\n return pug`\n EditEvent($event=$event)\n `\n}\n\nconst EditEvent = observer(({ $event }) => {\n const $showModal = $()\n return pug`\n Button(onPress=() => $showModal.set(true) variant='text' icon=faPen) Edit this cat meetup\n Modal(\n title='Edit cat meetup'\n $visible=$showModal\n )\n Form(\n $value=$event\n fields=EVENT_FORM\n )\n `\n})\n\nfunction renderWildIcon ({ color, size }) {\n return pug`\n Icon(icon=faWildBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderDomesticIcon ({ color, size }) {\n return pug`\n Icon(icon=faDomesticBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderHomeIcon ({ color, size }) {\n return pug`\n Icon(icon=faHeart style={ color, width: size, height: size })\n `\n}\n\nfunction renderTestIcon ({ color, size }) {\n return pug`\n Icon(icon=faToolbox style={ color, width: size, height: size })\n `\n}\n" ], - "mappings": "AACA,OAAAA,KAAA;qDACoD;AACpD,SAAAC,SAAA,EAAAC,IAAA,EAAAC,IAAA,EAAAC,KAAA,EAAAC,MAAA;AACA,SAAAC,IAAA,EAAAC,oBAAA,EAAAC,KAAA;AACA,SAAAC,OAAA,IAAAC,WAAA;AACA,SAAAC,MAAA,IAAAC,eAAA;AACA,SAAAC,OAAA;AACA,SAAAC,KAAA;AACA,SAAAC,SAAA;AACA,SAAAC,UAAA;AAEA,eAAAC,QAAA,UAAAC,UAAA;;;;;;;;;;;EACA,MAAAC,QAAA,GAAAlB,SAAA;EACA;IAAAmB;EAAA,IAAAb,oBAAA;EACA,MAAAc,MAAA,GAAAC,MAAA,CAAAC,CAAA,CAAAC,MAAA,CAAAJ,OAAA;EACA,KAAAC,MAAA,CAAAI,GAAA,UAAAC,KAAA;EAKA,UACI,aACE,SAAQ;MACVC,KAAA,EAAAN,MAAA,CAAAO,IAAA,CAAAH,GAAA;MACAI,WAAA,EAAAA,CAAA,KAAAC,eAAA;QAAAT;MAAA;IACA,MAEA,KACE,OAAMA,MAAA,CAAAO,IAAA,CAAAH,GAAA,IACN,eAAc;MAChB,GAAAM,IAAA;MACAC,qBAAA,EAAAb,QAAA;MACAc,2BAAA;MACAC,WAAA;MACAC,WAAA,EAAAd,MAAA,CAAAO,IAAA,CAAAH,GAAA;IACA,IAEE,YACE,aACA,SAAQ;QACZE,KAAA;QACAS,UAAA,EAAAC;MACA,MAEE,YACE,cACA,SAAQ;QACZC,IAAA;MACA,MAEE,YACE,gBACA,SAAQ;QACZX,KAAA;QACAS,UAAA,EAAAG;MACA,MAEE,YACE,YACA,SAAQ;QACZZ,KAAA;QACAS,UAAA,EAAAI;MACA,MAEE,YACE,YACA,SAAQ;QACZb,KAAA;QACAS,UAAA,EAAAK;MACA;AAWJ;AAEA,SAAAX,gBAAA;EAAAT;AAAA;EACA,QACI,kBAAiBA,MAAA;AAErB;AAEA,MAAAqB,SAAA,GAAAzB,QAAA;EAAAI;AAAA;EACA,MAAAsB,UAAA,GAAApB,CAAA;EACA,UACI,gBAAe,MAAAoB,UAAA,CAAAC,GAAA,QAA2B,qBAAoB9B,KAAA,EAAO,8BACrE,MACE,wBACA,UAAS6B,UAAA,GAET,KACE,QAAOtB,MAAA,EACP,QAAOL,UAAA;AAGf;AAEA,SAAAwB,eAAA;EAAAK,KAAA;EAAAC;AAAA;EACA,QACI,WAAUpC,WAAA,EAAY,OAAM;IAAAmC,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAEhC;AAEA,SAAAP,mBAAA;EAAAM,KAAA;EAAAC;AAAA;EACA,QACI,WAAUlC,eAAA,EAAgB,OAAM;IAAAiC,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAEpC;AAEA,SAAAT,eAAA;EAAAQ,KAAA;EAAAC;AAAA;EACA,QACI,WAAUjC,OAAA,EAAQ,OAAM;IAAAgC,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAE5B;AAEA,SAAAL,eAAA;EAAAI,KAAA;EAAAC;AAAA;EACA,QACI,WAAU/B,SAAA,EAAU,OAAM;IAAA8B,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAE9B", + "mappings": "AACA,OAAAA,KAAA;qDACoD;AACpD,SAAAC,SAAA,EAAAC,IAAA,EAAAC,IAAA,EAAAC,KAAA,EAAAC,MAAA;AACA,SAAAC,IAAA,EAAAC,oBAAA,EAAAC,KAAA;AACA,SAAAC,OAAA,IAAAC,WAAA;AACA,SAAAC,MAAA,IAAAC,eAAA;AACA,SAAAC,OAAA;AACA,SAAAC,KAAA;AACA,SAAAC,SAAA;AACA,SAAAC,UAAA;AAEA,eAAAC,QAAA,UAAAC,UAAA;;;;;;;;;;;EACA,MAAAC,QAAA,GAAAlB,SAAA;EACA;IAAAmB;EAAA,IAAAb,oBAAA;EACA,MAAAc,MAAA,GAAAC,MAAA,CAAAC,CAAA,CAAAC,MAAA,CAAAJ,OAAA;EACA,KAAAC,MAAA,CAAAI,GAAA,UAAAC,KAAA;EAKA,UACI,aACE,SAAQ;MACVC,KAAA,EAAAN,MAAA,CAAAO,IAAA,CAAAH,GAAA;MACAI,WAAA,EAAAA,CAAA,KAAAC,eAAA;QAAAT;MAAA;IACA,MAEA,KACE,OAAMA,MAAA,CAAAO,IAAA,CAAAH,GAAA,IACN,eAAc;MAChB,GAAAM,IAAA;MACAC,qBAAA,EAAAb,QAAA;MACAc,2BAAA;MACAC,WAAA;MACAC,WAAA,EAAAd,MAAA,CAAAO,IAAA,CAAAH,GAAA;IACA,IAEE,YACE,aACA,SAAQ;QACZE,KAAA;QACAS,UAAA,EAAAC;MACA,MAEE,YACE,cACA,SAAQ;QACZC,IAAA;MACA,MAEE,YACE,gBACA,SAAQ;QACZX,KAAA;QACAS,UAAA,EAAAG;MACA,MAEE,YACE,YACA,SAAQ;QACZZ,KAAA;QACAS,UAAA,EAAAI;MACA,MAEE,YACE,YACA,SAAQ;QACZb,KAAA;QACAS,UAAA,EAAAK;MACA;AAWJ;AAEA,SAAAX,gBAAA;EAAAT;AAAA;EACA,QACI,kBAAUA,MAAA;AAEd;AAEA,MAAAqB,SAAA,GAAAzB,QAAA;EAAAI;AAAA;EACA,MAAAsB,UAAA,GAAApB,CAAA;EACA,UACI,gBAAe,MAAAoB,UAAA,CAAAC,GAAA,QAA2B,qBAAoB9B,KAAA,EAAO,8BACrE,MACE,wBACA,UAAS6B,UAAA,GAET,KACE,QAAOtB,MAAA,EACP,QAAOL,UAAA;AAGf;AAEA,SAAAwB,eAAA;EAAAK,KAAA;EAAAC;AAAA;EACA,QACI,WAAUpC,WAAA,EAAY,OAAM;IAAAmC,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAEhC;AAEA,SAAAP,mBAAA;EAAAM,KAAA;EAAAC;AAAA;EACA,QACI,WAAUlC,eAAA,EAAgB,OAAM;IAAAiC,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAEpC;AAEA,SAAAT,eAAA;EAAAQ,KAAA;EAAAC;AAAA;EACA,QACI,WAAUjC,OAAA,EAAQ,OAAM;IAAAgC,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAE5B;AAEA,SAAAL,eAAA;EAAAI,KAAA;EAAAC;AAAA;EACA,QACI,WAAU/B,SAAA,EAAU,OAAM;IAAA8B,KAAA;IAAAE,KAAA,EAAAD,IAAA;IAAAE,MAAA,EAAAF;EAAA;AAE9B", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/esbuild/CatCard.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/esbuild/CatCard.js.output.sourcemap.json index 7ae87ed..4c661cc 100644 --- a/test/fixtures/real-project/snapshots/esbuild/CatCard.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/esbuild/CatCard.js.output.sourcemap.json @@ -6,6 +6,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport { Div, Span, Avatar, Link } from 'startupjs-ui'\n\nexport default observer(({ $cat, showPhone, large, small }) => {\n const { name, number, phone, catgram, photoFileId, phonegram } = $cat.get()\n return pug`\n Div(part='root' row vAlign='center')\n if photoFileId\n Photo.avatar(styleName={ large, small } fileId=photoFileId name=name)\n else\n Avatar.avatar(styleName={ large, small })= name\n Div(row)\n Span.text(bold styleName={ large })= (number || 'X') + '. '\n Div\n Span.text(styleName={ large })= name\n if showPhone\n if phone\n Span.text(styleName={ large })\n Span(bold) Phone:#{' '}\n = phone\n if catgram\n Span.text(styleName={ large })\n Span(bold) Catgram:#{' '}\n Link.text(styleName={ large } to=getCatgramLink(catgram))= catgram\n if phonegram\n Span.text(styleName={ large })\n Span(bold) Phonegram:#{' '}\n Link.text(styleName={ large } to=getPhonegramLink(phonegram))= phonegram\n style(lang='styl')\n .avatar\n margin-right 1u\n &.large\n width 12u\n height @width\n &.small\n width 4u\n height @width\n .text.large\n font(h6)\n `\n})\n\nconst Photo = observer(({ fileId, name }) => {\n const $file = useSub($.files[fileId])\n let url\n try { url = $file.getUrl() } catch (err) {}\n return pug`\n Avatar(part='root' src=url)= name\n `\n})\n\nfunction getCatgramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://catgr.am/' + username\n}\n\nfunction getPhonegramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://www.phonegram.com/' + username\n}\n" ], - "mappings": "AAAA,OAAA,WAAA;;AAEA,SAAA,KAAA,MAAA,QAAA,YAAA;AAEA,IAAA,kBAAA,SAAA,CAAA,EAAA,MAAA,WAAA,OAAA,MAAA,MAAA;;;;;;;;;;;;;;AACA,QAAA,EAAA,MAAA,QAAA,OAAA,SAAA,aAAA,UAAA,IAAA,KAAA,IAAA;AACA,SAAA,CACI,IAAA,KAAA,OAAA,IAAA,OAAA,UACK,cAAA,CACD,MAAa,WAAA,CAAA,UAAU,EAAA,OAAA,MAAA,CAAA,GAAiB,QAAO,aAAY,MAAK,MAAA,KAAA,CAEhE,OAAc,WAAA,CAAA,UAAU,EAAA,OAAA,MAAA,CAAA,IAAmB,KAAA,EAA3C,QAA2C,CAC7C,IAAA,IAAA,CACE,KAAe,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAf,OAA2B,UAAA,OAAA,KAAA,EAArC,KAAqC,CACrC,IAAA,CACE,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,IAAY,KAAA,EAAhC,MACG,YAAA,GACE,QAAA,CACD,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAA,CAClB,KAAA,KAAW,OAAQ,IAAA,EAAnB,MACE,MAAA,EAFJ,QAEI,MACH,UAAA,CACD,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAA,CAClB,KAAA,KAAW,SAAU,IAAA,EAArB,KAAqB,CACrB,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAU,IAAG,eAAA,OAAA,IAA0B,QAAA,EAA3D,KAA2D,EAF7D,QAE6D,MAC5D,YAAA,CACD,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAA,CAClB,KAAA,KAAW,WAAY,IAAA,EAAvB,KAAuB,CACvB,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAU,IAAG,iBAAA,SAAA,IAA8B,UAAA,EAA/D,KAA+D,EAFjE,QAEiE,KAAA,MAAA,KAAA,EAdvE,IAcuE,EAhBzE,IAgByE,EArB3E;AAkCJ,CAAA;AAEA,MAAA,QAAA,SAAA,CAAA,EAAA,QAAA,KAAA,MAAA;AACA,QAAA,QAAA,OAAA,EAAA,MAAA,MAAA,CAAA;AACA,MAAA;AACA,MAAA;AAAA,UAAA,MAAA,OAAA;EAAA,SAAA,KAAA;EAAA;AACA,SAAA,CACI,OAAA,KAAA,OAAA,KAAuB,MAAM,KAAA,EAA7B;AAEJ,CAAA;AAEA,SAAA,eAAA,UAAA;AACA,MAAA,CAAA,SAAA;AACA,MAAA,QAAA,KAAA,QAAA,EAAA,QAAA;AACA,SAAA,sBAAA;AACA;AAEA,SAAA,iBAAA,UAAA;AACA,MAAA,CAAA,SAAA;AACA,MAAA,QAAA,KAAA,QAAA,EAAA,QAAA;AACA,SAAA,+BAAA;AACA;", + "mappings": "AAAA,OAAA,WAAA;;AAEA,SAAA,KAAA,MAAA,QAAA,YAAA;AAEA,IAAA,kBAAA,SAAA,CAAA,EAAA,MAAA,WAAA,OAAA,MAAA,MAAA;;;;;;;;;;;;;;AACA,QAAA,EAAA,MAAA,QAAA,OAAA,SAAA,aAAA,UAAA,IAAA,KAAA,IAAA;AACA,SAAA,CACI,IAAA,KAAA,OAAA,IAAA,OAAA,UACK,cAAA,CACD,MAAa,WAAA,CAAA,UAAU,EAAA,OAAA,MAAA,CAAA,GAAiB,QAAO,aAAY,MAAA,MAAA,KAAA,CAE3D,OAAc,WAAA,CAAA,UAAU,EAAA,OAAA,MAAA,CAAA,IAAmB,KAAA,EAA3C,QAA2C,CAC7C,IAAA,IAAA,CACE,KAAe,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAf,OAA2B,UAAA,OAAA,KAAA,EAArC,KAAqC,CACrC,IAAA,CACE,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,IAAY,KAAA,EAAhC,MACG,YAAA,GACE,QAAA,CACD,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAA,CAClB,KAAA,KAAW,OAAQ,IAAA,EAAnB,MACE,MAAA,EAFJ,QAEI,MACH,UAAA,CACD,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAA,CAClB,KAAA,KAAW,SAAU,IAAA,EAArB,KAAqB,CACrB,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAU,IAAG,eAAA,OAAA,IAA0B,QAAA,EAA3D,KAA2D,EAF7D,QAE6D,MAC5D,YAAA,CACD,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAA,CAClB,KAAA,KAAW,WAAY,IAAA,EAAvB,KAAuB,CACvB,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAU,IAAG,iBAAA,SAAA,IAA8B,UAAA,EAA/D,KAA+D,EAFjE,QAEiE,KAAA,MAAA,KAAA,EAdvE,IAcuE,EAhBzE,IAgByE,EArB3E;AAkCJ,CAAA;AAEA,MAAA,QAAA,SAAA,CAAA,EAAA,QAAA,KAAA,MAAA;AACA,QAAA,QAAA,OAAA,EAAA,MAAA,MAAA,CAAA;AACA,MAAA;AACA,MAAA;AAAA,UAAA,MAAA,OAAA;EAAA,SAAA,KAAA;EAAA;AACA,SAAA,CACI,OAAA,KAAA,OAAA,KAAuB,MAAM,KAAA,EAA7B;AAEJ,CAAA;AAEA,SAAA,eAAA,UAAA;AACA,MAAA,CAAA,SAAA;AACA,MAAA,QAAA,KAAA,QAAA,EAAA,QAAA;AACA,SAAA,sBAAA;AACA;AAEA,SAAA,iBAAA,UAAA;AACA,MAAA,CAAA,SAAA;AACA,MAAA,QAAA,KAAA,QAAA,EAAA,QAAA;AACA,SAAA,+BAAA;AACA;", "names": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/esbuild/CatCard.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/esbuild/CatCard.tsx.output.sourcemap.json index aa7bfd7..5f435fd 100644 --- a/test/fixtures/real-project/snapshots/esbuild/CatCard.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/esbuild/CatCard.tsx.output.sourcemap.json @@ -6,6 +6,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport { Div, Span, Avatar, Link } from 'startupjs-ui'\n\nexport default observer(({ $cat, showPhone, large, small }) => {\n const { name, number, phone, catgram, photoFileId, phonegram } = $cat.get()\n return pug`\n Div(part='root' row vAlign='center')\n if photoFileId\n Photo.avatar(styleName={ large, small } fileId=photoFileId name=name)\n else\n Avatar.avatar(styleName={ large, small })= name\n Div(row)\n Span.text(bold styleName={ large })= (number || 'X') + '. '\n Div\n Span.text(styleName={ large })= name\n if showPhone\n if phone\n Span.text(styleName={ large })\n Span(bold) Phone:#{' '}\n = phone\n if catgram\n Span.text(styleName={ large })\n Span(bold) Catgram:#{' '}\n Link.text(styleName={ large } to=getCatgramLink(catgram))= catgram\n if phonegram\n Span.text(styleName={ large })\n Span(bold) Phonegram:#{' '}\n Link.text(styleName={ large } to=getPhonegramLink(phonegram))= phonegram\n style(lang='styl')\n .avatar\n margin-right 1u\n &.large\n width 12u\n height @width\n &.small\n width 4u\n height @width\n .text.large\n font(h6)\n `\n})\n\nconst Photo = observer(({ fileId, name }) => {\n const $file = useSub($.files[fileId])\n let url\n try { url = $file.getUrl() } catch (err) {}\n return pug`\n Avatar(part='root' src=url)= name\n `\n})\n\nfunction getCatgramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://catgr.am/' + username\n}\n\nfunction getPhonegramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://www.phonegram.com/' + username\n}\n" ], - "mappings": ";AAEA,SAAA,KAAA,MAAA,QAAA,YAAA;AAEA,IAAA,kBAAA,SAAA,CAAA,EAAA,MAAA,WAAA,OAAA,MAAA,MAAA;;;;;;;;;;;;;;AACA,QAAA,EAAA,MAAA,QAAA,OAAA,SAAA,aAAA,UAAA,IAAA,KAAA,IAAA;AACA,SAAA,CACI,IAAA,KAAA,OAAA,IAAA,OAAA,UACK,cAAA,CACD,MAAa,WAAA,CAAA,UAAU,EAAA,OAAA,MAAA,CAAA,GAAiB,QAAO,aAAY,MAAK,MAAA,KAAA,CAEhE,OAAc,WAAA,CAAA,UAAU,EAAA,OAAA,MAAA,CAAA,IAAmB,KAAA,EAA3C,QAA2C,CAC7C,IAAA,IAAA,CACE,KAAe,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAf,OAA2B,UAAA,OAAA,KAAA,EAArC,KAAqC,CACrC,IAAA,CACE,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,IAAY,KAAA,EAAhC,MACG,YAAA,GACE,QAAA,CACD,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAA,CAClB,KAAA,KAAW,OAAQ,IAAA,EAAnB,MACE,MAAA,EAFJ,QAEI,MACH,UAAA,CACD,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAA,CAClB,KAAA,KAAW,SAAU,IAAA,EAArB,KAAqB,CACrB,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAU,IAAG,eAAA,OAAA,IAA0B,QAAA,EAA3D,KAA2D,EAF7D,QAE6D,MAC5D,YAAA,CACD,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAA,CAClB,KAAA,KAAW,WAAY,IAAA,EAAvB,KAAuB,CACvB,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAU,IAAG,iBAAA,SAAA,IAA8B,UAAA,EAA/D,KAA+D,EAFjE,QAEiE,KAAA,MAAA,KAAA,EAdvE,IAcuE,EAhBzE,IAgByE,EArB3E;AAkCJ,CAAA;AAEA,MAAA,QAAA,SAAA,CAAA,EAAA,QAAA,KAAA,MAAA;AACA,QAAA,QAAA,OAAA,EAAA,MAAA,MAAA,CAAA;AACA,MAAA;AACA,MAAA;AAAA,UAAA,MAAA,OAAA;EAAA,SAAA,KAAA;EAAA;AACA,SAAA,CACI,OAAA,KAAA,OAAA,KAAuB,MAAM,KAAA,EAA7B;AAEJ,CAAA;AAEA,SAAA,eAAA,UAAA;AACA,MAAA,CAAA,SAAA;AACA,MAAA,QAAA,KAAA,QAAA,EAAA,QAAA;AACA,SAAA,sBAAA;AACA;AAEA,SAAA,iBAAA,UAAA;AACA,MAAA,CAAA,SAAA;AACA,MAAA,QAAA,KAAA,QAAA,EAAA,QAAA;AACA,SAAA,+BAAA;AACA;", + "mappings": ";AAEA,SAAA,KAAA,MAAA,QAAA,YAAA;AAEA,IAAA,kBAAA,SAAA,CAAA,EAAA,MAAA,WAAA,OAAA,MAAA,MAAA;;;;;;;;;;;;;;AACA,QAAA,EAAA,MAAA,QAAA,OAAA,SAAA,aAAA,UAAA,IAAA,KAAA,IAAA;AACA,SAAA,CACI,IAAA,KAAA,OAAA,IAAA,OAAA,UACK,cAAA,CACD,MAAa,WAAA,CAAA,UAAU,EAAA,OAAA,MAAA,CAAA,GAAiB,QAAO,aAAY,MAAA,MAAA,KAAA,CAE3D,OAAc,WAAA,CAAA,UAAU,EAAA,OAAA,MAAA,CAAA,IAAmB,KAAA,EAA3C,QAA2C,CAC7C,IAAA,IAAA,CACE,KAAe,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAf,OAA2B,UAAA,OAAA,KAAA,EAArC,KAAqC,CACrC,IAAA,CACE,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,IAAY,KAAA,EAAhC,MACG,YAAA,GACE,QAAA,CACD,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAA,CAClB,KAAA,KAAW,OAAQ,IAAA,EAAnB,MACE,MAAA,EAFJ,QAEI,MACH,UAAA,CACD,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAA,CAClB,KAAA,KAAW,SAAU,IAAA,EAArB,KAAqB,CACrB,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAU,IAAG,eAAA,OAAA,IAA0B,QAAA,EAA3D,KAA2D,EAF7D,QAE6D,MAC5D,YAAA,CACD,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAA,CAClB,KAAA,KAAW,WAAY,IAAA,EAAvB,KAAuB,CACvB,KAAU,WAAA,CAAA,QAAU,EAAA,MAAA,CAAA,GAAU,IAAG,iBAAA,SAAA,IAA8B,UAAA,EAA/D,KAA+D,EAFjE,QAEiE,KAAA,MAAA,KAAA,EAdvE,IAcuE,EAhBzE,IAgByE,EArB3E;AAkCJ,CAAA;AAEA,MAAA,QAAA,SAAA,CAAA,EAAA,QAAA,KAAA,MAAA;AACA,QAAA,QAAA,OAAA,EAAA,MAAA,MAAA,CAAA;AACA,MAAA;AACA,MAAA;AAAA,UAAA,MAAA,OAAA;EAAA,SAAA,KAAA;EAAA;AACA,SAAA,CACI,OAAA,KAAA,OAAA,KAAuB,MAAM,KAAA,EAA7B;AAEJ,CAAA;AAEA,SAAA,eAAA,UAAA;AACA,MAAA,CAAA,SAAA;AACA,MAAA,QAAA,KAAA,QAAA,EAAA,QAAA;AACA,SAAA,sBAAA;AACA;AAEA,SAAA,iBAAA,UAAA;AACA,MAAA,CAAA,SAAA;AACA,MAAA,QAAA,KAAA,QAAA,EAAA,QAAA;AACA,SAAA,+BAAA;AACA;", "names": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/esbuild/cat-profile-link.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/esbuild/cat-profile-link.js.output.sourcemap.json index 4804ed6..cb2f830 100644 --- a/test/fixtures/real-project/snapshots/esbuild/cat-profile-link.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/esbuild/cat-profile-link.js.output.sourcemap.json @@ -6,6 +6,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { Alert, Span, Modal, Content, Button, Form, Div, Tag, useMedia, useFormFields } from 'startupjs-ui'\nimport { useGlobalSearchParams, Stack } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport CatCard from '@/components/CatCard'\nimport * as stages from '@/components/stages'\nimport { CAT_PROFILE_EDIT_FORM } from '@/model/cats/schema'\nimport { STAGES } from '@/model/events/schema'\n\nexport default observer(() => {\n const { token } = useGlobalSearchParams()\n const [$cat] = useSub($.cats, { token })\n if (!$cat) return renderExpired()\n\n const eventId = $cat.eventId.get()\n const $event = useSub($.events[eventId])\n\n function renderTitle () {\n return pug`\n CatCard($cat=$cat)\n `\n }\n\n function renderSettings () {\n return pug`\n Profile($cat=$cat $event=$event)\n `\n }\n\n const Stage = stages[$cat.getMyStage()]\n\n return pug`\n Stack.Screen(\n options={\n headerTitle: renderTitle,\n headerRight: renderSettings\n }\n )\n Stage($cat=$cat $event=$event)\n `\n})\n\nconst Profile = observer(({ $cat, $event }) => {\n const $showEdit = $()\n const { tablet } = useMedia()\n const excludeNumber = $event.stage.get() !== STAGES.InProgress\n const profileEditFields = useFormFields(CAT_PROFILE_EDIT_FORM, excludeNumber ? { exclude: ['number'] } : {})\n\n return pug`\n Div(row vAlign='center' gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n if $cat.getMyStage() === STAGES.Profile\n Div.hackSidePadding\n else\n Button(\n variant='text'\n icon=faPen\n onPress=() => $showEdit.set(true)\n )\n if tablet\n = 'Edit cat profile'\n else\n = 'Edit'\n Modal(\n title='Edit cat profile'\n $visible=$showEdit\n )\n Form(\n fields=profileEditFields\n $value=$cat\n )\n style(lang='styl')\n .hackSidePadding\n width 1u\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nfunction renderExpired () {\n return pug`\n Content(padding)\n Alert(variant='error')\n Span\n | Cat profile link is incorrect or already expired.\n |\n | Your cat meetup profile link is only valid for a limited period of time.\n |\n | If you believe this is an error, please contact the cat meetup organizer.\n `\n}\n" ], - "mappings": "AAAA,OAAA,WAAA;;AAEA,SAAA,OAAA,MAAA,OAAA,SAAA,QAAA,MAAA,KAAA,KAAA,UAAA,qBAAA;AACA,SAAA,uBAAA,aAAA;AACA,SAAA,aAAA;AACA,OAAA,aAAA;AACA,YAAA,YAAA;AACA,SAAA,6BAAA;AACA,SAAA,cAAA;AAEA,IAAA,2BAAA,SAAA,MAAA;AACA,QAAA,EAAA,MAAA,IAAA,sBAAA;AACA,QAAA,CAAA,IAAA,IAAA,OAAA,EAAA,MAAA,EAAA,MAAA,CAAA;AACA,MAAA,CAAA,KAAA,QAAA,cAAA;AAEA,QAAA,UAAA,KAAA,QAAA,IAAA;AACA,QAAA,SAAA,OAAA,EAAA,OAAA,OAAA,CAAA;AAEA,WAAA,cAAA;AACA,WAAA,CACM,QAAA,MAAa,MAAA;EAEnB;AAEA,WAAA,iBAAA;AACA,WAAA,CACM,QAAA,MAAa,MAAK,QAAO,QAAA;EAE/B;AAEA,QAAA,QAAA,OAAA,KAAA,WAAA,CAAA;AAEA,SAAA,EAAA,CACI,MAAA,OACE,SAAQ;IACV,aAAA;IACA,aAAA;EACA,GAAA,EAAA,CAEA,MAAA,MAAW,MAAK,QAAO,QAAA,EAAA;AAE3B,CAAA;AAEA,MAAA,UAAA,SAAA,CAAA,EAAA,MAAA,OAAA,MAAA;;;;;;AACA,QAAA,YAAA,EAAA;AACA,QAAA,EAAA,OAAA,IAAA,SAAA;AACA,QAAA,gBAAA,OAAA,MAAA,IAAA,MAAA,OAAA;AACA,QAAA,oBAAA,cAAA,uBAAA,gBAAA,EAAA,SAAA,CAAA,QAAA,EAAA,IAAA,CAAA,CAAA;AAEA,SAAA,EAAA,CACI,IAAA,IAAA,OAAA,SAAA,KAA4B,IACvB,CAAA,WAAA,IAAA,IAAA,CACD,IAAA,MAAA,QAAmB,UAAA,EAAnB,OAAmB,MAClB,CAAA,KAAA,YAAA,IAAA,IAAA,CACD,IAAA,MAAA,QAAmB,QAAA,EAAnB,OAAmB,MAClB,KAAA,WAAA,MAAA,OAAA,UAAA,CACD,IAAA,WAAA,CAAA,iBAAG,GAAA,KAAA,CAEH,OACE,QAAA,OACA,MAAK,OACL,SAAQ,MAAA,UAAA,IAAA,IAAA,IAEL,SACC,qBAEA,OAAA,EARN,QAQM,EAhBV,IAgBU,CACV,MACE,MAAA,mBACA,UAAS,WAAA,CAET,KACE,QAAO,mBACP,QAAO,MAAA,EAAA,EANX,MAMW;AAMf,CAAA;AAEA,SAAA,WAAA,MAAA;AACA,UAAA,KAAA,MAAA,IAAA,KAAA,IAAA,KAAA,MAAA,KAAA,QAAA,IAAA,KAAA,IAAA,KAAA,MAAA,KAAA,UAAA,IAAA,KAAA,IAAA,KAAA;AACA;AAEA,SAAA,gBAAA;AACA,SAAA,CACI,QAAA,QAAA,CACE,MAAA,QAAA,QAAA,CACE,KACI;;;;yEAIC,EALL,KAKK,EANP,MAMO,EAPT;AASJ;", + "mappings": "AAAA,OAAA,WAAA;;AAEA,SAAA,OAAA,MAAA,OAAA,SAAA,QAAA,MAAA,KAAA,KAAA,UAAA,qBAAA;AACA,SAAA,uBAAA,aAAA;AACA,SAAA,aAAA;AACA,OAAA,aAAA;AACA,YAAA,YAAA;AACA,SAAA,6BAAA;AACA,SAAA,cAAA;AAEA,IAAA,2BAAA,SAAA,MAAA;AACA,QAAA,EAAA,MAAA,IAAA,sBAAA;AACA,QAAA,CAAA,IAAA,IAAA,OAAA,EAAA,MAAA,EAAA,MAAA,CAAA;AACA,MAAA,CAAA,KAAA,QAAA,cAAA;AAEA,QAAA,UAAA,KAAA,QAAA,IAAA;AACA,QAAA,SAAA,OAAA,EAAA,OAAA,OAAA,CAAA;AAEA,WAAA,cAAA;AACA,WAAA,CACM,QAAA,MAAQ,MAAA;EAEd;AAEA,WAAA,iBAAA;AACA,WAAA,CACM,QAAA,MAAQ,MAAU,QAAA,QAAA;EAExB;AAEA,QAAA,QAAA,OAAA,KAAA,WAAA,CAAA;AAEA,SAAA,EAAA,CACI,MAAA,OACE,SAAQ;IACV,aAAA;IACA,aAAA;EACA,GAAA,EAAA,CAEA,MAAA,MAAM,MAAU,QAAA,QAAA,EAAA;AAEpB,CAAA;AAEA,MAAA,UAAA,SAAA,CAAA,EAAA,MAAA,OAAA,MAAA;;;;;;AACA,QAAA,YAAA,EAAA;AACA,QAAA,EAAA,OAAA,IAAA,SAAA;AACA,QAAA,gBAAA,OAAA,MAAA,IAAA,MAAA,OAAA;AACA,QAAA,oBAAA,cAAA,uBAAA,gBAAA,EAAA,SAAA,CAAA,QAAA,EAAA,IAAA,CAAA,CAAA;AAEA,SAAA,EAAA,CACI,IAAA,IAAA,OAAA,SAAA,KAA4B,IACvB,CAAA,WAAA,IAAA,IAAA,CACD,IAAA,MAAA,QAAmB,UAAA,EAAnB,OAAmB,MAClB,CAAA,KAAA,YAAA,IAAA,IAAA,CACD,IAAA,MAAA,QAAmB,QAAA,EAAnB,OAAmB,MAClB,KAAA,WAAA,MAAA,OAAA,UAAA,CACD,IAAA,WAAA,CAAA,iBAAG,GAAA,KAAA,CAEH,OACE,QAAA,OACA,MAAK,OACL,SAAQ,MAAA,UAAA,IAAA,IAAA,IAEL,SACC,qBAEA,OAAA,EARN,QAQM,EAhBV,IAgBU,CACV,MACE,MAAA,mBACA,UAAS,WAAA,CAET,KACE,QAAO,mBACP,QAAO,MAAA,EAAA,EANX,MAMW;AAMf,CAAA;AAEA,SAAA,WAAA,MAAA;AACA,UAAA,KAAA,MAAA,IAAA,KAAA,IAAA,KAAA,MAAA,KAAA,QAAA,IAAA,KAAA,IAAA,KAAA,MAAA,KAAA,UAAA,IAAA,KAAA,IAAA,KAAA;AACA;AAEA,SAAA,gBAAA;AACA,SAAA,CACI,QAAA,QAAA,CACE,MAAA,QAAA,QAAA,CACE,KACI;;;;yEAIC,EALL,KAKK,EANP,MAMO,EAPT;AASJ;", "names": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/esbuild/cat-profile-link.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/esbuild/cat-profile-link.tsx.output.sourcemap.json index abc4292..7bc3dd9 100644 --- a/test/fixtures/real-project/snapshots/esbuild/cat-profile-link.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/esbuild/cat-profile-link.tsx.output.sourcemap.json @@ -6,6 +6,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { Alert, Span, Modal, Content, Button, Form, Div, Tag, useMedia, useFormFields } from 'startupjs-ui'\nimport { useGlobalSearchParams, Stack } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport CatCard from '@/components/CatCard'\nimport * as stages from '@/components/stages'\nimport { CAT_PROFILE_EDIT_FORM } from '@/model/cats/schema'\nimport { STAGES } from '@/model/events/schema'\n\nexport default observer(() => {\n const { token } = useGlobalSearchParams()\n const [$cat] = useSub($.cats, { token })\n if (!$cat) return renderExpired()\n\n const eventId = $cat.eventId.get()\n const $event = useSub($.events[eventId])\n\n function renderTitle () {\n return pug`\n CatCard($cat=$cat)\n `\n }\n\n function renderSettings () {\n return pug`\n Profile($cat=$cat $event=$event)\n `\n }\n\n const Stage = stages[$cat.getMyStage()]\n\n return pug`\n Stack.Screen(\n options={\n headerTitle: renderTitle,\n headerRight: renderSettings\n }\n )\n Stage($cat=$cat $event=$event)\n `\n})\n\nconst Profile = observer(({ $cat, $event }) => {\n const $showEdit = $()\n const { tablet } = useMedia()\n const excludeNumber = $event.stage.get() !== STAGES.InProgress\n const profileEditFields = useFormFields(CAT_PROFILE_EDIT_FORM, excludeNumber ? { exclude: ['number'] } : {})\n\n return pug`\n Div(row vAlign='center' gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n if $cat.getMyStage() === STAGES.Profile\n Div.hackSidePadding\n else\n Button(\n variant='text'\n icon=faPen\n onPress=() => $showEdit.set(true)\n )\n if tablet\n = 'Edit cat profile'\n else\n = 'Edit'\n Modal(\n title='Edit cat profile'\n $visible=$showEdit\n )\n Form(\n fields=profileEditFields\n $value=$cat\n )\n style(lang='styl')\n .hackSidePadding\n width 1u\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nfunction renderExpired () {\n return pug`\n Content(padding)\n Alert(variant='error')\n Span\n | Cat profile link is incorrect or already expired.\n |\n | Your cat meetup profile link is only valid for a limited period of time.\n |\n | If you believe this is an error, please contact the cat meetup organizer.\n `\n}\n" ], - "mappings": ";AAEA,SAAA,OAAA,MAAA,OAAA,SAAA,QAAA,MAAA,KAAA,KAAA,UAAA,qBAAA;AACA,SAAA,uBAAA,aAAA;AACA,SAAA,aAAA;AACA,OAAA,aAAA;AACA,YAAA,YAAA;AACA,SAAA,6BAAA;AACA,SAAA,cAAA;AAEA,IAAA,2BAAA,SAAA,MAAA;AACA,QAAA,EAAA,MAAA,IAAA,sBAAA;AACA,QAAA,CAAA,IAAA,IAAA,OAAA,EAAA,MAAA,EAAA,MAAA,CAAA;AACA,MAAA,CAAA,KAAA,QAAA,cAAA;AAEA,QAAA,UAAA,KAAA,QAAA,IAAA;AACA,QAAA,SAAA,OAAA,EAAA,OAAA,OAAA,CAAA;AAEA,WAAA,cAAA;AACA,WAAA,CACM,QAAA,MAAa,MAAA;EAEnB;AAEA,WAAA,iBAAA;AACA,WAAA,CACM,QAAA,MAAa,MAAK,QAAO,QAAA;EAE/B;AAEA,QAAA,QAAA,OAAA,KAAA,WAAA,CAAA;AAEA,SAAA,EAAA,CACI,MAAA,OACE,SAAQ;IACV,aAAA;IACA,aAAA;EACA,GAAA,EAAA,CAEA,MAAA,MAAW,MAAK,QAAO,QAAA,EAAA;AAE3B,CAAA;AAEA,MAAA,UAAA,SAAA,CAAA,EAAA,MAAA,OAAA,MAAA;;;;;;AACA,QAAA,YAAA,EAAA;AACA,QAAA,EAAA,OAAA,IAAA,SAAA;AACA,QAAA,gBAAA,OAAA,MAAA,IAAA,MAAA,OAAA;AACA,QAAA,oBAAA,cAAA,uBAAA,gBAAA,EAAA,SAAA,CAAA,QAAA,EAAA,IAAA,CAAA,CAAA;AAEA,SAAA,EAAA,CACI,IAAA,IAAA,OAAA,SAAA,KAA4B,IACvB,CAAA,WAAA,IAAA,IAAA,CACD,IAAA,MAAA,QAAmB,UAAA,EAAnB,OAAmB,MAClB,CAAA,KAAA,YAAA,IAAA,IAAA,CACD,IAAA,MAAA,QAAmB,QAAA,EAAnB,OAAmB,MAClB,KAAA,WAAA,MAAA,OAAA,UAAA,CACD,IAAA,WAAA,CAAA,iBAAG,GAAA,KAAA,CAEH,OACE,QAAA,OACA,MAAK,OACL,SAAQ,MAAA,UAAA,IAAA,IAAA,IAEL,SACC,qBAEA,OAAA,EARN,QAQM,EAhBV,IAgBU,CACV,MACE,MAAA,mBACA,UAAS,WAAA,CAET,KACE,QAAO,mBACP,QAAO,MAAA,EAAA,EANX,MAMW;AAMf,CAAA;AAEA,SAAA,WAAA,MAAA;AACA,UAAA,KAAA,MAAA,IAAA,KAAA,IAAA,KAAA,MAAA,KAAA,QAAA,IAAA,KAAA,IAAA,KAAA,MAAA,KAAA,UAAA,IAAA,KAAA,IAAA,KAAA;AACA;AAEA,SAAA,gBAAA;AACA,SAAA,CACI,QAAA,QAAA,CACE,MAAA,QAAA,QAAA,CACE,KACI;;;;yEAIC,EALL,KAKK,EANP,MAMO,EAPT;AASJ;", + "mappings": ";AAEA,SAAA,OAAA,MAAA,OAAA,SAAA,QAAA,MAAA,KAAA,KAAA,UAAA,qBAAA;AACA,SAAA,uBAAA,aAAA;AACA,SAAA,aAAA;AACA,OAAA,aAAA;AACA,YAAA,YAAA;AACA,SAAA,6BAAA;AACA,SAAA,cAAA;AAEA,IAAA,2BAAA,SAAA,MAAA;AACA,QAAA,EAAA,MAAA,IAAA,sBAAA;AACA,QAAA,CAAA,IAAA,IAAA,OAAA,EAAA,MAAA,EAAA,MAAA,CAAA;AACA,MAAA,CAAA,KAAA,QAAA,cAAA;AAEA,QAAA,UAAA,KAAA,QAAA,IAAA;AACA,QAAA,SAAA,OAAA,EAAA,OAAA,OAAA,CAAA;AAEA,WAAA,cAAA;AACA,WAAA,CACM,QAAA,MAAQ,MAAA;EAEd;AAEA,WAAA,iBAAA;AACA,WAAA,CACM,QAAA,MAAQ,MAAU,QAAA,QAAA;EAExB;AAEA,QAAA,QAAA,OAAA,KAAA,WAAA,CAAA;AAEA,SAAA,EAAA,CACI,MAAA,OACE,SAAQ;IACV,aAAA;IACA,aAAA;EACA,GAAA,EAAA,CAEA,MAAA,MAAM,MAAU,QAAA,QAAA,EAAA;AAEpB,CAAA;AAEA,MAAA,UAAA,SAAA,CAAA,EAAA,MAAA,OAAA,MAAA;;;;;;AACA,QAAA,YAAA,EAAA;AACA,QAAA,EAAA,OAAA,IAAA,SAAA;AACA,QAAA,gBAAA,OAAA,MAAA,IAAA,MAAA,OAAA;AACA,QAAA,oBAAA,cAAA,uBAAA,gBAAA,EAAA,SAAA,CAAA,QAAA,EAAA,IAAA,CAAA,CAAA;AAEA,SAAA,EAAA,CACI,IAAA,IAAA,OAAA,SAAA,KAA4B,IACvB,CAAA,WAAA,IAAA,IAAA,CACD,IAAA,MAAA,QAAmB,UAAA,EAAnB,OAAmB,MAClB,CAAA,KAAA,YAAA,IAAA,IAAA,CACD,IAAA,MAAA,QAAmB,QAAA,EAAnB,OAAmB,MAClB,KAAA,WAAA,MAAA,OAAA,UAAA,CACD,IAAA,WAAA,CAAA,iBAAG,GAAA,KAAA,CAEH,OACE,QAAA,OACA,MAAK,OACL,SAAQ,MAAA,UAAA,IAAA,IAAA,IAEL,SACC,qBAEA,OAAA,EARN,QAQM,EAhBV,IAgBU,CACV,MACE,MAAA,mBACA,UAAS,WAAA,CAET,KACE,QAAO,mBACP,QAAO,MAAA,EAAA,EANX,MAMW;AAMf,CAAA;AAEA,SAAA,WAAA,MAAA;AACA,UAAA,KAAA,MAAA,IAAA,KAAA,IAAA,KAAA,MAAA,KAAA,QAAA,IAAA,KAAA,IAAA,KAAA,MAAA,KAAA,UAAA,IAAA,KAAA,IAAA,KAAA;AACA;AAEA,SAAA,gBAAA;AACA,SAAA,CACI,QAAA,QAAA,CACE,MAAA,QAAA,QAAA,CACE,KACI;;;;yEAIC,EALL,KAKK,EANP,MAMO,EAPT;AASJ;", "names": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/esbuild/event-tabs-breed.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/esbuild/event-tabs-breed.js.output.sourcemap.json index 22d034f..4f8df52 100644 --- a/test/fixtures/real-project/snapshots/esbuild/event-tabs-breed.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/esbuild/event-tabs-breed.js.output.sourcemap.json @@ -6,6 +6,6 @@ "sourcesContent": [ "import React, { useState } from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport {\n Link, Item, ScrollView, Form, useFormProps, Alert,\n Content, Tag, Br, Button, Modal, Div, confirm,\n useFormFields$, useValidate\n} from 'startupjs-ui'\nimport { useGlobalSearchParams } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faLink } from '@fortawesome/free-solid-svg-icons/faLink'\nimport CatCard from '@/components/CatCard'\nimport { CAT_FORM } from '@/model/cats/schema'\n\nexport default observer(({ breed }) => {\n const { eventId } = useGlobalSearchParams()\n const [$selected, set$selected] = useState()\n const $new = $()\n const $showModal = $()\n const $mode = $()\n const $fields = useFormFields$(CAT_FORM)\n const validate = useValidate()\n\n function showCreate () {\n $new.set({ breed })\n $fields.breed.disabled.set(true)\n set$selected(() => $new)\n $mode.set('new')\n $showModal.set(true)\n }\n\n function showEdit ($cat) {\n $fields.breed.disabled.del()\n set$selected(() => $cat)\n $mode.set('edit')\n $showModal.set(true)\n }\n\n function cancel () {\n if (!$showModal.get()) return\n $showModal.del()\n $mode.del()\n }\n\n async function create () {\n if (!validate()) return\n await $.cats.addNew({\n ...$new.getDeepCopy(),\n eventId\n })\n cancel()\n }\n\n async function deleteCat () {\n if (!await confirm(`Are you sure you want to delete ${$selected.name.get()}?`)) return\n await $selected.del()\n cancel()\n }\n\n return pug`\n ScrollView(full)\n Content(full pure)\n CatsList(eventId=eventId onEdit=showEdit breed=breed)\n Content(padding=1)\n Button(onPress=showCreate) Add new #{breed}\n Modal(\n title=$mode.get() === 'new' ? 'Create cat' : 'Edit cat'\n $visible=$showModal\n onDismiss=cancel\n )\n - const oppositeBreed = $selected?.breed.get() && ($selected.breed.get() === 'domestic' ? 'wild' : 'domestic')\n Form(\n key=$selected?.getId() || 'NEW'\n $fields=$fields\n $value=$selected\n oppositeBreed=oppositeBreed\n eventId=eventId\n customInputs={\n likes: SelectLikesInput\n }\n validate=validate\n )\n Br\n if $mode.get() === 'new'\n Div(align='right' row)\n Button(onPress=cancel) Cancel\n Button(disabled=validate.hasErrors pushed variant='flat' color='primary' onPress=create) Create\n else if $mode.get() === 'edit'\n Div(align='right' row)\n Button(color='error' onPress=deleteCat) Delete\n `\n})\n\nconst CatsList = observer(({ onEdit, breed, eventId }) => {\n if (!eventId) return pug`Alert(variant='error') No event specified`\n const $cats = useSub($.cats, { eventId, breed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n Item(key=$cat.getId())\n CatCard($cat=$cat)\n Item.Right\n Div(vAlign='center' row gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n Button(variant='text' icon=faPen onPress=() => onEdit($cat) tooltip='Edit')\n Link(href='/events/' + eventId + '/matches/' + $cat.getId())\n Button(variant='text' icon=faHeart tooltip='Matches')\n Link(href='/cats/' + $cat.token.get())\n Button(variant='text' icon=faLink tooltip='Cat profile link') Link\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nconst SelectLikesInput = observer(({ $value, ...props }) => {\n const { oppositeBreed, eventId } = { ...useFormProps(), ...props }\n return pug`\n if oppositeBreed\n SelectLikes(\n $likes=$value\n oppositeBreed=oppositeBreed\n eventId=eventId\n )\n else\n Alert(variant='warning') Select breed to choose likes\n `\n})\n\nconst SelectLikes = observer(({ $likes, oppositeBreed, eventId }) => {\n const $cats = useSub($.cats, { eventId, breed: oppositeBreed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n - const catId = $cat.getId()\n Item.item(\n key=catId\n styleName={ selected: $likes[catId].get() }\n onPress=() => $likes[catId].get() ? $likes[catId].del() : $likes[catId].set(true)\n )\n CatCard($cat=$cat small)\n else\n Alert(variant='info') No cats with selected breed yet\n style(lang='styl')\n .item\n border-radius 1u\n &.selected\n // FIXME: We can't use color var(--color-text-success-strong) here\n background-color var(--color-text-success-strong)\n `\n})\n" ], - "mappings": "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", + "mappings": "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", "names": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/esbuild/event-tabs-breed.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/esbuild/event-tabs-breed.tsx.output.sourcemap.json index cadcd5d..ec02d67 100644 --- a/test/fixtures/real-project/snapshots/esbuild/event-tabs-breed.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/esbuild/event-tabs-breed.tsx.output.sourcemap.json @@ -6,6 +6,6 @@ "sourcesContent": [ "import React, { useState } from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport {\n Link, Item, ScrollView, Form, useFormProps, Alert,\n Content, Tag, Br, Button, Modal, Div, confirm,\n useFormFields$, useValidate\n} from 'startupjs-ui'\nimport { useGlobalSearchParams } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faLink } from '@fortawesome/free-solid-svg-icons/faLink'\nimport CatCard from '@/components/CatCard'\nimport { CAT_FORM } from '@/model/cats/schema'\n\nexport default observer(({ breed }) => {\n const { eventId } = useGlobalSearchParams()\n const [$selected, set$selected] = useState()\n const $new = $()\n const $showModal = $()\n const $mode = $()\n const $fields = useFormFields$(CAT_FORM)\n const validate = useValidate()\n\n function showCreate () {\n $new.set({ breed })\n $fields.breed.disabled.set(true)\n set$selected(() => $new)\n $mode.set('new')\n $showModal.set(true)\n }\n\n function showEdit ($cat) {\n $fields.breed.disabled.del()\n set$selected(() => $cat)\n $mode.set('edit')\n $showModal.set(true)\n }\n\n function cancel () {\n if (!$showModal.get()) return\n $showModal.del()\n $mode.del()\n }\n\n async function create () {\n if (!validate()) return\n await $.cats.addNew({\n ...$new.getDeepCopy(),\n eventId\n })\n cancel()\n }\n\n async function deleteCat () {\n if (!await confirm(`Are you sure you want to delete ${$selected.name.get()}?`)) return\n await $selected.del()\n cancel()\n }\n\n return pug`\n ScrollView(full)\n Content(full pure)\n CatsList(eventId=eventId onEdit=showEdit breed=breed)\n Content(padding=1)\n Button(onPress=showCreate) Add new #{breed}\n Modal(\n title=$mode.get() === 'new' ? 'Create cat' : 'Edit cat'\n $visible=$showModal\n onDismiss=cancel\n )\n - const oppositeBreed = $selected?.breed.get() && ($selected.breed.get() === 'domestic' ? 'wild' : 'domestic')\n Form(\n key=$selected?.getId() || 'NEW'\n $fields=$fields\n $value=$selected\n oppositeBreed=oppositeBreed\n eventId=eventId\n customInputs={\n likes: SelectLikesInput\n }\n validate=validate\n )\n Br\n if $mode.get() === 'new'\n Div(align='right' row)\n Button(onPress=cancel) Cancel\n Button(disabled=validate.hasErrors pushed variant='flat' color='primary' onPress=create) Create\n else if $mode.get() === 'edit'\n Div(align='right' row)\n Button(color='error' onPress=deleteCat) Delete\n `\n})\n\nconst CatsList = observer(({ onEdit, breed, eventId }) => {\n if (!eventId) return pug`Alert(variant='error') No event specified`\n const $cats = useSub($.cats, { eventId, breed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n Item(key=$cat.getId())\n CatCard($cat=$cat)\n Item.Right\n Div(vAlign='center' row gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n Button(variant='text' icon=faPen onPress=() => onEdit($cat) tooltip='Edit')\n Link(href='/events/' + eventId + '/matches/' + $cat.getId())\n Button(variant='text' icon=faHeart tooltip='Matches')\n Link(href='/cats/' + $cat.token.get())\n Button(variant='text' icon=faLink tooltip='Cat profile link') Link\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nconst SelectLikesInput = observer(({ $value, ...props }) => {\n const { oppositeBreed, eventId } = { ...useFormProps(), ...props }\n return pug`\n if oppositeBreed\n SelectLikes(\n $likes=$value\n oppositeBreed=oppositeBreed\n eventId=eventId\n )\n else\n Alert(variant='warning') Select breed to choose likes\n `\n})\n\nconst SelectLikes = observer(({ $likes, oppositeBreed, eventId }) => {\n const $cats = useSub($.cats, { eventId, breed: oppositeBreed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n - const catId = $cat.getId()\n Item.item(\n key=catId\n styleName={ selected: $likes[catId].get() }\n onPress=() => $likes[catId].get() ? $likes[catId].del() : $likes[catId].set(true)\n )\n CatCard($cat=$cat small)\n else\n Alert(variant='info') No cats with selected breed yet\n style(lang='styl')\n .item\n border-radius 1u\n &.selected\n // FIXME: We can't use color var(--color-text-success-strong) here\n background-color var(--color-text-success-strong)\n `\n})\n" ], - "mappings": "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", + "mappings": "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", "names": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/esbuild/event-tabs-layout.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/esbuild/event-tabs-layout.js.output.sourcemap.json index c770eb4..58b60b7 100644 --- a/test/fixtures/real-project/snapshots/esbuild/event-tabs-layout.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/esbuild/event-tabs-layout.js.output.sourcemap.json @@ -6,6 +6,6 @@ "sourcesContent": [ "// import { Platform } from 'react-native'\nimport React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { useColors, Icon, Form, Modal, Button } from 'startupjs-ui'\nimport { Tabs, useLocalSearchParams, Stack } from 'expo-router'\nimport { faVenus as faWildBadge } from '@fortawesome/free-solid-svg-icons/faVenus'\nimport { faMars as faDomesticBadge } from '@fortawesome/free-solid-svg-icons/faMars'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faToolbox } from '@fortawesome/free-solid-svg-icons/faToolbox'\nimport { EVENT_FORM } from '@/model/events/schema'\n\nexport default observer(function TabLayout () {\n const getColor = useColors()\n const { eventId } = useLocalSearchParams()\n const $event = useSub($.events[eventId])\n if (!$event.get()) throw Error('No such event')\n\n // NOTE:\n // headerShown -- Disable the static render of the header on web to prevent a hydration error in React Navigation v6.\n // tabBarStyle/order - Move the tab bar to the top on tablet+\n return pug`\n Stack.Screen(\n options={\n title: $event.name.get(),\n headerRight: () => renderEditEvent({ $event })\n }\n )\n Tabs(\n title=$event.name.get()\n screenOptions={\n ...styl('screen'),\n tabBarActiveTintColor: getColor('primary'),\n tabBarActiveBackgroundColor: 'rgba(255, 255, 255, 0.5)',\n headerShown: false,\n headerTitle: $event.name.get()\n }\n )\n Tabs.Screen(\n name='index'\n options={\n title: 'Dashboard',\n tabBarIcon: renderHomeIcon\n }\n )\n Tabs.Screen(\n name='-breed'\n options={\n href: null\n }\n )\n Tabs.Screen(\n name='domestic'\n options={\n title: 'Domestic Cats',\n tabBarIcon: renderDomesticIcon\n }\n )\n Tabs.Screen(\n name='wild'\n options={\n title: 'Wild Cats',\n tabBarIcon: renderWildIcon\n }\n )\n Tabs.Screen(\n name='test'\n options={\n title: 'Dev Only',\n tabBarIcon: renderTestIcon\n }\n )\n style(lang='styl')\n +tablet()\n .screen\n &:part(tabBar)\n order -1\n background-color transparent\n border-bottom-width 1px\n border-bottom-color rgba(0, 0, 0, 0.1)\n `\n})\n\nfunction renderEditEvent ({ $event }) {\n return pug`\n EditEvent($event=$event)\n `\n}\n\nconst EditEvent = observer(({ $event }) => {\n const $showModal = $()\n return pug`\n Button(onPress=() => $showModal.set(true) variant='text' icon=faPen) Edit this cat meetup\n Modal(\n title='Edit cat meetup'\n $visible=$showModal\n )\n Form(\n $value=$event\n fields=EVENT_FORM\n )\n `\n})\n\nfunction renderWildIcon ({ color, size }) {\n return pug`\n Icon(icon=faWildBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderDomesticIcon ({ color, size }) {\n return pug`\n Icon(icon=faDomesticBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderHomeIcon ({ color, size }) {\n return pug`\n Icon(icon=faHeart style={ color, width: size, height: size })\n `\n}\n\nfunction renderTestIcon ({ color, size }) {\n return pug`\n Icon(icon=faToolbox style={ color, width: size, height: size })\n `\n}\n" ], - "mappings": "AACA,OAAA,WAAA;;AAEA,SAAA,WAAA,MAAA,MAAA,OAAA,cAAA;AACA,SAAA,MAAA,sBAAA,aAAA;AACA,SAAA,WAAA,mBAAA;AACA,SAAA,UAAA,uBAAA;AACA,SAAA,eAAA;AACA,SAAA,aAAA;AACA,SAAA,iBAAA;AACA,SAAA,kBAAA;AAEA,IAAA,4BAAA,SAAA,SAAA,YAAA;;;;;;;;;;;AACA,QAAA,WAAA,UAAA;AACA,QAAA,EAAA,QAAA,IAAA,qBAAA;AACA,QAAA,SAAA,OAAA,EAAA,OAAA,OAAA,CAAA;AACA,MAAA,CAAA,OAAA,IAAA,EAAA,OAAA,MAAA,eAAA;AAKA,SAAA,EAAA,CACI,MAAA,OACE,SAAQ;IACV,OAAA,OAAA,KAAA,IAAA;IACA,aAAA,MAAA,gBAAA,EAAA,OAAA,CAAA;EACA,GAAA,EAAA,CAEA,KACE,OAAM,OAAA,KAAA,IAAA,GACN,eAAc;IAChB,GAAA,KAAA,QAAA;IACA,uBAAA,SAAA,SAAA;IACA,6BAAA;IACA,aAAA;IACA,aAAA,OAAA,KAAA,IAAA;EACA,GAAA,CAEE,KAAA,OACE,KAAA,QACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,SACA,SAAQ;IACZ,MAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,WACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,OACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,OACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,EA1CA,KA0CA;AAWJ,CAAA;AAEA,SAAA,gBAAA,EAAA,OAAA,GAAA;AACA,SAAA,CACI,UAAA,QAAiB,QAAA;AAErB;AAEA,MAAA,YAAA,SAAA,CAAA,EAAA,OAAA,MAAA;AACA,QAAA,aAAA,EAAA;AACA,SAAA,EAAA,CACI,OAAA,SAAe,MAAA,WAAA,IAAA,IAAA,GAA2B,QAAA,OAAA,MAAoB,OAAO,oBAAA,EAArE,OAAqE,CACrE,MACE,MAAA,kBACA,UAAS,YAAA,CAET,KACE,QAAO,QACP,QAAO,YAAA,EAAA,EANX,MAMW;AAGf,CAAA;AAEA,SAAA,eAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,aAAY,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAEhC;AAEA,SAAA,mBAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,iBAAgB,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAEpC;AAEA,SAAA,eAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,SAAQ,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAE5B;AAEA,SAAA,eAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,WAAU,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAE9B;", + "mappings": "AACA,OAAA,WAAA;;AAEA,SAAA,WAAA,MAAA,MAAA,OAAA,cAAA;AACA,SAAA,MAAA,sBAAA,aAAA;AACA,SAAA,WAAA,mBAAA;AACA,SAAA,UAAA,uBAAA;AACA,SAAA,eAAA;AACA,SAAA,aAAA;AACA,SAAA,iBAAA;AACA,SAAA,kBAAA;AAEA,IAAA,4BAAA,SAAA,SAAA,YAAA;;;;;;;;;;;AACA,QAAA,WAAA,UAAA;AACA,QAAA,EAAA,QAAA,IAAA,qBAAA;AACA,QAAA,SAAA,OAAA,EAAA,OAAA,OAAA,CAAA;AACA,MAAA,CAAA,OAAA,IAAA,EAAA,OAAA,MAAA,eAAA;AAKA,SAAA,EAAA,CACI,MAAA,OACE,SAAQ;IACV,OAAA,OAAA,KAAA,IAAA;IACA,aAAA,MAAA,gBAAA,EAAA,OAAA,CAAA;EACA,GAAA,EAAA,CAEA,KACE,OAAM,OAAA,KAAA,IAAA,GACN,eAAc;IAChB,GAAA,KAAA,QAAA;IACA,uBAAA,SAAA,SAAA;IACA,6BAAA;IACA,aAAA;IACA,aAAA,OAAA,KAAA,IAAA;EACA,GAAA,CAEE,KAAA,OACE,KAAA,QACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,SACA,SAAQ;IACZ,MAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,WACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,OACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,OACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,EA1CA,KA0CA;AAWJ,CAAA;AAEA,SAAA,gBAAA,EAAA,OAAA,GAAA;AACA,SAAA,CACI,UAAA,QAAU,QAAA;AAEd;AAEA,MAAA,YAAA,SAAA,CAAA,EAAA,OAAA,MAAA;AACA,QAAA,aAAA,EAAA;AACA,SAAA,EAAA,CACI,OAAA,SAAe,MAAA,WAAA,IAAA,IAAA,GAA2B,QAAA,OAAA,MAAoB,OAAO,oBAAA,EAArE,OAAqE,CACrE,MACE,MAAA,kBACA,UAAS,YAAA,CAET,KACE,QAAO,QACP,QAAO,YAAA,EAAA,EANX,MAMW;AAGf,CAAA;AAEA,SAAA,eAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,aAAY,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAEhC;AAEA,SAAA,mBAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,iBAAgB,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAEpC;AAEA,SAAA,eAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,SAAQ,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAE5B;AAEA,SAAA,eAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,WAAU,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAE9B;", "names": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/esbuild/event-tabs-layout.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/esbuild/event-tabs-layout.tsx.output.sourcemap.json index b017ad1..52273f2 100644 --- a/test/fixtures/real-project/snapshots/esbuild/event-tabs-layout.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/esbuild/event-tabs-layout.tsx.output.sourcemap.json @@ -6,6 +6,6 @@ "sourcesContent": [ "// import { Platform } from 'react-native'\nimport React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { useColors, Icon, Form, Modal, Button } from 'startupjs-ui'\nimport { Tabs, useLocalSearchParams, Stack } from 'expo-router'\nimport { faVenus as faWildBadge } from '@fortawesome/free-solid-svg-icons/faVenus'\nimport { faMars as faDomesticBadge } from '@fortawesome/free-solid-svg-icons/faMars'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faToolbox } from '@fortawesome/free-solid-svg-icons/faToolbox'\nimport { EVENT_FORM } from '@/model/events/schema'\n\nexport default observer(function TabLayout () {\n const getColor = useColors()\n const { eventId } = useLocalSearchParams()\n const $event = useSub($.events[eventId])\n if (!$event.get()) throw Error('No such event')\n\n // NOTE:\n // headerShown -- Disable the static render of the header on web to prevent a hydration error in React Navigation v6.\n // tabBarStyle/order - Move the tab bar to the top on tablet+\n return pug`\n Stack.Screen(\n options={\n title: $event.name.get(),\n headerRight: () => renderEditEvent({ $event })\n }\n )\n Tabs(\n title=$event.name.get()\n screenOptions={\n ...styl('screen'),\n tabBarActiveTintColor: getColor('primary'),\n tabBarActiveBackgroundColor: 'rgba(255, 255, 255, 0.5)',\n headerShown: false,\n headerTitle: $event.name.get()\n }\n )\n Tabs.Screen(\n name='index'\n options={\n title: 'Dashboard',\n tabBarIcon: renderHomeIcon\n }\n )\n Tabs.Screen(\n name='-breed'\n options={\n href: null\n }\n )\n Tabs.Screen(\n name='domestic'\n options={\n title: 'Domestic Cats',\n tabBarIcon: renderDomesticIcon\n }\n )\n Tabs.Screen(\n name='wild'\n options={\n title: 'Wild Cats',\n tabBarIcon: renderWildIcon\n }\n )\n Tabs.Screen(\n name='test'\n options={\n title: 'Dev Only',\n tabBarIcon: renderTestIcon\n }\n )\n style(lang='styl')\n +tablet()\n .screen\n &:part(tabBar)\n order -1\n background-color transparent\n border-bottom-width 1px\n border-bottom-color rgba(0, 0, 0, 0.1)\n `\n})\n\nfunction renderEditEvent ({ $event }) {\n return pug`\n EditEvent($event=$event)\n `\n}\n\nconst EditEvent = observer(({ $event }) => {\n const $showModal = $()\n return pug`\n Button(onPress=() => $showModal.set(true) variant='text' icon=faPen) Edit this cat meetup\n Modal(\n title='Edit cat meetup'\n $visible=$showModal\n )\n Form(\n $value=$event\n fields=EVENT_FORM\n )\n `\n})\n\nfunction renderWildIcon ({ color, size }) {\n return pug`\n Icon(icon=faWildBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderDomesticIcon ({ color, size }) {\n return pug`\n Icon(icon=faDomesticBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderHomeIcon ({ color, size }) {\n return pug`\n Icon(icon=faHeart style={ color, width: size, height: size })\n `\n}\n\nfunction renderTestIcon ({ color, size }) {\n return pug`\n Icon(icon=faToolbox style={ color, width: size, height: size })\n `\n}\n" ], - "mappings": ";AAGA,SAAA,WAAA,MAAA,MAAA,OAAA,cAAA;AACA,SAAA,MAAA,sBAAA,aAAA;AACA,SAAA,WAAA,mBAAA;AACA,SAAA,UAAA,uBAAA;AACA,SAAA,eAAA;AACA,SAAA,aAAA;AACA,SAAA,iBAAA;AACA,SAAA,kBAAA;AAEA,IAAA,4BAAA,SAAA,SAAA,YAAA;;;;;;;;;;;AACA,QAAA,WAAA,UAAA;AACA,QAAA,EAAA,QAAA,IAAA,qBAAA;AACA,QAAA,SAAA,OAAA,EAAA,OAAA,OAAA,CAAA;AACA,MAAA,CAAA,OAAA,IAAA,EAAA,OAAA,MAAA,eAAA;AAKA,SAAA,EAAA,CACI,MAAA,OACE,SAAQ;IACV,OAAA,OAAA,KAAA,IAAA;IACA,aAAA,MAAA,gBAAA,EAAA,OAAA,CAAA;EACA,GAAA,EAAA,CAEA,KACE,OAAM,OAAA,KAAA,IAAA,GACN,eAAc;IAChB,GAAA,KAAA,QAAA;IACA,uBAAA,SAAA,SAAA;IACA,6BAAA;IACA,aAAA;IACA,aAAA,OAAA,KAAA,IAAA;EACA,GAAA,CAEE,KAAA,OACE,KAAA,QACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,SACA,SAAQ;IACZ,MAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,WACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,OACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,OACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,EA1CA,KA0CA;AAWJ,CAAA;AAEA,SAAA,gBAAA,EAAA,OAAA,GAAA;AACA,SAAA,CACI,UAAA,QAAiB,QAAA;AAErB;AAEA,MAAA,YAAA,SAAA,CAAA,EAAA,OAAA,MAAA;AACA,QAAA,aAAA,EAAA;AACA,SAAA,EAAA,CACI,OAAA,SAAe,MAAA,WAAA,IAAA,IAAA,GAA2B,QAAA,OAAA,MAAoB,OAAO,oBAAA,EAArE,OAAqE,CACrE,MACE,MAAA,kBACA,UAAS,YAAA,CAET,KACE,QAAO,QACP,QAAO,YAAA,EAAA,EANX,MAMW;AAGf,CAAA;AAEA,SAAA,eAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,aAAY,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAEhC;AAEA,SAAA,mBAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,iBAAgB,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAEpC;AAEA,SAAA,eAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,SAAQ,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAE5B;AAEA,SAAA,eAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,WAAU,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAE9B;", + "mappings": ";AAGA,SAAA,WAAA,MAAA,MAAA,OAAA,cAAA;AACA,SAAA,MAAA,sBAAA,aAAA;AACA,SAAA,WAAA,mBAAA;AACA,SAAA,UAAA,uBAAA;AACA,SAAA,eAAA;AACA,SAAA,aAAA;AACA,SAAA,iBAAA;AACA,SAAA,kBAAA;AAEA,IAAA,4BAAA,SAAA,SAAA,YAAA;;;;;;;;;;;AACA,QAAA,WAAA,UAAA;AACA,QAAA,EAAA,QAAA,IAAA,qBAAA;AACA,QAAA,SAAA,OAAA,EAAA,OAAA,OAAA,CAAA;AACA,MAAA,CAAA,OAAA,IAAA,EAAA,OAAA,MAAA,eAAA;AAKA,SAAA,EAAA,CACI,MAAA,OACE,SAAQ;IACV,OAAA,OAAA,KAAA,IAAA;IACA,aAAA,MAAA,gBAAA,EAAA,OAAA,CAAA;EACA,GAAA,EAAA,CAEA,KACE,OAAM,OAAA,KAAA,IAAA,GACN,eAAc;IAChB,GAAA,KAAA,QAAA;IACA,uBAAA,SAAA,SAAA;IACA,6BAAA;IACA,aAAA;IACA,aAAA,OAAA,KAAA,IAAA;EACA,GAAA,CAEE,KAAA,OACE,KAAA,QACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,SACA,SAAQ;IACZ,MAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,WACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,OACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,CAEE,KAAA,OACE,KAAA,OACA,SAAQ;IACZ,OAAA;IACA,YAAA;EACA,GAAA,EAAA,EA1CA,KA0CA;AAWJ,CAAA;AAEA,SAAA,gBAAA,EAAA,OAAA,GAAA;AACA,SAAA,CACI,UAAA,QAAU,QAAA;AAEd;AAEA,MAAA,YAAA,SAAA,CAAA,EAAA,OAAA,MAAA;AACA,QAAA,aAAA,EAAA;AACA,SAAA,EAAA,CACI,OAAA,SAAe,MAAA,WAAA,IAAA,IAAA,GAA2B,QAAA,OAAA,MAAoB,OAAO,oBAAA,EAArE,OAAqE,CACrE,MACE,MAAA,kBACA,UAAS,YAAA,CAET,KACE,QAAO,QACP,QAAO,YAAA,EAAA,EANX,MAMW;AAGf,CAAA;AAEA,SAAA,eAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,aAAY,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAEhC;AAEA,SAAA,mBAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,iBAAgB,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAEpC;AAEA,SAAA,eAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,SAAQ,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAE5B;AAEA,SAAA,eAAA,EAAA,OAAA,KAAA,GAAA;AACA,SAAA,CACI,KAAA,MAAU,WAAU,OAAM,EAAA,OAAA,OAAA,MAAA,QAAA,KAAA,GAAA;AAE9B;", "names": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.js.diagnostics.txt b/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.js.diagnostics.txt index 746119a..830a5f9 100644 --- a/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.js.diagnostics.txt +++ b/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.js.diagnostics.txt @@ -1,6 +1,6 @@ /Users/cray0000/ws/www/vscode-pug-react/test/fixtures/real-project/cat-profile-link.js 36:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent 37:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent - 39:1 error Expected indentation of 2 spaces but found 4. @stylistic/indent + 38:5 error Expected indentation of 2 spaces but found 4. @stylistic/indent Found 3 errors in 1 files. \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.tsx.diagnostics.txt b/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.tsx.diagnostics.txt index eeabf30..7a572c1 100644 --- a/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.tsx.diagnostics.txt +++ b/test/fixtures/real-project/snapshots/eslint-neostandard/cat-profile-link.tsx.diagnostics.txt @@ -1,6 +1,6 @@ /Users/cray0000/ws/www/vscode-pug-react/test/fixtures/real-project/cat-profile-link.tsx 36:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent 37:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent - 39:1 error Expected indentation of 2 spaces but found 4. @stylistic/indent + 38:5 error Expected indentation of 2 spaces but found 4. @stylistic/indent Found 3 errors in 1 files. \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.js.diagnostics.txt b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.js.diagnostics.txt index 1712a76..fb0dad5 100644 --- a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.js.diagnostics.txt +++ b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.js.diagnostics.txt @@ -1,5 +1,5 @@ /Users/cray0000/ws/www/vscode-pug-react/test/fixtures/real-project/event-tabs-breed.js - 79:21 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 81:15 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 79:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 80:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent Found 2 errors in 1 files. \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.tsx.diagnostics.txt b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.tsx.diagnostics.txt index f13f70f..b2df798 100644 --- a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.tsx.diagnostics.txt +++ b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-breed.tsx.diagnostics.txt @@ -1,5 +1,5 @@ /Users/cray0000/ws/www/vscode-pug-react/test/fixtures/real-project/event-tabs-breed.tsx - 79:21 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 81:15 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 79:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 80:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent Found 2 errors in 1 files. \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.js.diagnostics.txt b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.js.diagnostics.txt index e1ac88d..3567ea5 100644 --- a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.js.diagnostics.txt +++ b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.js.diagnostics.txt @@ -1,26 +1,26 @@ /Users/cray0000/ws/www/vscode-pug-react/test/fixtures/real-project/event-tabs-layout.js 25:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent 26:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent - 28:5 error Expected indentation of 2 spaces but found 4. @stylistic/indent + 27:5 error Expected indentation of 2 spaces but found 4. @stylistic/indent 32:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent - 33:1 error Expected indentation of 4 spaces but found 6. @stylistic/indent - 34:1 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 33:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 34:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent 35:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent - 36:13 error Expected indentation of 4 spaces but found 6. @stylistic/indent - 39:3 error Expected indentation of 2 spaces but found 4. @stylistic/indent - 42:16 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 43:20 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 46:13 error Expected indentation of 2 spaces but found 6. @stylistic/indent - 50:2 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 52:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent - 55:26 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 56:30 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 60:4 error Expected indentation of 2 spaces but found 6. @stylistic/indent - 63:6 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 64:7 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 67:11 error Expected indentation of 2 spaces but found 6. @stylistic/indent - 70:3 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 70:32 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 72:7 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 36:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 37:5 error Expected indentation of 2 spaces but found 4. @stylistic/indent + 42:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 43:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 44:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 49:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 50:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 55:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 56:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 57:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 62:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 63:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 64:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 69:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 70:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 71:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent Found 23 errors in 1 files. \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.tsx.diagnostics.txt b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.tsx.diagnostics.txt index e12013a..ebb9f75 100644 --- a/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.tsx.diagnostics.txt +++ b/test/fixtures/real-project/snapshots/eslint-neostandard/event-tabs-layout.tsx.diagnostics.txt @@ -1,26 +1,26 @@ /Users/cray0000/ws/www/vscode-pug-react/test/fixtures/real-project/event-tabs-layout.tsx 25:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent 26:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent - 28:5 error Expected indentation of 2 spaces but found 4. @stylistic/indent + 27:5 error Expected indentation of 2 spaces but found 4. @stylistic/indent 32:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent - 33:1 error Expected indentation of 4 spaces but found 6. @stylistic/indent - 34:1 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 33:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 34:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent 35:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent - 36:13 error Expected indentation of 4 spaces but found 6. @stylistic/indent - 39:3 error Expected indentation of 2 spaces but found 4. @stylistic/indent - 42:16 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 43:20 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 46:13 error Expected indentation of 2 spaces but found 6. @stylistic/indent - 50:2 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 52:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent - 55:26 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 56:30 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 60:4 error Expected indentation of 2 spaces but found 6. @stylistic/indent - 63:6 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 64:7 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 67:11 error Expected indentation of 2 spaces but found 6. @stylistic/indent - 70:3 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 70:32 error Expected indentation of 4 spaces but found 8. @stylistic/indent - 72:7 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 36:5 error Expected indentation of 4 spaces but found 6. @stylistic/indent + 37:5 error Expected indentation of 2 spaces but found 4. @stylistic/indent + 42:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 43:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 44:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 49:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 50:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 55:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 56:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 57:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 62:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 63:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 64:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent + 69:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 70:5 error Expected indentation of 4 spaces but found 8. @stylistic/indent + 71:5 error Expected indentation of 2 spaces but found 6. @stylistic/indent Found 23 errors in 1 files. \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/shadow/CatCard.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/shadow/CatCard.js.output.sourcemap.json index 6970ef4..905ed35 100644 --- a/test/fixtures/real-project/snapshots/shadow/CatCard.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/shadow/CatCard.js.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport { Div, Span, Avatar, Link } from 'startupjs-ui'\n\nexport default observer(({ $cat, showPhone, large, small }) => {\n const { name, number, phone, catgram, photoFileId, phonegram } = $cat.get()\n return pug`\n Div(part='root' row vAlign='center')\n if photoFileId\n Photo.avatar(styleName={ large, small } fileId=photoFileId name=name)\n else\n Avatar.avatar(styleName={ large, small })= name\n Div(row)\n Span.text(bold styleName={ large })= (number || 'X') + '. '\n Div\n Span.text(styleName={ large })= name\n if showPhone\n if phone\n Span.text(styleName={ large })\n Span(bold) Phone:#{' '}\n = phone\n if catgram\n Span.text(styleName={ large })\n Span(bold) Catgram:#{' '}\n Link.text(styleName={ large } to=getCatgramLink(catgram))= catgram\n if phonegram\n Span.text(styleName={ large })\n Span(bold) Phonegram:#{' '}\n Link.text(styleName={ large } to=getPhonegramLink(phonegram))= phonegram\n style(lang='styl')\n .avatar\n margin-right 1u\n &.large\n width 12u\n height @width\n &.small\n width 4u\n height @width\n .text.large\n font(h6)\n `\n})\n\nconst Photo = observer(({ fileId, name }) => {\n const $file = useSub($.files[fileId])\n let url\n try { url = $file.getUrl() } catch (err) {}\n return pug`\n Avatar(part='root' src=url)= name\n `\n})\n\nfunction getCatgramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://catgr.am/' + username\n}\n\nfunction getPhonegramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://www.phonegram.com/' + username\n}\n" ], - "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;;IA0BM;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlCN;AACA,WACI,qCACK,eACD,MAAa,aAAR,SAAkB,mBAAiB,QAAO,aAAY,MAAK,YAEhE,OAAc,aAAR,SAAkB,oBAAmB,gBAC7C,SACE,KAAe,aAAX,OAAqB,YAAf,MAA2B,+BACrC,KACE,KAAU,aAAN,OAAgB,aAAY,aAC7B,eACE,SACD,KAAU,aAAN,OAAgB,aAClB,UAAW,OAAQ,YACjB,sBACH,WACD,KAAU,aAAN,OAAgB,aAClB,UAAW,SAAU,YACrB,KAAU,aAAN,OAAgB,YAAU,IAAG,0BAA0B,+BAC5D,aACD,KAAU,aAAN,OAAgB,aAClB,UAAW,WAAY,YACvB,KAAU,aAAN,OAAgB,YAAU,IAAG,8BAA8B,8DAY5E;AACH;AACA;AACA;AACA;AACA;AACA;AACA,WACI,wBAAuB,MAAM,eAC9B;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", + "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;;IA0BM;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlCN;AACA,WACI,qCACK,eACD,MAAa,aAAR,SAAkB,mBAAiB,QAAO,aAAY,MAAA,YAE3D,OAAc,aAAR,SAAkB,oBAAmB,gBAC7C,SACE,KAAe,aAAX,OAAqB,YAAf,MAA2B,+BACrC,KACE,KAAU,aAAN,OAAgB,aAAY,aAC7B,eACE,SACD,KAAU,aAAN,OAAgB,aAClB,UAAW,OAAQ,YACjB,sBACH,WACD,KAAU,aAAN,OAAgB,aAClB,UAAW,SAAU,YACrB,KAAU,aAAN,OAAgB,YAAU,IAAG,0BAA0B,+BAC5D,aACD,KAAU,aAAN,OAAgB,aAClB,UAAW,WAAY,YACvB,KAAU,aAAN,OAAgB,YAAU,IAAG,8BAA8B,8DAY5E;AACH;AACA;AACA;AACA;AACA;AACA;AACA,WACI,wBAAuB,MAAM,eAC9B;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/shadow/CatCard.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/shadow/CatCard.tsx.output.sourcemap.json index fd7dc9f..f4190df 100644 --- a/test/fixtures/real-project/snapshots/shadow/CatCard.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/shadow/CatCard.tsx.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport { Div, Span, Avatar, Link } from 'startupjs-ui'\n\nexport default observer(({ $cat, showPhone, large, small }) => {\n const { name, number, phone, catgram, photoFileId, phonegram } = $cat.get()\n return pug`\n Div(part='root' row vAlign='center')\n if photoFileId\n Photo.avatar(styleName={ large, small } fileId=photoFileId name=name)\n else\n Avatar.avatar(styleName={ large, small })= name\n Div(row)\n Span.text(bold styleName={ large })= (number || 'X') + '. '\n Div\n Span.text(styleName={ large })= name\n if showPhone\n if phone\n Span.text(styleName={ large })\n Span(bold) Phone:#{' '}\n = phone\n if catgram\n Span.text(styleName={ large })\n Span(bold) Catgram:#{' '}\n Link.text(styleName={ large } to=getCatgramLink(catgram))= catgram\n if phonegram\n Span.text(styleName={ large })\n Span(bold) Phonegram:#{' '}\n Link.text(styleName={ large } to=getPhonegramLink(phonegram))= phonegram\n style(lang='styl')\n .avatar\n margin-right 1u\n &.large\n width 12u\n height @width\n &.small\n width 4u\n height @width\n .text.large\n font(h6)\n `\n})\n\nconst Photo = observer(({ fileId, name }) => {\n const $file = useSub($.files[fileId])\n let url\n try { url = $file.getUrl() } catch (err) {}\n return pug`\n Avatar(part='root' src=url)= name\n `\n})\n\nfunction getCatgramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://catgr.am/' + username\n}\n\nfunction getPhonegramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://www.phonegram.com/' + username\n}\n" ], - "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;;IA0BM;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlCN;AACA,WACI,qCACK,eACD,MAAa,aAAR,SAAkB,mBAAiB,QAAO,aAAY,MAAK,YAEhE,OAAc,aAAR,SAAkB,oBAAmB,gBAC7C,SACE,KAAe,aAAX,OAAqB,YAAf,MAA2B,+BACrC,KACE,KAAU,aAAN,OAAgB,aAAY,aAC7B,eACE,SACD,KAAU,aAAN,OAAgB,aAClB,UAAW,OAAQ,YACjB,sBACH,WACD,KAAU,aAAN,OAAgB,aAClB,UAAW,SAAU,YACrB,KAAU,aAAN,OAAgB,YAAU,IAAG,0BAA0B,+BAC5D,aACD,KAAU,aAAN,OAAgB,aAClB,UAAW,WAAY,YACvB,KAAU,aAAN,OAAgB,YAAU,IAAG,8BAA8B,8DAY5E;AACH;AACA;AACA;AACA;AACA;AACA;AACA,WACI,wBAAuB,MAAM,eAC9B;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", + "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;;IA0BM;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlCN;AACA,WACI,qCACK,eACD,MAAa,aAAR,SAAkB,mBAAiB,QAAO,aAAY,MAAA,YAE3D,OAAc,aAAR,SAAkB,oBAAmB,gBAC7C,SACE,KAAe,aAAX,OAAqB,YAAf,MAA2B,+BACrC,KACE,KAAU,aAAN,OAAgB,aAAY,aAC7B,eACE,SACD,KAAU,aAAN,OAAgB,aAClB,UAAW,OAAQ,YACjB,sBACH,WACD,KAAU,aAAN,OAAgB,aAClB,UAAW,SAAU,YACrB,KAAU,aAAN,OAAgB,YAAU,IAAG,0BAA0B,+BAC5D,aACD,KAAU,aAAN,OAAgB,aAClB,UAAW,WAAY,YACvB,KAAU,aAAN,OAAgB,YAAU,IAAG,8BAA8B,8DAY5E;AACH;AACA;AACA;AACA;AACA;AACA;AACA,WACI,wBAAuB,MAAM,eAC9B;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/shadow/cat-profile-link.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/shadow/cat-profile-link.js.output.sourcemap.json index d014b54..e192b38 100644 --- a/test/fixtures/real-project/snapshots/shadow/cat-profile-link.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/shadow/cat-profile-link.js.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { Alert, Span, Modal, Content, Button, Form, Div, Tag, useMedia, useFormFields } from 'startupjs-ui'\nimport { useGlobalSearchParams, Stack } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport CatCard from '@/components/CatCard'\nimport * as stages from '@/components/stages'\nimport { CAT_PROFILE_EDIT_FORM } from '@/model/cats/schema'\nimport { STAGES } from '@/model/events/schema'\n\nexport default observer(() => {\n const { token } = useGlobalSearchParams()\n const [$cat] = useSub($.cats, { token })\n if (!$cat) return renderExpired()\n\n const eventId = $cat.eventId.get()\n const $event = useSub($.events[eventId])\n\n function renderTitle () {\n return pug`\n CatCard($cat=$cat)\n `\n }\n\n function renderSettings () {\n return pug`\n Profile($cat=$cat $event=$event)\n `\n }\n\n const Stage = stages[$cat.getMyStage()]\n\n return pug`\n Stack.Screen(\n options={\n headerTitle: renderTitle,\n headerRight: renderSettings\n }\n )\n Stage($cat=$cat $event=$event)\n `\n})\n\nconst Profile = observer(({ $cat, $event }) => {\n const $showEdit = $()\n const { tablet } = useMedia()\n const excludeNumber = $event.stage.get() !== STAGES.InProgress\n const profileEditFields = useFormFields(CAT_PROFILE_EDIT_FORM, excludeNumber ? { exclude: ['number'] } : {})\n\n return pug`\n Div(row vAlign='center' gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n if $cat.getMyStage() === STAGES.Profile\n Div.hackSidePadding\n else\n Button(\n variant='text'\n icon=faPen\n onPress=() => $showEdit.set(true)\n )\n if tablet\n = 'Edit cat profile'\n else\n = 'Edit'\n Modal(\n title='Edit cat profile'\n $visible=$showEdit\n )\n Form(\n fields=profileEditFields\n $value=$cat\n )\n style(lang='styl')\n .hackSidePadding\n width 1u\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nfunction renderExpired () {\n return pug`\n Content(padding)\n Alert(variant='error')\n Span\n | Cat profile link is incorrect or already expired.\n |\n | Your cat meetup profile link is only valid for a limited period of time.\n |\n | If you believe this is an error, please contact the cat meetup organizer.\n `\n}\n" ], - "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACM,cAAa,SACd;AACL;AACA;AACA;AACA,aACM,cAAa,MAAK,QAAO,WAC1B;AACL;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,YAAW,MAAK,QAAO,cACxB;AACH;AACA;AACA;;IAiCM;IACA;;;AAjCN;AACA;AACA;AACA;AACA;AACA,aACI,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBAClB,wCACD,iBAAG,yBAEH,OACE,eACA,MAAK,OACL,SAAQ,4BAEL,SACC,qBAEA,wBACV,MACE,yBACA,UAAS,YAET,KACE,QAAO,mBACP,QAAO,oBAKZ;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WACI,iBACE,uBACE,KACI;AACP;AACA,CAAQ;AACR;AACA,CAAQ,kGACV;AACH", + "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACM,cAAQ,SACT;AACL;AACA;AACA;AACA,aACM,cAAQ,MAAU,QAAA,WACnB;AACL;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,YAAM,MAAU,QAAA,cACjB;AACH;AACA;AACA;;IAiCM;IACA;;;AAjCN;AACA;AACA;AACA;AACA;AACA,aACI,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBAClB,wCACD,iBAAG,yBAEH,OACE,eACA,MAAK,OACL,SAAQ,4BAEL,SACC,qBAEA,wBACV,MACE,yBACA,UAAS,YAET,KACE,QAAO,mBACP,QAAO,oBAKZ;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WACI,iBACE,uBACE,KACI;AACP;AACA,CAAQ;AACR;AACA,CAAQ,kGACV;AACH", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/shadow/cat-profile-link.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/shadow/cat-profile-link.tsx.output.sourcemap.json index 2603a48..d7d36d9 100644 --- a/test/fixtures/real-project/snapshots/shadow/cat-profile-link.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/shadow/cat-profile-link.tsx.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { Alert, Span, Modal, Content, Button, Form, Div, Tag, useMedia, useFormFields } from 'startupjs-ui'\nimport { useGlobalSearchParams, Stack } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport CatCard from '@/components/CatCard'\nimport * as stages from '@/components/stages'\nimport { CAT_PROFILE_EDIT_FORM } from '@/model/cats/schema'\nimport { STAGES } from '@/model/events/schema'\n\nexport default observer(() => {\n const { token } = useGlobalSearchParams()\n const [$cat] = useSub($.cats, { token })\n if (!$cat) return renderExpired()\n\n const eventId = $cat.eventId.get()\n const $event = useSub($.events[eventId])\n\n function renderTitle () {\n return pug`\n CatCard($cat=$cat)\n `\n }\n\n function renderSettings () {\n return pug`\n Profile($cat=$cat $event=$event)\n `\n }\n\n const Stage = stages[$cat.getMyStage()]\n\n return pug`\n Stack.Screen(\n options={\n headerTitle: renderTitle,\n headerRight: renderSettings\n }\n )\n Stage($cat=$cat $event=$event)\n `\n})\n\nconst Profile = observer(({ $cat, $event }) => {\n const $showEdit = $()\n const { tablet } = useMedia()\n const excludeNumber = $event.stage.get() !== STAGES.InProgress\n const profileEditFields = useFormFields(CAT_PROFILE_EDIT_FORM, excludeNumber ? { exclude: ['number'] } : {})\n\n return pug`\n Div(row vAlign='center' gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n if $cat.getMyStage() === STAGES.Profile\n Div.hackSidePadding\n else\n Button(\n variant='text'\n icon=faPen\n onPress=() => $showEdit.set(true)\n )\n if tablet\n = 'Edit cat profile'\n else\n = 'Edit'\n Modal(\n title='Edit cat profile'\n $visible=$showEdit\n )\n Form(\n fields=profileEditFields\n $value=$cat\n )\n style(lang='styl')\n .hackSidePadding\n width 1u\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nfunction renderExpired () {\n return pug`\n Content(padding)\n Alert(variant='error')\n Span\n | Cat profile link is incorrect or already expired.\n |\n | Your cat meetup profile link is only valid for a limited period of time.\n |\n | If you believe this is an error, please contact the cat meetup organizer.\n `\n}\n" ], - "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACM,cAAa,SACd;AACL;AACA;AACA;AACA,aACM,cAAa,MAAK,QAAO,WAC1B;AACL;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,YAAW,MAAK,QAAO,cACxB;AACH;AACA;AACA;;IAiCM;IACA;;;AAjCN;AACA;AACA;AACA;AACA;AACA,aACI,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBAClB,wCACD,iBAAG,yBAEH,OACE,eACA,MAAK,OACL,SAAQ,4BAEL,SACC,qBAEA,wBACV,MACE,yBACA,UAAS,YAET,KACE,QAAO,mBACP,QAAO,oBAKZ;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WACI,iBACE,uBACE,KACI;AACP;AACA,CAAQ;AACR;AACA,CAAQ,kGACV;AACH", + "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACM,cAAQ,SACT;AACL;AACA;AACA;AACA,aACM,cAAQ,MAAU,QAAA,WACnB;AACL;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,YAAM,MAAU,QAAA,cACjB;AACH;AACA;AACA;;IAiCM;IACA;;;AAjCN;AACA;AACA;AACA;AACA;AACA,aACI,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBAClB,wCACD,iBAAG,yBAEH,OACE,eACA,MAAK,OACL,SAAQ,4BAEL,SACC,qBAEA,wBACV,MACE,yBACA,UAAS,YAET,KACE,QAAO,mBACP,QAAO,oBAKZ;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WACI,iBACE,uBACE,KACI;AACP;AACA,CAAQ;AACR;AACA,CAAQ,kGACV;AACH", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/shadow/event-tabs-breed.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/shadow/event-tabs-breed.js.output.sourcemap.json index ee09fba..9e26176 100644 --- a/test/fixtures/real-project/snapshots/shadow/event-tabs-breed.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/shadow/event-tabs-breed.js.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "import React, { useState } from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport {\n Link, Item, ScrollView, Form, useFormProps, Alert,\n Content, Tag, Br, Button, Modal, Div, confirm,\n useFormFields$, useValidate\n} from 'startupjs-ui'\nimport { useGlobalSearchParams } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faLink } from '@fortawesome/free-solid-svg-icons/faLink'\nimport CatCard from '@/components/CatCard'\nimport { CAT_FORM } from '@/model/cats/schema'\n\nexport default observer(({ breed }) => {\n const { eventId } = useGlobalSearchParams()\n const [$selected, set$selected] = useState()\n const $new = $()\n const $showModal = $()\n const $mode = $()\n const $fields = useFormFields$(CAT_FORM)\n const validate = useValidate()\n\n function showCreate () {\n $new.set({ breed })\n $fields.breed.disabled.set(true)\n set$selected(() => $new)\n $mode.set('new')\n $showModal.set(true)\n }\n\n function showEdit ($cat) {\n $fields.breed.disabled.del()\n set$selected(() => $cat)\n $mode.set('edit')\n $showModal.set(true)\n }\n\n function cancel () {\n if (!$showModal.get()) return\n $showModal.del()\n $mode.del()\n }\n\n async function create () {\n if (!validate()) return\n await $.cats.addNew({\n ...$new.getDeepCopy(),\n eventId\n })\n cancel()\n }\n\n async function deleteCat () {\n if (!await confirm(`Are you sure you want to delete ${$selected.name.get()}?`)) return\n await $selected.del()\n cancel()\n }\n\n return pug`\n ScrollView(full)\n Content(full pure)\n CatsList(eventId=eventId onEdit=showEdit breed=breed)\n Content(padding=1)\n Button(onPress=showCreate) Add new #{breed}\n Modal(\n title=$mode.get() === 'new' ? 'Create cat' : 'Edit cat'\n $visible=$showModal\n onDismiss=cancel\n )\n - const oppositeBreed = $selected?.breed.get() && ($selected.breed.get() === 'domestic' ? 'wild' : 'domestic')\n Form(\n key=$selected?.getId() || 'NEW'\n $fields=$fields\n $value=$selected\n oppositeBreed=oppositeBreed\n eventId=eventId\n customInputs={\n likes: SelectLikesInput\n }\n validate=validate\n )\n Br\n if $mode.get() === 'new'\n Div(align='right' row)\n Button(onPress=cancel) Cancel\n Button(disabled=validate.hasErrors pushed variant='flat' color='primary' onPress=create) Create\n else if $mode.get() === 'edit'\n Div(align='right' row)\n Button(color='error' onPress=deleteCat) Delete\n `\n})\n\nconst CatsList = observer(({ onEdit, breed, eventId }) => {\n if (!eventId) return pug`Alert(variant='error') No event specified`\n const $cats = useSub($.cats, { eventId, breed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n Item(key=$cat.getId())\n CatCard($cat=$cat)\n Item.Right\n Div(vAlign='center' row gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n Button(variant='text' icon=faPen onPress=() => onEdit($cat) tooltip='Edit')\n Link(href='/events/' + eventId + '/matches/' + $cat.getId())\n Button(variant='text' icon=faHeart tooltip='Matches')\n Link(href='/cats/' + $cat.token.get())\n Button(variant='text' icon=faLink tooltip='Cat profile link') Link\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nconst SelectLikesInput = observer(({ $value, ...props }) => {\n const { oppositeBreed, eventId } = { ...useFormProps(), ...props }\n return pug`\n if oppositeBreed\n SelectLikes(\n $likes=$value\n oppositeBreed=oppositeBreed\n eventId=eventId\n )\n else\n Alert(variant='warning') Select breed to choose likes\n `\n})\n\nconst SelectLikes = observer(({ $likes, oppositeBreed, eventId }) => {\n const $cats = useSub($.cats, { eventId, breed: oppositeBreed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n - const catId = $cat.getId()\n Item.item(\n key=catId\n styleName={ selected: $likes[catId].get() }\n onPress=() => $likes[catId].get() ? $likes[catId].del() : $likes[catId].set(true)\n )\n CatCard($cat=$cat small)\n else\n Alert(variant='info') No cats with selected breed yet\n style(lang='styl')\n .item\n border-radius 1u\n &.selected\n // FIXME: We can't use color var(--color-text-success-strong) here\n background-color var(--color-text-success-strong)\n `\n})\n" ], - "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,iBACE,mBACE,kBAAiB,SAAQ,QAAO,UAAS,OAAM,iCACnD,iBAAgB,IACd,gBAAe,YAAY,SAAU,0BACvC,MACE,OAAM,mDACN,UAAS,YACT,WAAU,iBAER,wHACF,KACE,KAAI,6BACJ,SAAQ,SACR,QAAO,WACP,eAAc,eACd,SAAQ,SACR,cAAa;AACjB;AACA,OACI,UAAS,aAEX,MACG,yBACD,uBACE,gBAAe,QAAQ,gBACvB,iBAAgB,oBAAmB,+CAA8C,QAAQ,wBACrF,0BACN,uBACE,8BAA6B,WAAW,mDAC/C;AACH;AACA;AACA;AACA,yBAA2B,sBAAuB,2BAAmB;AACrE;AACA,uEACS,QAAQ,8BACX,UAAS,eACP,cAAa,SACb,YACE,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBACrB,4BAA2B,OAAM,SAAQ,oBAAmB,kBAC5D,WAAU,oDACR,4BAA2B,SAAQ,4BACrC,WAAU,8BACR,4BAA2B,QAAO,2BAA4B,6EACzE;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UACO,iBACD,YACE,QAAO,QACP,eAAc,eACd,SAAQ,eAGV,wBAAyB,qCAC5B;AACH;AACA;AACA;;IAcM;IACA;IACA;IACA;IACA;;;AAjBN;AACA,uEACS,QAAQ,qCACT,mCACF,KAEE,aAFE,OAEQ,oCADV,KAAI,OAEJ,SAAQ,4EAER,cAAa,MAAK,0EAEpB,qBAAsB,6CAOzB;AACH", + "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,iBACE,mBACE,kBAAS,SAAgB,QAAO,UAAS,OAAA,iCAC7C,iBAAgB,IACd,gBAAe,YAAY,SAAU,0BACvC,MACE,OAAM,mDACN,UAAS,YACT,WAAU,iBAER,wHACF,KACE,KAAI,6BACJ,SAAA,SACA,QAAO,WACP,eAAA,eACA,SAAA,SACA,cAAa;AACjB;AACA,OACI,UAAA,aAEF,MACG,yBACD,uBACE,gBAAe,QAAQ,gBACvB,iBAAgB,oBAAmB,+CAA8C,QAAQ,wBACrF,0BACN,uBACE,8BAA6B,WAAW,mDAC/C;AACH;AACA;AACA;AACA,yBAA2B,sBAAuB,2BAAmB;AACrE;AACA,uEACS,QAAQ,8BACX,UAAS,eACP,cAAQ,SACR,YACE,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBACrB,4BAA2B,OAAM,SAAQ,oBAAmB,kBAC5D,WAAU,oDACR,4BAA2B,SAAQ,4BACrC,WAAU,8BACR,4BAA2B,QAAO,2BAA4B,6EACzE;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UACO,iBACD,YACE,QAAO,QACP,eAAA,eACA,SAAA,eAGF,wBAAyB,qCAC5B;AACH;AACA;AACA;;IAcM;IACA;IACA;IACA;IACA;;;AAjBN;AACA,uEACS,QAAQ,qCACT,mCACF,KAEE,aAFE,OAEQ,oCADV,KAAI,OAEJ,SAAQ,4EAER,cAAQ,MAAU,0EAEpB,qBAAsB,6CAOzB;AACH", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/shadow/event-tabs-breed.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/shadow/event-tabs-breed.tsx.output.sourcemap.json index 529de6b..bf70d21 100644 --- a/test/fixtures/real-project/snapshots/shadow/event-tabs-breed.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/shadow/event-tabs-breed.tsx.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "import React, { useState } from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport {\n Link, Item, ScrollView, Form, useFormProps, Alert,\n Content, Tag, Br, Button, Modal, Div, confirm,\n useFormFields$, useValidate\n} from 'startupjs-ui'\nimport { useGlobalSearchParams } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faLink } from '@fortawesome/free-solid-svg-icons/faLink'\nimport CatCard from '@/components/CatCard'\nimport { CAT_FORM } from '@/model/cats/schema'\n\nexport default observer(({ breed }) => {\n const { eventId } = useGlobalSearchParams()\n const [$selected, set$selected] = useState()\n const $new = $()\n const $showModal = $()\n const $mode = $()\n const $fields = useFormFields$(CAT_FORM)\n const validate = useValidate()\n\n function showCreate () {\n $new.set({ breed })\n $fields.breed.disabled.set(true)\n set$selected(() => $new)\n $mode.set('new')\n $showModal.set(true)\n }\n\n function showEdit ($cat) {\n $fields.breed.disabled.del()\n set$selected(() => $cat)\n $mode.set('edit')\n $showModal.set(true)\n }\n\n function cancel () {\n if (!$showModal.get()) return\n $showModal.del()\n $mode.del()\n }\n\n async function create () {\n if (!validate()) return\n await $.cats.addNew({\n ...$new.getDeepCopy(),\n eventId\n })\n cancel()\n }\n\n async function deleteCat () {\n if (!await confirm(`Are you sure you want to delete ${$selected.name.get()}?`)) return\n await $selected.del()\n cancel()\n }\n\n return pug`\n ScrollView(full)\n Content(full pure)\n CatsList(eventId=eventId onEdit=showEdit breed=breed)\n Content(padding=1)\n Button(onPress=showCreate) Add new #{breed}\n Modal(\n title=$mode.get() === 'new' ? 'Create cat' : 'Edit cat'\n $visible=$showModal\n onDismiss=cancel\n )\n - const oppositeBreed = $selected?.breed.get() && ($selected.breed.get() === 'domestic' ? 'wild' : 'domestic')\n Form(\n key=$selected?.getId() || 'NEW'\n $fields=$fields\n $value=$selected\n oppositeBreed=oppositeBreed\n eventId=eventId\n customInputs={\n likes: SelectLikesInput\n }\n validate=validate\n )\n Br\n if $mode.get() === 'new'\n Div(align='right' row)\n Button(onPress=cancel) Cancel\n Button(disabled=validate.hasErrors pushed variant='flat' color='primary' onPress=create) Create\n else if $mode.get() === 'edit'\n Div(align='right' row)\n Button(color='error' onPress=deleteCat) Delete\n `\n})\n\nconst CatsList = observer(({ onEdit, breed, eventId }) => {\n if (!eventId) return pug`Alert(variant='error') No event specified`\n const $cats = useSub($.cats, { eventId, breed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n Item(key=$cat.getId())\n CatCard($cat=$cat)\n Item.Right\n Div(vAlign='center' row gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n Button(variant='text' icon=faPen onPress=() => onEdit($cat) tooltip='Edit')\n Link(href='/events/' + eventId + '/matches/' + $cat.getId())\n Button(variant='text' icon=faHeart tooltip='Matches')\n Link(href='/cats/' + $cat.token.get())\n Button(variant='text' icon=faLink tooltip='Cat profile link') Link\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nconst SelectLikesInput = observer(({ $value, ...props }) => {\n const { oppositeBreed, eventId } = { ...useFormProps(), ...props }\n return pug`\n if oppositeBreed\n SelectLikes(\n $likes=$value\n oppositeBreed=oppositeBreed\n eventId=eventId\n )\n else\n Alert(variant='warning') Select breed to choose likes\n `\n})\n\nconst SelectLikes = observer(({ $likes, oppositeBreed, eventId }) => {\n const $cats = useSub($.cats, { eventId, breed: oppositeBreed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n - const catId = $cat.getId()\n Item.item(\n key=catId\n styleName={ selected: $likes[catId].get() }\n onPress=() => $likes[catId].get() ? $likes[catId].del() : $likes[catId].set(true)\n )\n CatCard($cat=$cat small)\n else\n Alert(variant='info') No cats with selected breed yet\n style(lang='styl')\n .item\n border-radius 1u\n &.selected\n // FIXME: We can't use color var(--color-text-success-strong) here\n background-color var(--color-text-success-strong)\n `\n})\n" ], - "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,iBACE,mBACE,kBAAiB,SAAQ,QAAO,UAAS,OAAM,iCACnD,iBAAgB,IACd,gBAAe,YAAY,SAAU,0BACvC,MACE,OAAM,mDACN,UAAS,YACT,WAAU,iBAER,wHACF,KACE,KAAI,6BACJ,SAAQ,SACR,QAAO,WACP,eAAc,eACd,SAAQ,SACR,cAAa;AACjB;AACA,OACI,UAAS,aAEX,MACG,yBACD,uBACE,gBAAe,QAAQ,gBACvB,iBAAgB,oBAAmB,+CAA8C,QAAQ,wBACrF,0BACN,uBACE,8BAA6B,WAAW,mDAC/C;AACH;AACA;AACA;AACA,yBAA2B,sBAAuB,2BAAmB;AACrE;AACA,uEACS,QAAQ,8BACX,UAAS,eACP,cAAa,SACb,YACE,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBACrB,4BAA2B,OAAM,SAAQ,oBAAmB,kBAC5D,WAAU,oDACR,4BAA2B,SAAQ,4BACrC,WAAU,8BACR,4BAA2B,QAAO,2BAA4B,6EACzE;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UACO,iBACD,YACE,QAAO,QACP,eAAc,eACd,SAAQ,eAGV,wBAAyB,qCAC5B;AACH;AACA;AACA;;IAcM;IACA;IACA;IACA;IACA;;;AAjBN;AACA,uEACS,QAAQ,qCACT,mCACF,KAEE,aAFE,OAEQ,oCADV,KAAI,OAEJ,SAAQ,4EAER,cAAa,MAAK,0EAEpB,qBAAsB,6CAOzB;AACH", + "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,iBACE,mBACE,kBAAS,SAAgB,QAAO,UAAS,OAAA,iCAC7C,iBAAgB,IACd,gBAAe,YAAY,SAAU,0BACvC,MACE,OAAM,mDACN,UAAS,YACT,WAAU,iBAER,wHACF,KACE,KAAI,6BACJ,SAAA,SACA,QAAO,WACP,eAAA,eACA,SAAA,SACA,cAAa;AACjB;AACA,OACI,UAAA,aAEF,MACG,yBACD,uBACE,gBAAe,QAAQ,gBACvB,iBAAgB,oBAAmB,+CAA8C,QAAQ,wBACrF,0BACN,uBACE,8BAA6B,WAAW,mDAC/C;AACH;AACA;AACA;AACA,yBAA2B,sBAAuB,2BAAmB;AACrE;AACA,uEACS,QAAQ,8BACX,UAAS,eACP,cAAQ,SACR,YACE,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBACrB,4BAA2B,OAAM,SAAQ,oBAAmB,kBAC5D,WAAU,oDACR,4BAA2B,SAAQ,4BACrC,WAAU,8BACR,4BAA2B,QAAO,2BAA4B,6EACzE;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UACO,iBACD,YACE,QAAO,QACP,eAAA,eACA,SAAA,eAGF,wBAAyB,qCAC5B;AACH;AACA;AACA;;IAcM;IACA;IACA;IACA;IACA;;;AAjBN;AACA,uEACS,QAAQ,qCACT,mCACF,KAEE,aAFE,OAEQ,oCADV,KAAI,OAEJ,SAAQ,4EAER,cAAQ,MAAU,0EAEpB,qBAAsB,6CAOzB;AACH", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/shadow/event-tabs-layout.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/shadow/event-tabs-layout.js.output.sourcemap.json index 8a020cb..16689a4 100644 --- a/test/fixtures/real-project/snapshots/shadow/event-tabs-layout.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/shadow/event-tabs-layout.js.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "// import { Platform } from 'react-native'\nimport React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { useColors, Icon, Form, Modal, Button } from 'startupjs-ui'\nimport { Tabs, useLocalSearchParams, Stack } from 'expo-router'\nimport { faVenus as faWildBadge } from '@fortawesome/free-solid-svg-icons/faVenus'\nimport { faMars as faDomesticBadge } from '@fortawesome/free-solid-svg-icons/faMars'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faToolbox } from '@fortawesome/free-solid-svg-icons/faToolbox'\nimport { EVENT_FORM } from '@/model/events/schema'\n\nexport default observer(function TabLayout () {\n const getColor = useColors()\n const { eventId } = useLocalSearchParams()\n const $event = useSub($.events[eventId])\n if (!$event.get()) throw Error('No such event')\n\n // NOTE:\n // headerShown -- Disable the static render of the header on web to prevent a hydration error in React Navigation v6.\n // tabBarStyle/order - Move the tab bar to the top on tablet+\n return pug`\n Stack.Screen(\n options={\n title: $event.name.get(),\n headerRight: () => renderEditEvent({ $event })\n }\n )\n Tabs(\n title=$event.name.get()\n screenOptions={\n ...styl('screen'),\n tabBarActiveTintColor: getColor('primary'),\n tabBarActiveBackgroundColor: 'rgba(255, 255, 255, 0.5)',\n headerShown: false,\n headerTitle: $event.name.get()\n }\n )\n Tabs.Screen(\n name='index'\n options={\n title: 'Dashboard',\n tabBarIcon: renderHomeIcon\n }\n )\n Tabs.Screen(\n name='-breed'\n options={\n href: null\n }\n )\n Tabs.Screen(\n name='domestic'\n options={\n title: 'Domestic Cats',\n tabBarIcon: renderDomesticIcon\n }\n )\n Tabs.Screen(\n name='wild'\n options={\n title: 'Wild Cats',\n tabBarIcon: renderWildIcon\n }\n )\n Tabs.Screen(\n name='test'\n options={\n title: 'Dev Only',\n tabBarIcon: renderTestIcon\n }\n )\n style(lang='styl')\n +tablet()\n .screen\n &:part(tabBar)\n order -1\n background-color transparent\n border-bottom-width 1px\n border-bottom-color rgba(0, 0, 0, 0.1)\n `\n})\n\nfunction renderEditEvent ({ $event }) {\n return pug`\n EditEvent($event=$event)\n `\n}\n\nconst EditEvent = observer(({ $event }) => {\n const $showModal = $()\n return pug`\n Button(onPress=() => $showModal.set(true) variant='text' icon=faPen) Edit this cat meetup\n Modal(\n title='Edit cat meetup'\n $visible=$showModal\n )\n Form(\n $value=$event\n fields=EVENT_FORM\n )\n `\n})\n\nfunction renderWildIcon ({ color, size }) {\n return pug`\n Icon(icon=faWildBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderDomesticIcon ({ color, size }) {\n return pug`\n Icon(icon=faDomesticBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderHomeIcon ({ color, size }) {\n return pug`\n Icon(icon=faHeart style={ color, width: size, height: size })\n `\n}\n\nfunction renderTestIcon ({ color, size }) {\n return pug`\n Icon(icon=faToolbox style={ color, width: size, height: size })\n `\n}\n" ], - "mappings": "AAAA;AACA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;IA6DM;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlEN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,KACE,OAAM,mBACN,eAAc;AAChB;AACA;AACA;AACA;AACA;AACA,MAEE,YACE,aACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,cACA,SAAQ;AACZ;AACA,UAEE,YACE,gBACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,oBAUD;AACH;AACA;AACA;AACA,WACI,kBAAiB,WAClB;AACH;AACA;AACA;AACA;AACA,aACI,gBAAe,4BAA2B,qBAAoB,OAAO,8BACrE,MACE,wBACA,UAAS,aAET,KACE,QAAO,QACP,QAAO,0BAEZ;AACH;AACA;AACA;AACA,WACI,WAAU,aAAY,OAAM,yCAC7B;AACH;AACA;AACA;AACA,WACI,WAAU,iBAAgB,OAAM,yCACjC;AACH;AACA;AACA;AACA,WACI,WAAU,SAAQ,OAAM,yCACzB;AACH;AACA;AACA;AACA,WACI,WAAU,WAAU,OAAM,yCAC3B;AACH", + "mappings": "AAAA;AACA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;IA6DM;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlEN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,KACE,OAAM,mBACN,eAAc;AAChB;AACA;AACA;AACA;AACA;AACA,MAEE,YACE,aACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,cACA,SAAQ;AACZ;AACA,UAEE,YACE,gBACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,oBAUD;AACH;AACA;AACA;AACA,WACI,kBAAU,WACX;AACH;AACA;AACA;AACA;AACA,aACI,gBAAe,4BAA2B,qBAAoB,OAAO,8BACrE,MACE,wBACA,UAAS,aAET,KACE,QAAO,QACP,QAAO,0BAEZ;AACH;AACA;AACA;AACA,WACI,WAAU,aAAY,OAAM,yCAC7B;AACH;AACA;AACA;AACA,WACI,WAAU,iBAAgB,OAAM,yCACjC;AACH;AACA;AACA;AACA,WACI,WAAU,SAAQ,OAAM,yCACzB;AACH;AACA;AACA;AACA,WACI,WAAU,WAAU,OAAM,yCAC3B;AACH", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/shadow/event-tabs-layout.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/shadow/event-tabs-layout.tsx.output.sourcemap.json index 8dbf3d1..1453c9e 100644 --- a/test/fixtures/real-project/snapshots/shadow/event-tabs-layout.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/shadow/event-tabs-layout.tsx.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "// import { Platform } from 'react-native'\nimport React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { useColors, Icon, Form, Modal, Button } from 'startupjs-ui'\nimport { Tabs, useLocalSearchParams, Stack } from 'expo-router'\nimport { faVenus as faWildBadge } from '@fortawesome/free-solid-svg-icons/faVenus'\nimport { faMars as faDomesticBadge } from '@fortawesome/free-solid-svg-icons/faMars'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faToolbox } from '@fortawesome/free-solid-svg-icons/faToolbox'\nimport { EVENT_FORM } from '@/model/events/schema'\n\nexport default observer(function TabLayout () {\n const getColor = useColors()\n const { eventId } = useLocalSearchParams()\n const $event = useSub($.events[eventId])\n if (!$event.get()) throw Error('No such event')\n\n // NOTE:\n // headerShown -- Disable the static render of the header on web to prevent a hydration error in React Navigation v6.\n // tabBarStyle/order - Move the tab bar to the top on tablet+\n return pug`\n Stack.Screen(\n options={\n title: $event.name.get(),\n headerRight: () => renderEditEvent({ $event })\n }\n )\n Tabs(\n title=$event.name.get()\n screenOptions={\n ...styl('screen'),\n tabBarActiveTintColor: getColor('primary'),\n tabBarActiveBackgroundColor: 'rgba(255, 255, 255, 0.5)',\n headerShown: false,\n headerTitle: $event.name.get()\n }\n )\n Tabs.Screen(\n name='index'\n options={\n title: 'Dashboard',\n tabBarIcon: renderHomeIcon\n }\n )\n Tabs.Screen(\n name='-breed'\n options={\n href: null\n }\n )\n Tabs.Screen(\n name='domestic'\n options={\n title: 'Domestic Cats',\n tabBarIcon: renderDomesticIcon\n }\n )\n Tabs.Screen(\n name='wild'\n options={\n title: 'Wild Cats',\n tabBarIcon: renderWildIcon\n }\n )\n Tabs.Screen(\n name='test'\n options={\n title: 'Dev Only',\n tabBarIcon: renderTestIcon\n }\n )\n style(lang='styl')\n +tablet()\n .screen\n &:part(tabBar)\n order -1\n background-color transparent\n border-bottom-width 1px\n border-bottom-color rgba(0, 0, 0, 0.1)\n `\n})\n\nfunction renderEditEvent ({ $event }) {\n return pug`\n EditEvent($event=$event)\n `\n}\n\nconst EditEvent = observer(({ $event }) => {\n const $showModal = $()\n return pug`\n Button(onPress=() => $showModal.set(true) variant='text' icon=faPen) Edit this cat meetup\n Modal(\n title='Edit cat meetup'\n $visible=$showModal\n )\n Form(\n $value=$event\n fields=EVENT_FORM\n )\n `\n})\n\nfunction renderWildIcon ({ color, size }) {\n return pug`\n Icon(icon=faWildBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderDomesticIcon ({ color, size }) {\n return pug`\n Icon(icon=faDomesticBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderHomeIcon ({ color, size }) {\n return pug`\n Icon(icon=faHeart style={ color, width: size, height: size })\n `\n}\n\nfunction renderTestIcon ({ color, size }) {\n return pug`\n Icon(icon=faToolbox style={ color, width: size, height: size })\n `\n}\n" ], - "mappings": "AAAA;AACA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;IA6DM;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlEN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,KACE,OAAM,mBACN,eAAc;AAChB;AACA;AACA;AACA;AACA;AACA,MAEE,YACE,aACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,cACA,SAAQ;AACZ;AACA,UAEE,YACE,gBACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,oBAUD;AACH;AACA;AACA;AACA,WACI,kBAAiB,WAClB;AACH;AACA;AACA;AACA;AACA,aACI,gBAAe,4BAA2B,qBAAoB,OAAO,8BACrE,MACE,wBACA,UAAS,aAET,KACE,QAAO,QACP,QAAO,0BAEZ;AACH;AACA;AACA;AACA,WACI,WAAU,aAAY,OAAM,yCAC7B;AACH;AACA;AACA;AACA,WACI,WAAU,iBAAgB,OAAM,yCACjC;AACH;AACA;AACA;AACA,WACI,WAAU,SAAQ,OAAM,yCACzB;AACH;AACA;AACA;AACA,WACI,WAAU,WAAU,OAAM,yCAC3B;AACH", + "mappings": "AAAA;AACA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;IA6DM;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlEN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,KACE,OAAM,mBACN,eAAc;AAChB;AACA;AACA;AACA;AACA;AACA,MAEE,YACE,aACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,cACA,SAAQ;AACZ;AACA,UAEE,YACE,gBACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,oBAUD;AACH;AACA;AACA;AACA,WACI,kBAAU,WACX;AACH;AACA;AACA;AACA;AACA,aACI,gBAAe,4BAA2B,qBAAoB,OAAO,8BACrE,MACE,wBACA,UAAS,aAET,KACE,QAAO,QACP,QAAO,0BAEZ;AACH;AACA;AACA;AACA,WACI,WAAU,aAAY,OAAM,yCAC7B;AACH;AACA;AACA;AACA,WACI,WAAU,iBAAgB,OAAM,yCACjC;AACH;AACA;AACA;AACA,WACI,WAAU,SAAQ,OAAM,yCACzB;AACH;AACA;AACA;AACA,WACI,WAAU,WAAU,OAAM,yCAC3B;AACH", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/swc/CatCard.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/swc/CatCard.js.output.sourcemap.json index 6970ef4..905ed35 100644 --- a/test/fixtures/real-project/snapshots/swc/CatCard.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/swc/CatCard.js.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport { Div, Span, Avatar, Link } from 'startupjs-ui'\n\nexport default observer(({ $cat, showPhone, large, small }) => {\n const { name, number, phone, catgram, photoFileId, phonegram } = $cat.get()\n return pug`\n Div(part='root' row vAlign='center')\n if photoFileId\n Photo.avatar(styleName={ large, small } fileId=photoFileId name=name)\n else\n Avatar.avatar(styleName={ large, small })= name\n Div(row)\n Span.text(bold styleName={ large })= (number || 'X') + '. '\n Div\n Span.text(styleName={ large })= name\n if showPhone\n if phone\n Span.text(styleName={ large })\n Span(bold) Phone:#{' '}\n = phone\n if catgram\n Span.text(styleName={ large })\n Span(bold) Catgram:#{' '}\n Link.text(styleName={ large } to=getCatgramLink(catgram))= catgram\n if phonegram\n Span.text(styleName={ large })\n Span(bold) Phonegram:#{' '}\n Link.text(styleName={ large } to=getPhonegramLink(phonegram))= phonegram\n style(lang='styl')\n .avatar\n margin-right 1u\n &.large\n width 12u\n height @width\n &.small\n width 4u\n height @width\n .text.large\n font(h6)\n `\n})\n\nconst Photo = observer(({ fileId, name }) => {\n const $file = useSub($.files[fileId])\n let url\n try { url = $file.getUrl() } catch (err) {}\n return pug`\n Avatar(part='root' src=url)= name\n `\n})\n\nfunction getCatgramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://catgr.am/' + username\n}\n\nfunction getPhonegramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://www.phonegram.com/' + username\n}\n" ], - "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;;IA0BM;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlCN;AACA,WACI,qCACK,eACD,MAAa,aAAR,SAAkB,mBAAiB,QAAO,aAAY,MAAK,YAEhE,OAAc,aAAR,SAAkB,oBAAmB,gBAC7C,SACE,KAAe,aAAX,OAAqB,YAAf,MAA2B,+BACrC,KACE,KAAU,aAAN,OAAgB,aAAY,aAC7B,eACE,SACD,KAAU,aAAN,OAAgB,aAClB,UAAW,OAAQ,YACjB,sBACH,WACD,KAAU,aAAN,OAAgB,aAClB,UAAW,SAAU,YACrB,KAAU,aAAN,OAAgB,YAAU,IAAG,0BAA0B,+BAC5D,aACD,KAAU,aAAN,OAAgB,aAClB,UAAW,WAAY,YACvB,KAAU,aAAN,OAAgB,YAAU,IAAG,8BAA8B,8DAY5E;AACH;AACA;AACA;AACA;AACA;AACA;AACA,WACI,wBAAuB,MAAM,eAC9B;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", + "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;;IA0BM;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlCN;AACA,WACI,qCACK,eACD,MAAa,aAAR,SAAkB,mBAAiB,QAAO,aAAY,MAAA,YAE3D,OAAc,aAAR,SAAkB,oBAAmB,gBAC7C,SACE,KAAe,aAAX,OAAqB,YAAf,MAA2B,+BACrC,KACE,KAAU,aAAN,OAAgB,aAAY,aAC7B,eACE,SACD,KAAU,aAAN,OAAgB,aAClB,UAAW,OAAQ,YACjB,sBACH,WACD,KAAU,aAAN,OAAgB,aAClB,UAAW,SAAU,YACrB,KAAU,aAAN,OAAgB,YAAU,IAAG,0BAA0B,+BAC5D,aACD,KAAU,aAAN,OAAgB,aAClB,UAAW,WAAY,YACvB,KAAU,aAAN,OAAgB,YAAU,IAAG,8BAA8B,8DAY5E;AACH;AACA;AACA;AACA;AACA;AACA;AACA,WACI,wBAAuB,MAAM,eAC9B;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/swc/CatCard.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/swc/CatCard.tsx.output.sourcemap.json index fd7dc9f..f4190df 100644 --- a/test/fixtures/real-project/snapshots/swc/CatCard.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/swc/CatCard.tsx.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport { Div, Span, Avatar, Link } from 'startupjs-ui'\n\nexport default observer(({ $cat, showPhone, large, small }) => {\n const { name, number, phone, catgram, photoFileId, phonegram } = $cat.get()\n return pug`\n Div(part='root' row vAlign='center')\n if photoFileId\n Photo.avatar(styleName={ large, small } fileId=photoFileId name=name)\n else\n Avatar.avatar(styleName={ large, small })= name\n Div(row)\n Span.text(bold styleName={ large })= (number || 'X') + '. '\n Div\n Span.text(styleName={ large })= name\n if showPhone\n if phone\n Span.text(styleName={ large })\n Span(bold) Phone:#{' '}\n = phone\n if catgram\n Span.text(styleName={ large })\n Span(bold) Catgram:#{' '}\n Link.text(styleName={ large } to=getCatgramLink(catgram))= catgram\n if phonegram\n Span.text(styleName={ large })\n Span(bold) Phonegram:#{' '}\n Link.text(styleName={ large } to=getPhonegramLink(phonegram))= phonegram\n style(lang='styl')\n .avatar\n margin-right 1u\n &.large\n width 12u\n height @width\n &.small\n width 4u\n height @width\n .text.large\n font(h6)\n `\n})\n\nconst Photo = observer(({ fileId, name }) => {\n const $file = useSub($.files[fileId])\n let url\n try { url = $file.getUrl() } catch (err) {}\n return pug`\n Avatar(part='root' src=url)= name\n `\n})\n\nfunction getCatgramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://catgr.am/' + username\n}\n\nfunction getPhonegramLink (username) {\n if (!username) return\n if (/:\\/\\//.test(username)) return username\n return 'https://www.phonegram.com/' + username\n}\n" ], - "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;;IA0BM;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlCN;AACA,WACI,qCACK,eACD,MAAa,aAAR,SAAkB,mBAAiB,QAAO,aAAY,MAAK,YAEhE,OAAc,aAAR,SAAkB,oBAAmB,gBAC7C,SACE,KAAe,aAAX,OAAqB,YAAf,MAA2B,+BACrC,KACE,KAAU,aAAN,OAAgB,aAAY,aAC7B,eACE,SACD,KAAU,aAAN,OAAgB,aAClB,UAAW,OAAQ,YACjB,sBACH,WACD,KAAU,aAAN,OAAgB,aAClB,UAAW,SAAU,YACrB,KAAU,aAAN,OAAgB,YAAU,IAAG,0BAA0B,+BAC5D,aACD,KAAU,aAAN,OAAgB,aAClB,UAAW,WAAY,YACvB,KAAU,aAAN,OAAgB,YAAU,IAAG,8BAA8B,8DAY5E;AACH;AACA;AACA;AACA;AACA;AACA;AACA,WACI,wBAAuB,MAAM,eAC9B;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", + "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;;IA0BM;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlCN;AACA,WACI,qCACK,eACD,MAAa,aAAR,SAAkB,mBAAiB,QAAO,aAAY,MAAA,YAE3D,OAAc,aAAR,SAAkB,oBAAmB,gBAC7C,SACE,KAAe,aAAX,OAAqB,YAAf,MAA2B,+BACrC,KACE,KAAU,aAAN,OAAgB,aAAY,aAC7B,eACE,SACD,KAAU,aAAN,OAAgB,aAClB,UAAW,OAAQ,YACjB,sBACH,WACD,KAAU,aAAN,OAAgB,aAClB,UAAW,SAAU,YACrB,KAAU,aAAN,OAAgB,YAAU,IAAG,0BAA0B,+BAC5D,aACD,KAAU,aAAN,OAAgB,aAClB,UAAW,WAAY,YACvB,KAAU,aAAN,OAAgB,YAAU,IAAG,8BAA8B,8DAY5E;AACH;AACA;AACA;AACA;AACA;AACA;AACA,WACI,wBAAuB,MAAM,eAC9B;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/swc/cat-profile-link.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/swc/cat-profile-link.js.output.sourcemap.json index d014b54..e192b38 100644 --- a/test/fixtures/real-project/snapshots/swc/cat-profile-link.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/swc/cat-profile-link.js.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { Alert, Span, Modal, Content, Button, Form, Div, Tag, useMedia, useFormFields } from 'startupjs-ui'\nimport { useGlobalSearchParams, Stack } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport CatCard from '@/components/CatCard'\nimport * as stages from '@/components/stages'\nimport { CAT_PROFILE_EDIT_FORM } from '@/model/cats/schema'\nimport { STAGES } from '@/model/events/schema'\n\nexport default observer(() => {\n const { token } = useGlobalSearchParams()\n const [$cat] = useSub($.cats, { token })\n if (!$cat) return renderExpired()\n\n const eventId = $cat.eventId.get()\n const $event = useSub($.events[eventId])\n\n function renderTitle () {\n return pug`\n CatCard($cat=$cat)\n `\n }\n\n function renderSettings () {\n return pug`\n Profile($cat=$cat $event=$event)\n `\n }\n\n const Stage = stages[$cat.getMyStage()]\n\n return pug`\n Stack.Screen(\n options={\n headerTitle: renderTitle,\n headerRight: renderSettings\n }\n )\n Stage($cat=$cat $event=$event)\n `\n})\n\nconst Profile = observer(({ $cat, $event }) => {\n const $showEdit = $()\n const { tablet } = useMedia()\n const excludeNumber = $event.stage.get() !== STAGES.InProgress\n const profileEditFields = useFormFields(CAT_PROFILE_EDIT_FORM, excludeNumber ? { exclude: ['number'] } : {})\n\n return pug`\n Div(row vAlign='center' gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n if $cat.getMyStage() === STAGES.Profile\n Div.hackSidePadding\n else\n Button(\n variant='text'\n icon=faPen\n onPress=() => $showEdit.set(true)\n )\n if tablet\n = 'Edit cat profile'\n else\n = 'Edit'\n Modal(\n title='Edit cat profile'\n $visible=$showEdit\n )\n Form(\n fields=profileEditFields\n $value=$cat\n )\n style(lang='styl')\n .hackSidePadding\n width 1u\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nfunction renderExpired () {\n return pug`\n Content(padding)\n Alert(variant='error')\n Span\n | Cat profile link is incorrect or already expired.\n |\n | Your cat meetup profile link is only valid for a limited period of time.\n |\n | If you believe this is an error, please contact the cat meetup organizer.\n `\n}\n" ], - "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACM,cAAa,SACd;AACL;AACA;AACA;AACA,aACM,cAAa,MAAK,QAAO,WAC1B;AACL;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,YAAW,MAAK,QAAO,cACxB;AACH;AACA;AACA;;IAiCM;IACA;;;AAjCN;AACA;AACA;AACA;AACA;AACA,aACI,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBAClB,wCACD,iBAAG,yBAEH,OACE,eACA,MAAK,OACL,SAAQ,4BAEL,SACC,qBAEA,wBACV,MACE,yBACA,UAAS,YAET,KACE,QAAO,mBACP,QAAO,oBAKZ;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WACI,iBACE,uBACE,KACI;AACP;AACA,CAAQ;AACR;AACA,CAAQ,kGACV;AACH", + "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACM,cAAQ,SACT;AACL;AACA;AACA;AACA,aACM,cAAQ,MAAU,QAAA,WACnB;AACL;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,YAAM,MAAU,QAAA,cACjB;AACH;AACA;AACA;;IAiCM;IACA;;;AAjCN;AACA;AACA;AACA;AACA;AACA,aACI,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBAClB,wCACD,iBAAG,yBAEH,OACE,eACA,MAAK,OACL,SAAQ,4BAEL,SACC,qBAEA,wBACV,MACE,yBACA,UAAS,YAET,KACE,QAAO,mBACP,QAAO,oBAKZ;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WACI,iBACE,uBACE,KACI;AACP;AACA,CAAQ;AACR;AACA,CAAQ,kGACV;AACH", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/swc/cat-profile-link.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/swc/cat-profile-link.tsx.output.sourcemap.json index 2603a48..d7d36d9 100644 --- a/test/fixtures/real-project/snapshots/swc/cat-profile-link.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/swc/cat-profile-link.tsx.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "import React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { Alert, Span, Modal, Content, Button, Form, Div, Tag, useMedia, useFormFields } from 'startupjs-ui'\nimport { useGlobalSearchParams, Stack } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport CatCard from '@/components/CatCard'\nimport * as stages from '@/components/stages'\nimport { CAT_PROFILE_EDIT_FORM } from '@/model/cats/schema'\nimport { STAGES } from '@/model/events/schema'\n\nexport default observer(() => {\n const { token } = useGlobalSearchParams()\n const [$cat] = useSub($.cats, { token })\n if (!$cat) return renderExpired()\n\n const eventId = $cat.eventId.get()\n const $event = useSub($.events[eventId])\n\n function renderTitle () {\n return pug`\n CatCard($cat=$cat)\n `\n }\n\n function renderSettings () {\n return pug`\n Profile($cat=$cat $event=$event)\n `\n }\n\n const Stage = stages[$cat.getMyStage()]\n\n return pug`\n Stack.Screen(\n options={\n headerTitle: renderTitle,\n headerRight: renderSettings\n }\n )\n Stage($cat=$cat $event=$event)\n `\n})\n\nconst Profile = observer(({ $cat, $event }) => {\n const $showEdit = $()\n const { tablet } = useMedia()\n const excludeNumber = $event.stage.get() !== STAGES.InProgress\n const profileEditFields = useFormFields(CAT_PROFILE_EDIT_FORM, excludeNumber ? { exclude: ['number'] } : {})\n\n return pug`\n Div(row vAlign='center' gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n if $cat.getMyStage() === STAGES.Profile\n Div.hackSidePadding\n else\n Button(\n variant='text'\n icon=faPen\n onPress=() => $showEdit.set(true)\n )\n if tablet\n = 'Edit cat profile'\n else\n = 'Edit'\n Modal(\n title='Edit cat profile'\n $visible=$showEdit\n )\n Form(\n fields=profileEditFields\n $value=$cat\n )\n style(lang='styl')\n .hackSidePadding\n width 1u\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nfunction renderExpired () {\n return pug`\n Content(padding)\n Alert(variant='error')\n Span\n | Cat profile link is incorrect or already expired.\n |\n | Your cat meetup profile link is only valid for a limited period of time.\n |\n | If you believe this is an error, please contact the cat meetup organizer.\n `\n}\n" ], - "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACM,cAAa,SACd;AACL;AACA;AACA;AACA,aACM,cAAa,MAAK,QAAO,WAC1B;AACL;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,YAAW,MAAK,QAAO,cACxB;AACH;AACA;AACA;;IAiCM;IACA;;;AAjCN;AACA;AACA;AACA;AACA;AACA,aACI,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBAClB,wCACD,iBAAG,yBAEH,OACE,eACA,MAAK,OACL,SAAQ,4BAEL,SACC,qBAEA,wBACV,MACE,yBACA,UAAS,YAET,KACE,QAAO,mBACP,QAAO,oBAKZ;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WACI,iBACE,uBACE,KACI;AACP;AACA,CAAQ;AACR;AACA,CAAQ,kGACV;AACH", + "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACM,cAAQ,SACT;AACL;AACA;AACA;AACA,aACM,cAAQ,MAAU,QAAA,WACnB;AACL;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,YAAM,MAAU,QAAA,cACjB;AACH;AACA;AACA;;IAiCM;IACA;;;AAjCN;AACA;AACA;AACA;AACA;AACA,aACI,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBAClB,wCACD,iBAAG,yBAEH,OACE,eACA,MAAK,OACL,SAAQ,4BAEL,SACC,qBAEA,wBACV,MACE,yBACA,UAAS,YAET,KACE,QAAO,mBACP,QAAO,oBAKZ;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WACI,iBACE,uBACE,KACI;AACP;AACA,CAAQ;AACR;AACA,CAAQ,kGACV;AACH", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/swc/event-tabs-breed.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/swc/event-tabs-breed.js.output.sourcemap.json index 3f46fa4..59c2eb1 100644 --- a/test/fixtures/real-project/snapshots/swc/event-tabs-breed.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/swc/event-tabs-breed.js.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "import React, { useState } from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport {\n Link, Item, ScrollView, Form, useFormProps, Alert,\n Content, Tag, Br, Button, Modal, Div, confirm,\n useFormFields$, useValidate\n} from 'startupjs-ui'\nimport { useGlobalSearchParams } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faLink } from '@fortawesome/free-solid-svg-icons/faLink'\nimport CatCard from '@/components/CatCard'\nimport { CAT_FORM } from '@/model/cats/schema'\n\nexport default observer(({ breed }) => {\n const { eventId } = useGlobalSearchParams()\n const [$selected, set$selected] = useState()\n const $new = $()\n const $showModal = $()\n const $mode = $()\n const $fields = useFormFields$(CAT_FORM)\n const validate = useValidate()\n\n function showCreate () {\n $new.set({ breed })\n $fields.breed.disabled.set(true)\n set$selected(() => $new)\n $mode.set('new')\n $showModal.set(true)\n }\n\n function showEdit ($cat) {\n $fields.breed.disabled.del()\n set$selected(() => $cat)\n $mode.set('edit')\n $showModal.set(true)\n }\n\n function cancel () {\n if (!$showModal.get()) return\n $showModal.del()\n $mode.del()\n }\n\n async function create () {\n if (!validate()) return\n await $.cats.addNew({\n ...$new.getDeepCopy(),\n eventId\n })\n cancel()\n }\n\n async function deleteCat () {\n if (!await confirm(`Are you sure you want to delete ${$selected.name.get()}?`)) return\n await $selected.del()\n cancel()\n }\n\n return pug`\n ScrollView(full)\n Content(full pure)\n CatsList(eventId=eventId onEdit=showEdit breed=breed)\n Content(padding=1)\n Button(onPress=showCreate) Add new #{breed}\n Modal(\n title=$mode.get() === 'new' ? 'Create cat' : 'Edit cat'\n $visible=$showModal\n onDismiss=cancel\n )\n - const oppositeBreed = $selected?.breed.get() && ($selected.breed.get() === 'domestic' ? 'wild' : 'domestic')\n Form(\n key=$selected?.getId() || 'NEW'\n $fields=$fields\n $value=$selected\n oppositeBreed=oppositeBreed\n eventId=eventId\n customInputs={\n likes: SelectLikesInput\n }\n validate=validate\n )\n Br\n if $mode.get() === 'new'\n Div(align='right' row)\n Button(onPress=cancel) Cancel\n Button(disabled=validate.hasErrors pushed variant='flat' color='primary' onPress=create) Create\n else if $mode.get() === 'edit'\n Div(align='right' row)\n Button(color='error' onPress=deleteCat) Delete\n `\n})\n\nconst CatsList = observer(({ onEdit, breed, eventId }) => {\n if (!eventId) return pug`Alert(variant='error') No event specified`\n const $cats = useSub($.cats, { eventId, breed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n Item(key=$cat.getId())\n CatCard($cat=$cat)\n Item.Right\n Div(vAlign='center' row gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n Button(variant='text' icon=faPen onPress=() => onEdit($cat) tooltip='Edit')\n Link(href='/events/' + eventId + '/matches/' + $cat.getId())\n Button(variant='text' icon=faHeart tooltip='Matches')\n Link(href='/cats/' + $cat.token.get())\n Button(variant='text' icon=faLink tooltip='Cat profile link') Link\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nconst SelectLikesInput = observer(({ $value, ...props }) => {\n const { oppositeBreed, eventId } = { ...useFormProps(), ...props }\n return pug`\n if oppositeBreed\n SelectLikes(\n $likes=$value\n oppositeBreed=oppositeBreed\n eventId=eventId\n )\n else\n Alert(variant='warning') Select breed to choose likes\n `\n})\n\nconst SelectLikes = observer(({ $likes, oppositeBreed, eventId }) => {\n const $cats = useSub($.cats, { eventId, breed: oppositeBreed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n - const catId = $cat.getId()\n Item.item(\n key=catId\n styleName={ selected: $likes[catId].get() }\n onPress=() => $likes[catId].get() ? $likes[catId].del() : $likes[catId].set(true)\n )\n CatCard($cat=$cat small)\n else\n Alert(variant='info') No cats with selected breed yet\n style(lang='styl')\n .item\n border-radius 1u\n &.selected\n // FIXME: We can't use color var(--color-text-success-strong) here\n background-color var(--color-text-success-strong)\n `\n})\n" ], - "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,iBACE,mBACE,kBAAiB,SAAQ,QAAO,UAAS,OAAM,iCACnD,iBAAgB,IACd,gBAAe,YAAY,SAAU,0BACvC,MACE,OAAM,mDACN,UAAS,YACT,WAAU,iBAER,wHACF,KACE,KAAI,6BACJ,SAAQ,SACR,QAAO,WACP,eAAc,eACd,SAAQ,SACR,cAAa;AACjB;AACA,OACI,UAAS,aAEX,MACG,yBACD,uBACE,gBAAe,QAAQ,gBACvB,iBAAgB,oBAAmB,+CAA8C,QAAQ,wBACrF,0BACN,uBACE,8BAA6B,WAAW,mDAC/C;AACH;AACA;AACA;AACA,yBAA2B,sBAAuB,2BAAmB;AACrE;AACA,wDACS,QAAQ,8BACX,UAAS,eACP,cAAa,SACb,YACE,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBACrB,4BAA2B,OAAM,SAAQ,oBAAmB,kBAC5D,WAAU,oDACR,4BAA2B,SAAQ,4BACrC,WAAU,8BACR,4BAA2B,QAAO,2BAA4B,6EACzE;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UACO,iBACD,YACE,QAAO,QACP,eAAc,eACd,SAAQ,eAGV,wBAAyB,qCAC5B;AACH;AACA;AACA;;IAcM;IACA;IACA;IACA;IACA;;;AAjBN;AACA,wDACS,QAAQ,qCACT,mCACF,KAEE,aAFE,OAEQ,oCADV,KAAI,OAEJ,SAAQ,4EAER,cAAa,MAAK,0EAEpB,qBAAsB,6CAOzB;AACH", + "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,iBACE,mBACE,kBAAS,SAAgB,QAAO,UAAS,OAAA,iCAC7C,iBAAgB,IACd,gBAAe,YAAY,SAAU,0BACvC,MACE,OAAM,mDACN,UAAS,YACT,WAAU,iBAER,wHACF,KACE,KAAI,6BACJ,SAAA,SACA,QAAO,WACP,eAAA,eACA,SAAA,SACA,cAAa;AACjB;AACA,OACI,UAAA,aAEF,MACG,yBACD,uBACE,gBAAe,QAAQ,gBACvB,iBAAgB,oBAAmB,+CAA8C,QAAQ,wBACrF,0BACN,uBACE,8BAA6B,WAAW,mDAC/C;AACH;AACA;AACA;AACA,yBAA2B,sBAAuB,2BAAmB;AACrE;AACA,wDACS,QAAQ,8BACX,UAAS,eACP,cAAQ,SACR,YACE,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBACrB,4BAA2B,OAAM,SAAQ,oBAAmB,kBAC5D,WAAU,oDACR,4BAA2B,SAAQ,4BACrC,WAAU,8BACR,4BAA2B,QAAO,2BAA4B,6EACzE;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UACO,iBACD,YACE,QAAO,QACP,eAAA,eACA,SAAA,eAGF,wBAAyB,qCAC5B;AACH;AACA;AACA;;IAcM;IACA;IACA;IACA;IACA;;;AAjBN;AACA,wDACS,QAAQ,qCACT,mCACF,KAEE,aAFE,OAEQ,oCADV,KAAI,OAEJ,SAAQ,4EAER,cAAQ,MAAU,0EAEpB,qBAAsB,6CAOzB;AACH", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/swc/event-tabs-breed.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/swc/event-tabs-breed.tsx.output.sourcemap.json index b79c019..ec4f8e1 100644 --- a/test/fixtures/real-project/snapshots/swc/event-tabs-breed.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/swc/event-tabs-breed.tsx.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "import React, { useState } from 'react'\nimport { pug, observer, useSub, $ } from 'startupjs'\nimport {\n Link, Item, ScrollView, Form, useFormProps, Alert,\n Content, Tag, Br, Button, Modal, Div, confirm,\n useFormFields$, useValidate\n} from 'startupjs-ui'\nimport { useGlobalSearchParams } from 'expo-router'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faLink } from '@fortawesome/free-solid-svg-icons/faLink'\nimport CatCard from '@/components/CatCard'\nimport { CAT_FORM } from '@/model/cats/schema'\n\nexport default observer(({ breed }) => {\n const { eventId } = useGlobalSearchParams()\n const [$selected, set$selected] = useState()\n const $new = $()\n const $showModal = $()\n const $mode = $()\n const $fields = useFormFields$(CAT_FORM)\n const validate = useValidate()\n\n function showCreate () {\n $new.set({ breed })\n $fields.breed.disabled.set(true)\n set$selected(() => $new)\n $mode.set('new')\n $showModal.set(true)\n }\n\n function showEdit ($cat) {\n $fields.breed.disabled.del()\n set$selected(() => $cat)\n $mode.set('edit')\n $showModal.set(true)\n }\n\n function cancel () {\n if (!$showModal.get()) return\n $showModal.del()\n $mode.del()\n }\n\n async function create () {\n if (!validate()) return\n await $.cats.addNew({\n ...$new.getDeepCopy(),\n eventId\n })\n cancel()\n }\n\n async function deleteCat () {\n if (!await confirm(`Are you sure you want to delete ${$selected.name.get()}?`)) return\n await $selected.del()\n cancel()\n }\n\n return pug`\n ScrollView(full)\n Content(full pure)\n CatsList(eventId=eventId onEdit=showEdit breed=breed)\n Content(padding=1)\n Button(onPress=showCreate) Add new #{breed}\n Modal(\n title=$mode.get() === 'new' ? 'Create cat' : 'Edit cat'\n $visible=$showModal\n onDismiss=cancel\n )\n - const oppositeBreed = $selected?.breed.get() && ($selected.breed.get() === 'domestic' ? 'wild' : 'domestic')\n Form(\n key=$selected?.getId() || 'NEW'\n $fields=$fields\n $value=$selected\n oppositeBreed=oppositeBreed\n eventId=eventId\n customInputs={\n likes: SelectLikesInput\n }\n validate=validate\n )\n Br\n if $mode.get() === 'new'\n Div(align='right' row)\n Button(onPress=cancel) Cancel\n Button(disabled=validate.hasErrors pushed variant='flat' color='primary' onPress=create) Create\n else if $mode.get() === 'edit'\n Div(align='right' row)\n Button(color='error' onPress=deleteCat) Delete\n `\n})\n\nconst CatsList = observer(({ onEdit, breed, eventId }) => {\n if (!eventId) return pug`Alert(variant='error') No event specified`\n const $cats = useSub($.cats, { eventId, breed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n Item(key=$cat.getId())\n CatCard($cat=$cat)\n Item.Right\n Div(vAlign='center' row gap=1)\n if !hasContact($cat)\n Tag(color='error') No contact\n if !$cat.photoFileId.get()\n Tag(color='error') No photo\n Button(variant='text' icon=faPen onPress=() => onEdit($cat) tooltip='Edit')\n Link(href='/events/' + eventId + '/matches/' + $cat.getId())\n Button(variant='text' icon=faHeart tooltip='Matches')\n Link(href='/cats/' + $cat.token.get())\n Button(variant='text' icon=faLink tooltip='Cat profile link') Link\n `\n})\n\nfunction hasContact ($cat) {\n return ($cat.phone.get() || '').trim() || ($cat.catgram.get() || '').trim() || ($cat.phonegram.get() || '').trim()\n}\n\nconst SelectLikesInput = observer(({ $value, ...props }) => {\n const { oppositeBreed, eventId } = { ...useFormProps(), ...props }\n return pug`\n if oppositeBreed\n SelectLikes(\n $likes=$value\n oppositeBreed=oppositeBreed\n eventId=eventId\n )\n else\n Alert(variant='warning') Select breed to choose likes\n `\n})\n\nconst SelectLikes = observer(({ $likes, oppositeBreed, eventId }) => {\n const $cats = useSub($.cats, { eventId, breed: oppositeBreed, $sort: { breed: 1, number: 1 } })\n return pug`\n each $cat in $cats\n - const catId = $cat.getId()\n Item.item(\n key=catId\n styleName={ selected: $likes[catId].get() }\n onPress=() => $likes[catId].get() ? $likes[catId].del() : $likes[catId].set(true)\n )\n CatCard($cat=$cat small)\n else\n Alert(variant='info') No cats with selected breed yet\n style(lang='styl')\n .item\n border-radius 1u\n &.selected\n // FIXME: We can't use color var(--color-text-success-strong) here\n background-color var(--color-text-success-strong)\n `\n})\n" ], - "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,iBACE,mBACE,kBAAiB,SAAQ,QAAO,UAAS,OAAM,iCACnD,iBAAgB,IACd,gBAAe,YAAY,SAAU,0BACvC,MACE,OAAM,mDACN,UAAS,YACT,WAAU,iBAER,wHACF,KACE,KAAI,6BACJ,SAAQ,SACR,QAAO,WACP,eAAc,eACd,SAAQ,SACR,cAAa;AACjB;AACA,OACI,UAAS,aAEX,MACG,yBACD,uBACE,gBAAe,QAAQ,gBACvB,iBAAgB,oBAAmB,+CAA8C,QAAQ,wBACrF,0BACN,uBACE,8BAA6B,WAAW,mDAC/C;AACH;AACA;AACA;AACA,yBAA2B,sBAAuB,2BAAmB;AACrE;AACA,wDACS,QAAQ,8BACX,UAAS,eACP,cAAa,SACb,YACE,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBACrB,4BAA2B,OAAM,SAAQ,oBAAmB,kBAC5D,WAAU,oDACR,4BAA2B,SAAQ,4BACrC,WAAU,8BACR,4BAA2B,QAAO,2BAA4B,6EACzE;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UACO,iBACD,YACE,QAAO,QACP,eAAc,eACd,SAAQ,eAGV,wBAAyB,qCAC5B;AACH;AACA;AACA;;IAcM;IACA;IACA;IACA;IACA;;;AAjBN;AACA,wDACS,QAAQ,qCACT,mCACF,KAEE,aAFE,OAEQ,oCADV,KAAI,OAEJ,SAAQ,4EAER,cAAa,MAAK,0EAEpB,qBAAsB,6CAOzB;AACH", + "mappings": "AAAA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,iBACE,mBACE,kBAAS,SAAgB,QAAO,UAAS,OAAA,iCAC7C,iBAAgB,IACd,gBAAe,YAAY,SAAU,0BACvC,MACE,OAAM,mDACN,UAAS,YACT,WAAU,iBAER,wHACF,KACE,KAAI,6BACJ,SAAA,SACA,QAAO,WACP,eAAA,eACA,SAAA,SACA,cAAa;AACjB;AACA,OACI,UAAA,aAEF,MACG,yBACD,uBACE,gBAAe,QAAQ,gBACvB,iBAAgB,oBAAmB,+CAA8C,QAAQ,wBACrF,0BACN,uBACE,8BAA6B,WAAW,mDAC/C;AACH;AACA;AACA;AACA,yBAA2B,sBAAuB,2BAAmB;AACrE;AACA,wDACS,QAAQ,8BACX,UAAS,eACP,cAAQ,SACR,YACE,6BAA4B,IACvB,qBACD,kBAAmB,yBAClB,2BACD,kBAAmB,uBACrB,4BAA2B,OAAM,SAAQ,oBAAmB,kBAC5D,WAAU,oDACR,4BAA2B,SAAQ,4BACrC,WAAU,8BACR,4BAA2B,QAAO,2BAA4B,6EACzE;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UACO,iBACD,YACE,QAAO,QACP,eAAA,eACA,SAAA,eAGF,wBAAyB,qCAC5B;AACH;AACA;AACA;;IAcM;IACA;IACA;IACA;IACA;;;AAjBN;AACA,wDACS,QAAQ,qCACT,mCACF,KAEE,aAFE,OAEQ,oCADV,KAAI,OAEJ,SAAQ,4EAER,cAAQ,MAAU,0EAEpB,qBAAsB,6CAOzB;AACH", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/swc/event-tabs-layout.js.output.sourcemap.json b/test/fixtures/real-project/snapshots/swc/event-tabs-layout.js.output.sourcemap.json index 8a020cb..16689a4 100644 --- a/test/fixtures/real-project/snapshots/swc/event-tabs-layout.js.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/swc/event-tabs-layout.js.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "// import { Platform } from 'react-native'\nimport React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { useColors, Icon, Form, Modal, Button } from 'startupjs-ui'\nimport { Tabs, useLocalSearchParams, Stack } from 'expo-router'\nimport { faVenus as faWildBadge } from '@fortawesome/free-solid-svg-icons/faVenus'\nimport { faMars as faDomesticBadge } from '@fortawesome/free-solid-svg-icons/faMars'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faToolbox } from '@fortawesome/free-solid-svg-icons/faToolbox'\nimport { EVENT_FORM } from '@/model/events/schema'\n\nexport default observer(function TabLayout () {\n const getColor = useColors()\n const { eventId } = useLocalSearchParams()\n const $event = useSub($.events[eventId])\n if (!$event.get()) throw Error('No such event')\n\n // NOTE:\n // headerShown -- Disable the static render of the header on web to prevent a hydration error in React Navigation v6.\n // tabBarStyle/order - Move the tab bar to the top on tablet+\n return pug`\n Stack.Screen(\n options={\n title: $event.name.get(),\n headerRight: () => renderEditEvent({ $event })\n }\n )\n Tabs(\n title=$event.name.get()\n screenOptions={\n ...styl('screen'),\n tabBarActiveTintColor: getColor('primary'),\n tabBarActiveBackgroundColor: 'rgba(255, 255, 255, 0.5)',\n headerShown: false,\n headerTitle: $event.name.get()\n }\n )\n Tabs.Screen(\n name='index'\n options={\n title: 'Dashboard',\n tabBarIcon: renderHomeIcon\n }\n )\n Tabs.Screen(\n name='-breed'\n options={\n href: null\n }\n )\n Tabs.Screen(\n name='domestic'\n options={\n title: 'Domestic Cats',\n tabBarIcon: renderDomesticIcon\n }\n )\n Tabs.Screen(\n name='wild'\n options={\n title: 'Wild Cats',\n tabBarIcon: renderWildIcon\n }\n )\n Tabs.Screen(\n name='test'\n options={\n title: 'Dev Only',\n tabBarIcon: renderTestIcon\n }\n )\n style(lang='styl')\n +tablet()\n .screen\n &:part(tabBar)\n order -1\n background-color transparent\n border-bottom-width 1px\n border-bottom-color rgba(0, 0, 0, 0.1)\n `\n})\n\nfunction renderEditEvent ({ $event }) {\n return pug`\n EditEvent($event=$event)\n `\n}\n\nconst EditEvent = observer(({ $event }) => {\n const $showModal = $()\n return pug`\n Button(onPress=() => $showModal.set(true) variant='text' icon=faPen) Edit this cat meetup\n Modal(\n title='Edit cat meetup'\n $visible=$showModal\n )\n Form(\n $value=$event\n fields=EVENT_FORM\n )\n `\n})\n\nfunction renderWildIcon ({ color, size }) {\n return pug`\n Icon(icon=faWildBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderDomesticIcon ({ color, size }) {\n return pug`\n Icon(icon=faDomesticBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderHomeIcon ({ color, size }) {\n return pug`\n Icon(icon=faHeart style={ color, width: size, height: size })\n `\n}\n\nfunction renderTestIcon ({ color, size }) {\n return pug`\n Icon(icon=faToolbox style={ color, width: size, height: size })\n `\n}\n" ], - "mappings": "AAAA;AACA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;IA6DM;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlEN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,KACE,OAAM,mBACN,eAAc;AAChB;AACA;AACA;AACA;AACA;AACA,MAEE,YACE,aACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,cACA,SAAQ;AACZ;AACA,UAEE,YACE,gBACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,oBAUD;AACH;AACA;AACA;AACA,WACI,kBAAiB,WAClB;AACH;AACA;AACA;AACA;AACA,aACI,gBAAe,4BAA2B,qBAAoB,OAAO,8BACrE,MACE,wBACA,UAAS,aAET,KACE,QAAO,QACP,QAAO,0BAEZ;AACH;AACA;AACA;AACA,WACI,WAAU,aAAY,OAAM,yCAC7B;AACH;AACA;AACA;AACA,WACI,WAAU,iBAAgB,OAAM,yCACjC;AACH;AACA;AACA;AACA,WACI,WAAU,SAAQ,OAAM,yCACzB;AACH;AACA;AACA;AACA,WACI,WAAU,WAAU,OAAM,yCAC3B;AACH", + "mappings": "AAAA;AACA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;IA6DM;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlEN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,KACE,OAAM,mBACN,eAAc;AAChB;AACA;AACA;AACA;AACA;AACA,MAEE,YACE,aACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,cACA,SAAQ;AACZ;AACA,UAEE,YACE,gBACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,oBAUD;AACH;AACA;AACA;AACA,WACI,kBAAU,WACX;AACH;AACA;AACA;AACA;AACA,aACI,gBAAe,4BAA2B,qBAAoB,OAAO,8BACrE,MACE,wBACA,UAAS,aAET,KACE,QAAO,QACP,QAAO,0BAEZ;AACH;AACA;AACA;AACA,WACI,WAAU,aAAY,OAAM,yCAC7B;AACH;AACA;AACA;AACA,WACI,WAAU,iBAAgB,OAAM,yCACjC;AACH;AACA;AACA;AACA,WACI,WAAU,SAAQ,OAAM,yCACzB;AACH;AACA;AACA;AACA,WACI,WAAU,WAAU,OAAM,yCAC3B;AACH", "ignoreList": [] } \ No newline at end of file diff --git a/test/fixtures/real-project/snapshots/swc/event-tabs-layout.tsx.output.sourcemap.json b/test/fixtures/real-project/snapshots/swc/event-tabs-layout.tsx.output.sourcemap.json index 8dbf3d1..1453c9e 100644 --- a/test/fixtures/real-project/snapshots/swc/event-tabs-layout.tsx.output.sourcemap.json +++ b/test/fixtures/real-project/snapshots/swc/event-tabs-layout.tsx.output.sourcemap.json @@ -8,6 +8,6 @@ "sourcesContent": [ "// import { Platform } from 'react-native'\nimport React from 'react'\nimport { pug, observer, $, useSub } from 'startupjs'\nimport { useColors, Icon, Form, Modal, Button } from 'startupjs-ui'\nimport { Tabs, useLocalSearchParams, Stack } from 'expo-router'\nimport { faVenus as faWildBadge } from '@fortawesome/free-solid-svg-icons/faVenus'\nimport { faMars as faDomesticBadge } from '@fortawesome/free-solid-svg-icons/faMars'\nimport { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart'\nimport { faPen } from '@fortawesome/free-solid-svg-icons/faPen'\nimport { faToolbox } from '@fortawesome/free-solid-svg-icons/faToolbox'\nimport { EVENT_FORM } from '@/model/events/schema'\n\nexport default observer(function TabLayout () {\n const getColor = useColors()\n const { eventId } = useLocalSearchParams()\n const $event = useSub($.events[eventId])\n if (!$event.get()) throw Error('No such event')\n\n // NOTE:\n // headerShown -- Disable the static render of the header on web to prevent a hydration error in React Navigation v6.\n // tabBarStyle/order - Move the tab bar to the top on tablet+\n return pug`\n Stack.Screen(\n options={\n title: $event.name.get(),\n headerRight: () => renderEditEvent({ $event })\n }\n )\n Tabs(\n title=$event.name.get()\n screenOptions={\n ...styl('screen'),\n tabBarActiveTintColor: getColor('primary'),\n tabBarActiveBackgroundColor: 'rgba(255, 255, 255, 0.5)',\n headerShown: false,\n headerTitle: $event.name.get()\n }\n )\n Tabs.Screen(\n name='index'\n options={\n title: 'Dashboard',\n tabBarIcon: renderHomeIcon\n }\n )\n Tabs.Screen(\n name='-breed'\n options={\n href: null\n }\n )\n Tabs.Screen(\n name='domestic'\n options={\n title: 'Domestic Cats',\n tabBarIcon: renderDomesticIcon\n }\n )\n Tabs.Screen(\n name='wild'\n options={\n title: 'Wild Cats',\n tabBarIcon: renderWildIcon\n }\n )\n Tabs.Screen(\n name='test'\n options={\n title: 'Dev Only',\n tabBarIcon: renderTestIcon\n }\n )\n style(lang='styl')\n +tablet()\n .screen\n &:part(tabBar)\n order -1\n background-color transparent\n border-bottom-width 1px\n border-bottom-color rgba(0, 0, 0, 0.1)\n `\n})\n\nfunction renderEditEvent ({ $event }) {\n return pug`\n EditEvent($event=$event)\n `\n}\n\nconst EditEvent = observer(({ $event }) => {\n const $showModal = $()\n return pug`\n Button(onPress=() => $showModal.set(true) variant='text' icon=faPen) Edit this cat meetup\n Modal(\n title='Edit cat meetup'\n $visible=$showModal\n )\n Form(\n $value=$event\n fields=EVENT_FORM\n )\n `\n})\n\nfunction renderWildIcon ({ color, size }) {\n return pug`\n Icon(icon=faWildBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderDomesticIcon ({ color, size }) {\n return pug`\n Icon(icon=faDomesticBadge style={ color, width: size, height: size })\n `\n}\n\nfunction renderHomeIcon ({ color, size }) {\n return pug`\n Icon(icon=faHeart style={ color, width: size, height: size })\n `\n}\n\nfunction renderTestIcon ({ color, size }) {\n return pug`\n Icon(icon=faToolbox style={ color, width: size, height: size })\n `\n}\n" ], - "mappings": "AAAA;AACA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;IA6DM;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlEN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,KACE,OAAM,mBACN,eAAc;AAChB;AACA;AACA;AACA;AACA;AACA,MAEE,YACE,aACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,cACA,SAAQ;AACZ;AACA,UAEE,YACE,gBACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,oBAUD;AACH;AACA;AACA;AACA,WACI,kBAAiB,WAClB;AACH;AACA;AACA;AACA;AACA,aACI,gBAAe,4BAA2B,qBAAoB,OAAO,8BACrE,MACE,wBACA,UAAS,aAET,KACE,QAAO,QACP,QAAO,0BAEZ;AACH;AACA;AACA;AACA,WACI,WAAU,aAAY,OAAM,yCAC7B;AACH;AACA;AACA;AACA,WACI,WAAU,iBAAgB,OAAM,yCACjC;AACH;AACA;AACA;AACA,WACI,WAAU,SAAQ,OAAM,yCACzB;AACH;AACA;AACA;AACA,WACI,WAAU,WAAU,OAAM,yCAC3B;AACH", + "mappings": "AAAA;AACA;qDACoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;IA6DM;IACA;IACA;IACA;IACA;IACA;IACA;;;AAlEN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aACI,aACE,SAAQ;AACV;AACA;AACA,QAEA,KACE,OAAM,mBACN,eAAc;AAChB;AACA;AACA;AACA;AACA;AACA,MAEE,YACE,aACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,cACA,SAAQ;AACZ;AACA,UAEE,YACE,gBACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,UAEE,YACE,YACA,SAAQ;AACZ;AACA;AACA,oBAUD;AACH;AACA;AACA;AACA,WACI,kBAAU,WACX;AACH;AACA;AACA;AACA;AACA,aACI,gBAAe,4BAA2B,qBAAoB,OAAO,8BACrE,MACE,wBACA,UAAS,aAET,KACE,QAAO,QACP,QAAO,0BAEZ;AACH;AACA;AACA;AACA,WACI,WAAU,aAAY,OAAM,yCAC7B;AACH;AACA;AACA;AACA,WACI,WAAU,iBAAgB,OAAM,yCACjC;AACH;AACA;AACA;AACA,WACI,WAAU,SAAQ,OAAM,yCACzB;AACH;AACA;AACA;AACA,WACI,WAAU,WAAU,OAAM,yCAC3B;AACH", "ignoreList": [] } \ No newline at end of file From 384247bfd52ce473689cede67195e8bc16ee1311 Mon Sep 17 00:00:00 2001 From: Pavel Zhukov Date: Wed, 15 Apr 2026 20:48:29 +0300 Subject: [PATCH 5/9] docs: clarify eslint processor fix mapping contract --- README.md | 4 +++- packages/eslint-plugin-react-pug/README.md | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f87250e..c94184c 100644 --- a/README.md +++ b/README.md @@ -125,13 +125,15 @@ ESLint processor behavior: - real JS/TS diagnostics inside Pug expression sites such as `#{...}`, `${...}`, `tag= ...`, attribute expressions, and inline handler/function bodies are mapped back to the original Pug source - formatting diagnostics for those embedded expression sites are linted against source-faithful JS wrappers rather than only against generated JSX +- autofixes and suggestions for those embedded expression sites are mapped back to the original Pug source - diagnostics that originate only from synthetic generated helper code are filtered out - the processor formats against the project's own `@stylistic` package when available so generated JSX converges to the same style engine the outer ESLint run uses Current limitation: - multiline unbuffered `- ...` statements that are authored across several Pug lines do not yet get the same source-faithful formatting-diagnostic surface as embedded expression sites -- autofixes and suggestions are currently not mapped back for files that contain transformed Pug regions, so transformed-region diagnostics are report-only today +- diagnostics that arise only on the generated JSX surface of a transformed Pug region still do not map autofixes back; those remain report-only unless they come from an embedded source-faithful JS site +- the internal formatter still relies on deprecated `@stylistic/jsx-indent` / `@stylistic/jsx-indent-props` compatibility rules, so some dependency graphs may emit a one-time deprecation warning during an ESLint run ## VS Code Settings diff --git a/packages/eslint-plugin-react-pug/README.md b/packages/eslint-plugin-react-pug/README.md index 6aec0e9..8e7cd23 100644 --- a/packages/eslint-plugin-react-pug/README.md +++ b/packages/eslint-plugin-react-pug/README.md @@ -46,13 +46,15 @@ The processor is designed to preserve useful JavaScript/TypeScript diagnostics i - real JS/TS rule violations inside `#{...}`, `${...}`, `tag= ...`, attribute expressions, and inline handler/function bodies are reported back at the original Pug location - formatting diagnostics for those embedded expression sites are linted against source-faithful JS wrappers rather than only against generated JSX +- autofixes and suggestions for those embedded expression sites are mapped back to the original Pug source - diagnostics caused only by synthetic generated helper code are filtered out - the formatter tries to converge to the consuming project's own `@stylistic` setup when that package is available locally Current limitation: - multiline unbuffered `- ...` statements that are authored across several Pug lines do not yet get the same source-faithful formatting-diagnostic surface as embedded expression sites -- autofixes and suggestions are currently not mapped back for files that contain transformed Pug regions, so transformed-region diagnostics are report-only today +- diagnostics that arise only on the generated JSX surface of a transformed Pug region still do not map autofixes back; those remain report-only unless they come from an embedded source-faithful JS site +- the internal formatter still relies on deprecated `@stylistic/jsx-indent` / `@stylistic/jsx-indent-props` compatibility rules, so some dependency graphs may emit a one-time deprecation warning during an ESLint run ## Exports From 006c48132b3f5e3648fbe2c103da22daca4c1670 Mon Sep 17 00:00:00 2001 From: Pavel Zhukov Date: Wed, 15 Apr 2026 23:40:43 +0300 Subject: [PATCH 6/9] fix: support multiline embedded expression carriers --- packages/eslint-plugin-react-pug/src/index.ts | 12 +- .../test/integration/diagnostics.test.ts | 4 +- packages/pug-lexer/index.js | 99 +++++- packages/pug-lexer/test/multiline.test.js | 136 ++++++++ packages/pug-lexer/test/typescript.test.js | 46 +++ .../react-pug-core/src/language/pugToTsx.ts | 258 ++++++++++++++ .../react-pug-core/test/unit/pugToTsx.test.ts | 328 ++++++++++-------- plan.md | 5 + 8 files changed, 731 insertions(+), 157 deletions(-) create mode 100644 packages/pug-lexer/test/multiline.test.js diff --git a/packages/eslint-plugin-react-pug/src/index.ts b/packages/eslint-plugin-react-pug/src/index.ts index eaa1d74..c2d6f20 100644 --- a/packages/eslint-plugin-react-pug/src/index.ts +++ b/packages/eslint-plugin-react-pug/src/index.ts @@ -89,6 +89,9 @@ interface EslintProcessorLike { const FLAT_LINT_FILES = ['**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}']; const LEGACY_STYLE_HELPERS = new Set(['styl', 'css', 'sass', 'scss']); const LEGACY_STYLE_SUPPRESSED_RULES = new Set(['no-unused-expressions', 'no-unreachable']); +const EMBEDDED_BLOCK_RULE_ALLOWLIST = new Set([ + '@typescript-eslint/no-unused-vars', +]); const stylisticPluginCache = new Map(); const FORMAT_RULE_CONFIG: any = { languageOptions: { @@ -1027,7 +1030,14 @@ function mapEmbeddedLintMessage( includeSuggestions?: boolean; } = {}, ): EslintLintMessage | null { - if (typeof message.ruleId !== 'string' || !message.ruleId.startsWith('@stylistic/')) { + if ( + typeof message.ruleId === 'string' + && !message.ruleId.startsWith('@stylistic/') + && ( + !EMBEDDED_BLOCK_RULE_ALLOWLIST.has(message.ruleId) + || block.site.kind !== 'expression' + ) + ) { return null; } if (message.line == null || message.column == null) return null; diff --git a/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts b/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts index 4b708ec..49c3909 100644 --- a/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts +++ b/packages/eslint-plugin-react-pug/test/integration/diagnostics.test.ts @@ -316,7 +316,7 @@ describe('eslint processor diagnostic mapping', () => { expectExactMappedMessage(input, result.messages, 'no-undef', 'missingStatementValue') }) - it.fails('maps exact @typescript-eslint/no-unused-vars ranges across complex embedded TS expression sites', async () => { + it('maps exact @typescript-eslint/no-unused-vars ranges across complex embedded TS expression sites', async () => { const filePath = resolve(repoRoot, 'embedded-ts-site-matrix.tsx') const input = [ "import { pug } from 'startupjs'", @@ -360,7 +360,7 @@ describe('eslint processor diagnostic mapping', () => { expectExactMappedMessage(input, result.messages, '@typescript-eslint/no-unused-vars', 'unusedTemplateValue') }) - it.fails('reports source-faithful indent diagnostics across the embedded expression-site matrix without synthetic noise', async () => { + it('reports source-faithful indent diagnostics across the embedded expression-site matrix without synthetic noise', async () => { const filePath = resolve(repoRoot, 'embedded-style-matrix.js') const lines = [ "import { pug } from 'startupjs'", diff --git a/packages/pug-lexer/index.js b/packages/pug-lexer/index.js index 681e22c..470fbf7 100644 --- a/packages/pug-lexer/index.js +++ b/packages/pug-lexer/index.js @@ -30,6 +30,23 @@ function startsWithTypeScriptContinuation(str, index, whitespaceRe) { return true; } +function hasOpenJavaScriptSyntax(str) { + var state = characterParser.default(str); + return state.isNesting() || state.isString(); +} + +function endsWithJavaScriptContinuation(str) { + var trimmed = str.replace(/[ \t]+$/, ''); + return /(?:=>|[([{,:?+\-*/%&|^=!<>]|\b(?:as|satisfies|in|instanceof)\b)$/.test(trimmed); +} + +function startsWithJavaScriptContinuationLine(str) { + var trimmed = str.trim(); + if (!trimmed) return false; + + return /^(?:\?|:|&&|\|\||\?\?|as\b|satisfies\b|instanceof\b|in\b)/.test(trimmed); +} + /** * Initialize `Lexer` with the given `str`. * @@ -127,6 +144,48 @@ Lexer.prototype = { } }, + incrementPositionByText: function(text) { + var lines = text.split('\n'); + var newlineCount = lines.length - 1; + if (newlineCount === 0) { + this.incrementColumn(text.length); + return; + } + + this.incrementLine(newlineCount); + this.incrementColumn(lines[newlineCount].length); + }, + + collectMultilineCodeFragment: function(startIndex, initialCode) { + var consumed = startIndex + initialCode.length; + var code = initialCode; + + while (consumed < this.input.length && this.input[consumed] === '\n') { + var nextLineStart = consumed + 1; + var nextLineEnd = this.input.indexOf('\n', nextLineStart); + if (nextLineEnd === -1) { + nextLineEnd = this.input.length; + } + var nextLine = this.input.slice(nextLineStart, nextLineEnd); + var shouldContinue = + hasOpenJavaScriptSyntax(code) || + endsWithJavaScriptContinuation(code) || + startsWithJavaScriptContinuationLine(nextLine); + + if (!shouldContinue) { + break; + } + + code += this.input.slice(consumed, nextLineEnd); + consumed = nextLineEnd; + } + + return { + code: code, + consumed: consumed, + }; + }, + /** * Construct a token with the given `type` and `val`. * @@ -619,11 +678,12 @@ Lexer.prototype = { } var rest = matchOfStringInterp[3]; + var fullRest = rest + this.input; var range; tok = this.tok('interpolated-code'); this.incrementColumn(2); try { - range = characterParser.parseUntil(rest, '}'); + range = characterParser.parseUntil(fullRest, '}'); } catch (ex) { if (ex.index !== undefined) { this.incrementColumn(ex.index); @@ -643,15 +703,24 @@ Lexer.prototype = { tok.buffer = true; tok.val = range.src; this.assertExpression(range.src); + var consumedFromRest = range.end + 1; + var extraInputConsumed = Math.max(0, consumedFromRest - rest.length); + var tailInValue = + consumedFromRest < rest.length ? rest.substr(consumedFromRest) : ''; - if (range.end + 1 < rest.length) { - rest = rest.substr(range.end + 1); - this.incrementColumn(range.end + 1); - this.tokens.push(this.tokEnd(tok)); - this.addText(type, rest); - } else { - this.incrementColumn(rest.length); - this.tokens.push(this.tokEnd(tok)); + this.input = this.input.substr(extraInputConsumed); + this.incrementPositionByText(range.src); + this.incrementColumn(1); + this.tokens.push(this.tokEnd(tok)); + + var tailFromInput = ''; + if (this.input.length && this.input[0] !== '\n' && this.input[0] !== ']') { + tailFromInput = /^[^\n\]]*/.exec(this.input)[0]; + this.consume(tailFromInput.length); + } + + if (tailInValue || tailFromInput) { + this.addText(type, tailInValue + tailFromInput); } return; } @@ -1153,6 +1222,8 @@ Lexer.prototype = { var flags = captures[1]; var code = captures[2]; var shortened = 0; + var prefixLength = captures[0].length - captures[2].length; + var consumed = captures[0].length; if (this.interpolated) { var parsed; try { @@ -1174,8 +1245,12 @@ Lexer.prototype = { } shortened = code.length - parsed.end; code = parsed.src; + consumed -= shortened; + } else if (flags.charAt(0) === '=' || flags.charAt(1) === '=') { + var collected = this.collectMultilineCodeFragment(prefixLength, code); + code = collected.code; + consumed = collected.consumed; } - var consumed = captures[0].length - shortened; this.consume(consumed); var tok = this.tok('code', code); tok.mustEscape = flags.charAt(0) === '='; @@ -1194,7 +1269,7 @@ Lexer.prototype = { // --- captures[2] // ---- captures[0] - captures[2] // ^ after colno - this.incrementColumn(captures[0].length - captures[2].length); + this.incrementColumn(prefixLength); if (tok.buffer) this.assertExpression(code); this.tokens.push(tok); @@ -1209,7 +1284,7 @@ Lexer.prototype = { // shortened // --- code // ^ after colno - this.incrementColumn(code.length); + this.incrementPositionByText(code); this.tokEnd(tok); return true; } diff --git a/packages/pug-lexer/test/multiline.test.js b/packages/pug-lexer/test/multiline.test.js new file mode 100644 index 0000000..3996b83 --- /dev/null +++ b/packages/pug-lexer/test/multiline.test.js @@ -0,0 +1,136 @@ +'use strict'; + +const lex = require('../'); + +function findToken(tokens, type) { + return tokens.find(token => token.type === type); +} + +test('supports multiline buffered pure-JS expressions on code lines', () => { + const tokens = lex( + [ + 'p= ready', + " ? formatLabel('yes')", + " : formatLabel('no')", + ].join('\n'), + { filename: 'multiline-buffered-js.pug' }, + ); + + expect(findToken(tokens, 'code')).toEqual( + expect.objectContaining({ + val: [ + 'ready', + " ? formatLabel('yes')", + " : formatLabel('no')", + ].join('\n'), + }), + ); +}); + +test('supports multiline buffered TypeScript expressions with continuation keywords', () => { + const tokens = lex( + [ + 'p= ({', + ' label: value,', + '}) satisfies CardConfig', + ].join('\n'), + { filename: 'multiline-buffered-ts-keyword.pug' }, + ); + + expect(findToken(tokens, 'code')).toEqual( + expect.objectContaining({ + val: [ + '({', + ' label: value,', + '}) satisfies CardConfig', + ].join('\n'), + }), + ); +}); + +test('supports multiline text interpolation with nested objects and trailing text', () => { + const tokens = lex( + [ + 'p Hello #{(() => {', + " const value = { label: 'hi' }", + ' return value.label', + '})()} world', + ].join('\n'), + { filename: 'multiline-interpolation-js.pug' }, + ); + + expect(tokens).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + type: 'interpolated-code', + val: [ + '(() => {', + " const value = { label: 'hi' }", + ' return value.label', + '})()', + ].join('\n'), + }), + expect.objectContaining({ + type: 'text', + val: ' world', + }), + ]), + ); +}); + +test('supports multiline text interpolation with TypeScript syntax', () => { + const tokens = lex( + [ + 'p Hello #{(() => {', + ' const value = known as string', + ' return value', + '})()} world', + ].join('\n'), + { filename: 'multiline-interpolation-ts.pug' }, + ); + + expect(findToken(tokens, 'interpolated-code')).toEqual( + expect.objectContaining({ + val: [ + '(() => {', + ' const value = known as string', + ' return value', + '})()', + ].join('\n'), + }), + ); +}); + +test('keeps existing unbuffered code-block semantics with nested pug children', () => { + const tokens = lex( + [ + '- if (ready) {', + ' p yes', + '- }', + ].join('\n'), + { filename: 'multiline-unbuffered-js.pug' }, + ); + + expect(tokens).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + type: 'code', + val: 'if (ready) {', + buffer: false, + }), + expect.objectContaining({ + type: 'tag', + val: 'p', + }), + expect.objectContaining({ + type: 'text', + val: 'yes', + }), + expect.objectContaining({ + type: 'code', + val: '}', + buffer: false, + }), + ]), + ); +}); diff --git a/packages/pug-lexer/test/typescript.test.js b/packages/pug-lexer/test/typescript.test.js index 547eda0..af11423 100644 --- a/packages/pug-lexer/test/typescript.test.js +++ b/packages/pug-lexer/test/typescript.test.js @@ -100,3 +100,49 @@ test('supports TypeScript syntax in conditionals, loops, interpolation, and hand }), ); }); + +test('supports multiline buffered TypeScript expressions on code lines', () => { + const tokens = lex( + [ + 'p= (() => {', + ' const value = known as string', + ' return value', + '})()', + ].join('\n'), + { filename: 'multiline-buffered-expression.pug' }, + ); + + expect(tokens).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + type: 'code', + val: ['(() => {', ' const value = known as string', ' return value', '})()'].join('\n'), + }), + ]), + ); +}); + +test('supports multiline TypeScript interpolations inside text', () => { + const tokens = lex( + [ + 'p Hello #{(() => {', + ' const value = known as string', + ' return value', + '})()} world', + ].join('\n'), + { filename: 'multiline-interpolation.pug' }, + ); + + expect(tokens).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + type: 'interpolated-code', + val: ['(() => {', ' const value = known as string', ' return value', '})()'].join('\n'), + }), + expect.objectContaining({ + type: 'text', + val: ' world', + }), + ]), + ); +}); diff --git a/packages/react-pug-core/src/language/pugToTsx.ts b/packages/react-pug-core/src/language/pugToTsx.ts index f7b7ad0..c2e5833 100644 --- a/packages/react-pug-core/src/language/pugToTsx.ts +++ b/packages/react-pug-core/src/language/pugToTsx.ts @@ -380,6 +380,7 @@ function findInterpolationEnd(text: string, exprStart: number): number | null { let inLineComment = false; let inBlockComment = false; let escaped = false; + const templateExpressionDepths: number[] = []; while (i < text.length) { const ch = text[i]; @@ -433,7 +434,9 @@ function findInterpolationEnd(text: string, exprStart: number): number | null { } else if (ch === '`') { inTemplate = false; } else if (ch === '$' && next === '{') { + templateExpressionDepths.push(depth); depth += 1; + inTemplate = false; i += 2; continue; } @@ -474,6 +477,13 @@ function findInterpolationEnd(text: string, exprStart: number): number | null { if (ch === '}') { depth -= 1; if (depth === 0) return i; + if ( + templateExpressionDepths.length > 0 + && templateExpressionDepths[templateExpressionDepths.length - 1] === depth + ) { + templateExpressionDepths.pop(); + inTemplate = true; + } i += 1; continue; } @@ -654,6 +664,251 @@ function recordEmbeddedJsLintSite( }); } +function canParseEmbeddedExpression(text: string): boolean { + try { + parseExpression(text, { + plugins: ['jsx', 'decorators-legacy', 'typescript'], + }); + return true; + } catch { + return false; + } +} + +function getJavaScriptDelimiterBalance(text: string): { + paren: number; + brace: number; + bracket: number; +} { + let paren = 0; + let brace = 0; + let bracket = 0; + let i = 0; + let inSingle = false; + let inDouble = false; + let inTemplate = false; + let inLineComment = false; + let inBlockComment = false; + let escaped = false; + + while (i < text.length) { + const ch = text[i]; + const next = text[i + 1] ?? ''; + + if (inLineComment) { + if (ch === '\n') inLineComment = false; + i += 1; + continue; + } + + if (inBlockComment) { + if (ch === '*' && next === '/') { + inBlockComment = false; + i += 2; + } else { + i += 1; + } + continue; + } + + if (inSingle) { + if (escaped) escaped = false; + else if (ch === '\\') escaped = true; + else if (ch === '\'') inSingle = false; + i += 1; + continue; + } + + if (inDouble) { + if (escaped) escaped = false; + else if (ch === '\\') escaped = true; + else if (ch === '"') inDouble = false; + i += 1; + continue; + } + + if (inTemplate) { + if (escaped) { + escaped = false; + } else if (ch === '\\') { + escaped = true; + } else if (ch === '`') { + inTemplate = false; + } + i += 1; + continue; + } + + if (ch === '/' && next === '/') { + inLineComment = true; + i += 2; + continue; + } + if (ch === '/' && next === '*') { + inBlockComment = true; + i += 2; + continue; + } + if (ch === '\'') { + inSingle = true; + i += 1; + continue; + } + if (ch === '"') { + inDouble = true; + i += 1; + continue; + } + if (ch === '`') { + inTemplate = true; + i += 1; + continue; + } + + if (ch === '(') paren += 1; + else if (ch === ')') paren = Math.max(0, paren - 1); + else if (ch === '{') brace += 1; + else if (ch === '}') brace = Math.max(0, brace - 1); + else if (ch === '[') bracket += 1; + else if (ch === ']') bracket = Math.max(0, bracket - 1); + + i += 1; + } + + return { paren, brace, bracket }; +} + +function hasOpenJavaScriptDelimiters(text: string): boolean { + const balance = getJavaScriptDelimiterBalance(text); + return balance.paren > 0 || balance.brace > 0 || balance.bracket > 0; +} + +function lineStartOffsets(text: string): number[] { + const starts = [0]; + for (let i = 0; i < text.length; i += 1) { + if (text[i] === '\n' && i + 1 < text.length) starts.push(i + 1); + } + return starts; +} + +function looksLikeTagAttrListStart(trimmedLine: string): boolean { + return /^[A-Za-z_$][\w$]*(?:[.:][A-Za-z_$][\w$-]*)*(?:[.#][A-Za-z_$][\w-]*)*\s*\($/.test(trimmedLine); +} + +function collectRawEmbeddedExpressionSite( + lines: string[], + starts: number[], + startLineIndex: number, + startColumn: number, +): { text: string; sourceStart: number; endLineIndex: number } { + const baseIndent = countIndent(lines[startLineIndex]); + let endLineIndex = startLineIndex; + let text = lines[startLineIndex].slice(startColumn); + + while (endLineIndex + 1 < lines.length) { + if (canParseEmbeddedExpression(text) && !hasOpenJavaScriptDelimiters(text)) break; + + const nextLineIndex = endLineIndex + 1; + const nextLine = lines[nextLineIndex]; + const nextTrimmed = nextLine.trim(); + const nextIndent = countIndent(nextLine); + const shouldContinue = ( + nextTrimmed.length === 0 + || nextIndent > baseIndent + || hasOpenJavaScriptDelimiters(text) + || nextTrimmed.startsWith(')') + || nextTrimmed.startsWith(']') + || nextTrimmed.startsWith('}') + || nextTrimmed.startsWith('?') + || nextTrimmed.startsWith(':') + ); + + if (!shouldContinue) break; + + text += `\n${nextLine}`; + endLineIndex = nextLineIndex; + } + + return { + text, + sourceStart: starts[startLineIndex] + startColumn, + endLineIndex, + }; +} + +function extractEmbeddedJsLintSitesFromRawPugText(pugText: string): void { + // This is a recovery-only path. Valid multiline embedded expressions should + // be handled by the vendored pug lexer/parser directly. We keep this raw scan + // only so ESLint can still surface source-faithful embedded-JS diagnostics + // while the template is malformed or temporarily incomplete during typing. + for (let i = 0; i < pugText.length; i += 1) { + const marker = pugText[i]; + if ((marker === '#' || marker === '!') && pugText[i + 1] === '{') { + const exprStart = i + 2; + const exprEnd = findInterpolationEnd(pugText, exprStart); + if (exprEnd != null) { + recordEmbeddedJsLintSite('expression', pugText.slice(exprStart, exprEnd), exprStart); + i = exprEnd; + } + } + } + + const lines = pugText.split('\n'); + const starts = lineStartOffsets(pugText); + let inAttrList = false; + + for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) { + const line = lines[lineIndex]; + const trimmed = line.trim(); + if (trimmed.length === 0) continue; + + if (inAttrList) { + if (trimmed.startsWith(')')) { + inAttrList = false; + continue; + } + + const attrMatch = line.match(/^\s*([A-Za-z_$][\w:$-]*)\s*=\s*(.*)$/); + if (attrMatch) { + const equalsIndex = line.indexOf('='); + let startColumn = equalsIndex + 1; + while (startColumn < line.length && /\s/u.test(line[startColumn])) startColumn += 1; + const site = collectRawEmbeddedExpressionSite(lines, starts, lineIndex, startColumn); + recordEmbeddedJsLintSite('expression', site.text, site.sourceStart); + lineIndex = site.endLineIndex; + if (lines[lineIndex]?.trim().startsWith(')')) inAttrList = false; + continue; + } + + continue; + } + + if (looksLikeTagAttrListStart(trimmed)) { + inAttrList = true; + continue; + } + + const statementMatch = line.match(/^\s*-\s+(.*)$/); + if (statementMatch) { + const startColumn = line.indexOf('-') + 2; + const site = collectRawEmbeddedExpressionSite(lines, starts, lineIndex, startColumn); + recordEmbeddedJsLintSite('statement', site.text, site.sourceStart); + lineIndex = site.endLineIndex; + continue; + } + + const bufferedMatch = line.match(/^\s*([A-Za-z_$][\w$]*(?:[.:][A-Za-z_$][\w$-]*)*(?:[.#][A-Za-z_$][\w-]*)*)\s*=\s*(.*)$/); + if (bufferedMatch) { + const equalsIndex = line.indexOf('='); + let startColumn = equalsIndex + 1; + while (startColumn < line.length && /\s/u.test(line[startColumn])) startColumn += 1; + const site = collectRawEmbeddedExpressionSite(lines, starts, lineIndex, startColumn); + recordEmbeddedJsLintSite('expression', site.text, site.sourceStart); + lineIndex = site.endLineIndex; + } + } +} + function countIndent(line: string): number { return line.match(/^(\s*)/)?.[1].length ?? 0; } @@ -1986,6 +2241,7 @@ export function compilePugToTsx(pugText: string, options: CompileOptions = {}): try { tokens = lex(recoveredText, { filename: 'template.pug' }); } catch { + extractEmbeddedJsLintSitesFromRawPugText(pugTextForParse); return { tsx: fallbackNullExpression(mode), mappings: [], @@ -1997,6 +2253,7 @@ export function compilePugToTsx(pugText: string, options: CompileOptions = {}): }; } } else { + extractEmbeddedJsLintSitesFromRawPugText(pugTextForParse); return { tsx: fallbackNullExpression(mode), mappings: [], @@ -2044,6 +2301,7 @@ export function compilePugToTsx(pugText: string, options: CompileOptions = {}): } if (!ast) { + extractEmbeddedJsLintSitesFromRawPugText(pugTextForParse); return { tsx: fallbackNullExpression(mode), mappings: [], diff --git a/packages/react-pug-core/test/unit/pugToTsx.test.ts b/packages/react-pug-core/test/unit/pugToTsx.test.ts index 2198d08..6b13c84 100644 --- a/packages/react-pug-core/test/unit/pugToTsx.test.ts +++ b/packages/react-pug-core/test/unit/pugToTsx.test.ts @@ -84,29 +84,23 @@ describe('TsxEmitter', () => { describe('tag compilation', () => { it('compiles bare tag: div ->
', () => { const result = compilePugToTsx('div'); - expect(result.tsx).toContain(''); + expect(result.tsx).toMatchInlineSnapshot(`"(
)"`); expect(result.parseError).toBeNull(); }); it('compiles component tag: Button ->