@zod-to-form/vite 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +40 -0
- package/dist/cache.d.ts +39 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +56 -0
- package/dist/cache.js.map +1 -0
- package/dist/config/load.d.ts +59 -0
- package/dist/config/load.d.ts.map +1 -0
- package/dist/config/load.js +117 -0
- package/dist/config/load.js.map +1 -0
- package/dist/errors.d.ts +50 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +62 -0
- package/dist/errors.js.map +1 -0
- package/dist/generate-mode/babel-traverse.d.ts +5 -0
- package/dist/generate-mode/babel-traverse.d.ts.map +1 -0
- package/dist/generate-mode/babel-traverse.js +16 -0
- package/dist/generate-mode/babel-traverse.js.map +1 -0
- package/dist/generate-mode/generate-source.d.ts +51 -0
- package/dist/generate-mode/generate-source.d.ts.map +1 -0
- package/dist/generate-mode/generate-source.js +187 -0
- package/dist/generate-mode/generate-source.js.map +1 -0
- package/dist/generate-mode/resolve-schema.d.ts +43 -0
- package/dist/generate-mode/resolve-schema.d.ts.map +1 -0
- package/dist/generate-mode/resolve-schema.js +182 -0
- package/dist/generate-mode/resolve-schema.js.map +1 -0
- package/dist/generate-mode/scan-jsx.d.ts +86 -0
- package/dist/generate-mode/scan-jsx.d.ts.map +1 -0
- package/dist/generate-mode/scan-jsx.js +161 -0
- package/dist/generate-mode/scan-jsx.js.map +1 -0
- package/dist/hmr.d.ts +44 -0
- package/dist/hmr.d.ts.map +1 -0
- package/dist/hmr.js +28 -0
- package/dist/hmr.js.map +1 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +27 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +46 -0
- package/dist/logger.js.map +1 -0
- package/dist/plugin.d.ts +61 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +650 -0
- package/dist/plugin.js.map +1 -0
- package/dist/query-mode/parse-specifier.d.ts +23 -0
- package/dist/query-mode/parse-specifier.d.ts.map +1 -0
- package/dist/query-mode/parse-specifier.js +83 -0
- package/dist/query-mode/parse-specifier.js.map +1 -0
- package/dist/query-mode/resolve-id.d.ts +12 -0
- package/dist/query-mode/resolve-id.d.ts.map +1 -0
- package/dist/query-mode/resolve-id.js +61 -0
- package/dist/query-mode/resolve-id.js.map +1 -0
- package/dist/query-mode/transform.d.ts +33 -0
- package/dist/query-mode/transform.d.ts.map +1 -0
- package/dist/query-mode/transform.js +90 -0
- package/dist/query-mode/transform.js.map +1 -0
- package/dist/resolver-strip.d.ts +58 -0
- package/dist/resolver-strip.d.ts.map +1 -0
- package/dist/resolver-strip.js +141 -0
- package/dist/resolver-strip.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types.d.ts +242 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/write-guard.d.ts +26 -0
- package/dist/write-guard.d.ts.map +1 -0
- package/dist/write-guard.js +32 -0
- package/dist/write-guard.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { parse as parseBabel } from '@babel/parser';
|
|
2
|
+
import MagicString from 'magic-string';
|
|
3
|
+
export function generateSource(input) {
|
|
4
|
+
const { source, resolved, onWarn } = input;
|
|
5
|
+
if (resolved.length === 0) {
|
|
6
|
+
// Nothing to do — but still hand back a valid magic-string sourcemap
|
|
7
|
+
// so downstream Vite plumbing has something to chain against.
|
|
8
|
+
const ms = new MagicString(source);
|
|
9
|
+
return {
|
|
10
|
+
code: source,
|
|
11
|
+
map: ms.generateMap({ hires: true }),
|
|
12
|
+
rewritten: 0
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const ms = new MagicString(source);
|
|
16
|
+
// Process sites in source order. magic-string supports overlapping
|
|
17
|
+
// edits as long as we use append/prepend instead of overwrite for
|
|
18
|
+
// adjacent ranges, but our per-site edits never overlap because
|
|
19
|
+
// they're confined to the opening/closing tag of distinct elements.
|
|
20
|
+
for (const site of resolved) {
|
|
21
|
+
const { candidate, generatedIdentifier } = site;
|
|
22
|
+
const openingSlice = source.slice(candidate.openingRange.start, candidate.openingRange.end);
|
|
23
|
+
// Build the new opening tag: replace `ZodForm` and remove the schema attr.
|
|
24
|
+
const newOpening = buildNewOpening(openingSlice, generatedIdentifier, candidate);
|
|
25
|
+
ms.overwrite(candidate.openingRange.start, candidate.openingRange.end, newOpening);
|
|
26
|
+
// Closing tag — `</ZodForm>` becomes `</_z2fGeneratedForm_N>`.
|
|
27
|
+
if (candidate.closingRange !== null) {
|
|
28
|
+
const closingSlice = source.slice(candidate.closingRange.start, candidate.closingRange.end);
|
|
29
|
+
const newClosing = closingSlice.replace(/ZodForm/, generatedIdentifier);
|
|
30
|
+
ms.overwrite(candidate.closingRange.start, candidate.closingRange.end, newClosing);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Insert the generated imports AFTER any leading shebang / block
|
|
34
|
+
// comments / string directives (`'use client'`, `'use strict'`) and
|
|
35
|
+
// AFTER the last existing top-level `import` statement — not blindly
|
|
36
|
+
// at byte 0. Prepending at byte 0 would demote a `'use client'`
|
|
37
|
+
// directive past the first import, invalidating it, and would push
|
|
38
|
+
// header comments below the generated block.
|
|
39
|
+
//
|
|
40
|
+
// Every generate-mode variant emits its component under the fixed
|
|
41
|
+
// export name `Form`; see `isGenerateVariant` in query-mode/transform.ts.
|
|
42
|
+
const importLines = [];
|
|
43
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
44
|
+
const site = resolved[i];
|
|
45
|
+
const variant = `__generate_${i + 1}`;
|
|
46
|
+
importLines.push(`import { Form as ${site.generatedIdentifier} } from '${site.schemaFile}?z2f=${variant}';`);
|
|
47
|
+
}
|
|
48
|
+
const insertAt = findImportInsertionPoint(source, onWarn);
|
|
49
|
+
// When the scanner can't find a trailing newline after the preamble
|
|
50
|
+
// (e.g. a preamble-only file, or a shebang file with no final `\n`),
|
|
51
|
+
// prepend one to the inserted text so `#!/usr/bin/env node` + generated
|
|
52
|
+
// import can't collapse to `#!/usr/bin/env nodeimport { … }` on the
|
|
53
|
+
// same line. No-op in the common case where `insertAt` already points
|
|
54
|
+
// at the start of a line.
|
|
55
|
+
const needsLeadingNewline = insertAt > 0 &&
|
|
56
|
+
insertAt < source.length &&
|
|
57
|
+
source[insertAt - 1] !== '\n' &&
|
|
58
|
+
source[insertAt - 1] !== '\r';
|
|
59
|
+
const prefix = needsLeadingNewline ? '\n' : '';
|
|
60
|
+
ms.appendLeft(insertAt, prefix + importLines.join('\n') + '\n');
|
|
61
|
+
return {
|
|
62
|
+
code: ms.toString(),
|
|
63
|
+
map: ms.generateMap({ hires: true }),
|
|
64
|
+
rewritten: resolved.length
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Find the byte offset at which to insert generated imports. The target
|
|
69
|
+
* is "immediately after the last thing that must come first": the file's
|
|
70
|
+
* shebang, its leading string directives (`'use client'`, `'use strict'`),
|
|
71
|
+
* and any existing top-level `import` statements. If none of those exist,
|
|
72
|
+
* the result is byte 0 (the file starts with user code and the generated
|
|
73
|
+
* imports go at the very top).
|
|
74
|
+
*
|
|
75
|
+
* Uses Babel's parser — the same dependency scan-jsx and resolve-schema
|
|
76
|
+
* already rely on — so directive detection, multi-line imports,
|
|
77
|
+
* TypeScript-specific forms (`import type`), side-effect-only imports,
|
|
78
|
+
* BOM handling, and escape sequences inside string literals are all
|
|
79
|
+
* handled by the production-grade parser instead of a hand-rolled
|
|
80
|
+
* textual walker.
|
|
81
|
+
*
|
|
82
|
+
* On parse failure (e.g. the user is mid-save with broken syntax) we
|
|
83
|
+
* warn via `onWarn` and return 0. This is defense-in-depth: `scanJsx`'s
|
|
84
|
+
* upstream parse normally filters broken sources before this code runs,
|
|
85
|
+
* but a future Babel plugin-flag drift between the two parsers could
|
|
86
|
+
* make them disagree, and silent corruption is worse than a warn line.
|
|
87
|
+
*
|
|
88
|
+
* `onWarn` MUST NOT throw — exceptions in the callback would kill the
|
|
89
|
+
* transform and turn a recoverable warning into a hard build failure.
|
|
90
|
+
* Any throw is caught and ignored below.
|
|
91
|
+
*/
|
|
92
|
+
// Exported for direct unit testing. Not part of the plugin's public API —
|
|
93
|
+
// callers outside this file should go through `generateSource`.
|
|
94
|
+
export function findImportInsertionPoint(source, onWarn) {
|
|
95
|
+
const safeWarn = (message) => {
|
|
96
|
+
if (onWarn === undefined)
|
|
97
|
+
return;
|
|
98
|
+
try {
|
|
99
|
+
onWarn(message);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// A throwing logger must not mask the fallback return path.
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
let ast;
|
|
106
|
+
try {
|
|
107
|
+
ast = parseBabel(source, {
|
|
108
|
+
sourceType: 'module',
|
|
109
|
+
plugins: ['jsx', 'typescript'],
|
|
110
|
+
errorRecovery: false
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
115
|
+
safeWarn(`generate-mode: re-parse failed inside findImportInsertionPoint (${msg}); ` +
|
|
116
|
+
'inserting at byte 0 as a safety fallback');
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
// Seed from the furthest end across every preamble-flavored node:
|
|
120
|
+
// - `program.interpreter` holds the shebang (`#!...`). Babel models it
|
|
121
|
+
// outside `body`, so a shebang would otherwise slip past the walk.
|
|
122
|
+
// - `program.directives` holds every leading string-literal directive.
|
|
123
|
+
// Babel lifts them out of `body` under `sourceType: 'module'`.
|
|
124
|
+
let lastPreambleEnd = Math.max(0, ast.program.interpreter?.end ?? 0, ...ast.program.directives.map((d) => d.end ?? 0));
|
|
125
|
+
// Walk top-level statements. Imports always extend the preamble. For
|
|
126
|
+
// defense-in-depth against Babel versions (< 7.21) that may leave a
|
|
127
|
+
// hashbang-following directive as a body `ExpressionStatement` instead
|
|
128
|
+
// of lifting it to `program.directives`, also treat a leading
|
|
129
|
+
// `ExpressionStatement` whose expression is a `StringLiteral` as
|
|
130
|
+
// preamble and keep walking.
|
|
131
|
+
for (const stmt of ast.program.body) {
|
|
132
|
+
if (stmt.type === 'ImportDeclaration' && stmt.end != null) {
|
|
133
|
+
lastPreambleEnd = stmt.end;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (stmt.type === 'ExpressionStatement') {
|
|
137
|
+
const expr = stmt.expression;
|
|
138
|
+
if (expr.type === 'StringLiteral' && stmt.end != null) {
|
|
139
|
+
lastPreambleEnd = Math.max(lastPreambleEnd, stmt.end);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Anything else stops the preamble.
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
// Babel ranges don't include a trailing newline. Advance past any
|
|
147
|
+
// horizontal whitespace followed by a single line terminator (any of
|
|
148
|
+
// `\n`, `\r\n`, or bare `\r`) so the inserted imports land on their
|
|
149
|
+
// own line rather than appended to the last preamble statement.
|
|
150
|
+
const match = /^[ \t]*(?:\r\n|\n|\r)/.exec(source.slice(lastPreambleEnd));
|
|
151
|
+
if (match !== null) {
|
|
152
|
+
lastPreambleEnd += match[0].length;
|
|
153
|
+
}
|
|
154
|
+
return lastPreambleEnd;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Build the replacement opening tag from the original source slice.
|
|
158
|
+
* Strategy: walk attributes from end to start so removing the schema
|
|
159
|
+
* attribute doesn't shift earlier offsets. We work with the slice
|
|
160
|
+
* (origin-relative offsets) to keep the math local.
|
|
161
|
+
*/
|
|
162
|
+
function buildNewOpening(openingSlice, generatedIdentifier, candidate) {
|
|
163
|
+
// Convert absolute attribute ranges to slice-local offsets.
|
|
164
|
+
const sliceStart = candidate.openingRange.start;
|
|
165
|
+
let result = openingSlice;
|
|
166
|
+
// Process attributes in REVERSE order so each removal/replacement
|
|
167
|
+
// doesn't invalidate earlier offsets.
|
|
168
|
+
const sortedAttrs = [...candidate.attributes].sort((a, b) => b.range.start - a.range.start);
|
|
169
|
+
for (const attr of sortedAttrs) {
|
|
170
|
+
if (attr.kind !== 'named' || attr.name !== 'schema')
|
|
171
|
+
continue;
|
|
172
|
+
const start = attr.range.start - sliceStart;
|
|
173
|
+
const end = attr.range.end - sliceStart;
|
|
174
|
+
// Trim a leading whitespace character if present so we don't leave
|
|
175
|
+
// a double space between adjacent props.
|
|
176
|
+
const before = result.slice(0, start);
|
|
177
|
+
const after = result.slice(end);
|
|
178
|
+
const trimmedBefore = before.endsWith(' ') ? before.slice(0, -1) : before;
|
|
179
|
+
result = trimmedBefore + after;
|
|
180
|
+
}
|
|
181
|
+
// Replace the element name (the FIRST occurrence of `ZodForm`, which
|
|
182
|
+
// is the tag name). Subsequent occurrences inside attributes — vanishingly
|
|
183
|
+
// rare but possible — are left alone.
|
|
184
|
+
result = result.replace(/ZodForm/, generatedIdentifier);
|
|
185
|
+
return result;
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=generate-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-source.js","sourceRoot":"","sources":["../../src/generate-mode/generate-source.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,KAAK,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,WAAW,MAAM,cAAc,CAAC;AA2BvC,MAAM,UAAU,cAAc,CAAC,KAA0B;IACvD,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAE3C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,qEAAqE;QACrE,8DAA8D;QAC9D,MAAM,EAAE,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;QACnC,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YACpC,SAAS,EAAE,CAAC;SACb,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;IAEnC,mEAAmE;IACnE,kEAAkE;IAClE,gEAAgE;IAChE,oEAAoE;IACpE,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,EAAE,SAAS,EAAE,mBAAmB,EAAE,GAAG,IAAI,CAAC;QAChD,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAE5F,2EAA2E;QAC3E,MAAM,UAAU,GAAG,eAAe,CAAC,YAAY,EAAE,mBAAmB,EAAE,SAAS,CAAC,CAAC;QACjF,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAEnF,+DAA+D;QAC/D,IAAI,SAAS,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;YACpC,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;YAC5F,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;YACxE,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IAED,iEAAiE;IACjE,oEAAoE;IACpE,qEAAqE;IACrE,gEAAgE;IAChE,mEAAmE;IACnE,6CAA6C;IAC7C,EAAE;IACF,kEAAkE;IAClE,0EAA0E;IAC1E,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,WAAW,CAAC,IAAI,CACd,oBAAoB,IAAI,CAAC,mBAAmB,YAAY,IAAI,CAAC,UAAU,QAAQ,OAAO,IAAI,CAC3F,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,wBAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1D,oEAAoE;IACpE,qEAAqE;IACrE,wEAAwE;IACxE,oEAAoE;IACpE,sEAAsE;IACtE,0BAA0B;IAC1B,MAAM,mBAAmB,GACvB,QAAQ,GAAG,CAAC;QACZ,QAAQ,GAAG,MAAM,CAAC,MAAM;QACxB,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK,IAAI;QAC7B,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;IAChC,MAAM,MAAM,GAAG,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/C,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IAEhE,OAAO;QACL,IAAI,EAAE,EAAE,CAAC,QAAQ,EAAE;QACnB,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACpC,SAAS,EAAE,QAAQ,CAAC,MAAM;KAC3B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,0EAA0E;AAC1E,gEAAgE;AAChE,MAAM,UAAU,wBAAwB,CACtC,MAAc,EACd,MAAkC;IAElC,MAAM,QAAQ,GAAG,CAAC,OAAe,EAAQ,EAAE;QACzC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO;QACjC,IAAI,CAAC;YACH,MAAM,CAAC,OAAO,CAAC,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,4DAA4D;QAC9D,CAAC;IACH,CAAC,CAAC;IAEF,IAAI,GAAsB,CAAC;IAC3B,IAAI,CAAC;QACH,GAAG,GAAG,UAAU,CAAC,MAAM,EAAE;YACvB,UAAU,EAAE,QAAQ;YACpB,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC;YAC9B,aAAa,EAAE,KAAK;SACrB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,QAAQ,CACN,mEAAmE,GAAG,KAAK;YACzE,0CAA0C,CAC7C,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,kEAAkE;IAClE,uEAAuE;IACvE,qEAAqE;IACrE,uEAAuE;IACvE,iEAAiE;IACjE,IAAI,eAAe,GAAG,IAAI,CAAC,GAAG,CAC5B,CAAC,EACD,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,EACjC,GAAG,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CACjD,CAAC;IAEF,qEAAqE;IACrE,oEAAoE;IACpE,uEAAuE;IACvE,8DAA8D;IAC9D,iEAAiE;IACjE,6BAA6B;IAC7B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,IAAI,KAAK,mBAAmB,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;YAC1D,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC;YAC3B,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACxC,MAAM,IAAI,GAAI,IAA4B,CAAC,UAAU,CAAC;YACtD,IAAI,IAAI,CAAC,IAAI,KAAK,eAAe,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;gBACtD,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;gBACtD,SAAS;YACX,CAAC;QACH,CAAC;QACD,oCAAoC;QACpC,MAAM;IACR,CAAC;IAED,kEAAkE;IAClE,qEAAqE;IACrE,oEAAoE;IACpE,gEAAgE;IAChE,MAAM,KAAK,GAAG,uBAAuB,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;IAC1E,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,eAAe,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACrC,CAAC;IAED,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CACtB,YAAoB,EACpB,mBAA2B,EAC3B,SAIC;IAED,4DAA4D;IAC5D,MAAM,UAAU,GAAG,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC;IAChD,IAAI,MAAM,GAAG,YAAY,CAAC;IAE1B,kEAAkE;IAClE,sCAAsC;IACtC,MAAM,WAAW,GAAG,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC5F,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAS;QAC9D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC;QAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC;QACxC,mEAAmE;QACnE,yCAAyC;QACzC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC1E,MAAM,GAAG,aAAa,GAAG,KAAK,CAAC;IACjC,CAAC;IAED,qEAAqE;IACrE,2EAA2E;IAC3E,sCAAsC;IACtC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IAExD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CandidateSite } from './scan-jsx.js';
|
|
2
|
+
export interface ImportBinding {
|
|
3
|
+
/** The raw import specifier (e.g. `'./schemas/signup'` or `'@acme/lib'`). */
|
|
4
|
+
source: string;
|
|
5
|
+
/** Local identifier name (after any `as` alias). */
|
|
6
|
+
localName: string;
|
|
7
|
+
/** Imported name from the source module (`signupSchema`, `default`). */
|
|
8
|
+
importedName: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ResolvedSite {
|
|
11
|
+
/** The candidate site this resolution applies to. */
|
|
12
|
+
candidate: CandidateSite;
|
|
13
|
+
/** Absolute path to the schema file (post-resolveImport). */
|
|
14
|
+
schemaFile: string;
|
|
15
|
+
/** Imported name of the schema from the source module. */
|
|
16
|
+
schemaExportName: string;
|
|
17
|
+
/** The local identifier that will replace `ZodForm` at this site ( (`_z2fGeneratedForm_<n>`). */
|
|
18
|
+
generatedIdentifier: string;
|
|
19
|
+
}
|
|
20
|
+
export type SkipReason = string;
|
|
21
|
+
export interface ResolveSchemaInput {
|
|
22
|
+
source: string;
|
|
23
|
+
candidates: CandidateSite[];
|
|
24
|
+
/** Absolute path to the file containing the candidates (importer). */
|
|
25
|
+
sourceFile: string;
|
|
26
|
+
/**
|
|
27
|
+
* Resolves an import specifier (e.g. `'./schemas/signup'`) against the
|
|
28
|
+
* importing source file and returns an absolute path, or null when the
|
|
29
|
+
* resolver can't find it. Wraps Vite's `this.resolve` in the caller.
|
|
30
|
+
*/
|
|
31
|
+
resolveImport: (specifier: string, importer: string) => Promise<string | null>;
|
|
32
|
+
/** Vite root — schema files outside this dir are skipped. */
|
|
33
|
+
viteRoot: string;
|
|
34
|
+
}
|
|
35
|
+
export interface ResolveSchemaOutput {
|
|
36
|
+
resolved: ResolvedSite[];
|
|
37
|
+
skipped: Array<{
|
|
38
|
+
candidate: CandidateSite;
|
|
39
|
+
reason: SkipReason;
|
|
40
|
+
}>;
|
|
41
|
+
}
|
|
42
|
+
export declare function resolveSchemas(input: ResolveSchemaInput): Promise<ResolveSchemaOutput>;
|
|
43
|
+
//# sourceMappingURL=resolve-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-schema.d.ts","sourceRoot":"","sources":["../../src/generate-mode/resolve-schema.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAInD,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,qDAAqD;IACrD,SAAS,EAAE,aAAa,CAAC;IACzB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,gBAAgB,EAAE,MAAM,CAAC;IACzB,iGAAiG;IACjG,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/E,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,aAAa,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,CAAC,CAAC;CAClE;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAgK5F"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resolveSchema — given a `CandidateSite` and the source file's path,
|
|
3
|
+
* walk the AST scope to validate that:
|
|
4
|
+
*
|
|
5
|
+
* 1. The `ZodForm` identifier resolves to a named import from the literal
|
|
6
|
+
* specifier `'@zod-to-form/react'` (no aliased re-exports).
|
|
7
|
+
* 2. The `schema` identifier resolves to a named import whose source
|
|
8
|
+
* module path is inside the Vite root.
|
|
9
|
+
*
|
|
10
|
+
* Returns a fully-resolved `GenerateSite` on success, or a `SkipReason`
|
|
11
|
+
* string on failure. The caller buffers the skip reason through the
|
|
12
|
+
* logger.
|
|
13
|
+
*
|
|
14
|
+
* Pure: takes the parsed AST + source + candidate, returns a result.
|
|
15
|
+
* No I/O. The path-resolution portion (turning a string specifier into
|
|
16
|
+
* an absolute file path) is delegated to a `resolveImport` callback that
|
|
17
|
+
* the plugin's `transform` hook supplies — it wraps Vite's `this.resolve`.
|
|
18
|
+
*/
|
|
19
|
+
import { parse } from '@babel/parser';
|
|
20
|
+
import { traverse } from './babel-traverse.js';
|
|
21
|
+
const ZOD_FORM_PACKAGE = '@zod-to-form/react';
|
|
22
|
+
export async function resolveSchemas(input) {
|
|
23
|
+
const { source, candidates, sourceFile, resolveImport, viteRoot } = input;
|
|
24
|
+
if (candidates.length === 0) {
|
|
25
|
+
return { resolved: [], skipped: [] };
|
|
26
|
+
}
|
|
27
|
+
// Re-parse the source to pick up the program-level import declarations.
|
|
28
|
+
// We could pass the AST through from scanJsx, but keeping resolveSchemas
|
|
29
|
+
// self-contained makes it easier to unit-test in isolation. The parse
|
|
30
|
+
// cost is bounded by the file size, not by the number of candidates.
|
|
31
|
+
let ast;
|
|
32
|
+
try {
|
|
33
|
+
ast = parse(source, {
|
|
34
|
+
sourceType: 'module',
|
|
35
|
+
plugins: ['jsx', 'typescript'],
|
|
36
|
+
errorRecovery: false
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
41
|
+
return {
|
|
42
|
+
resolved: [],
|
|
43
|
+
skipped: candidates.map((c) => ({
|
|
44
|
+
candidate: c,
|
|
45
|
+
reason: `source file failed to re-parse: ${message}`
|
|
46
|
+
}))
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// Build a map of local identifier name → import binding for every
|
|
50
|
+
// top-level import. We only care about top-level imports because
|
|
51
|
+
// <ZodForm> can't validly use a function-scoped import.
|
|
52
|
+
const bindings = new Map();
|
|
53
|
+
traverse(ast, {
|
|
54
|
+
Program(path) {
|
|
55
|
+
for (const node of path.node.body) {
|
|
56
|
+
if (node.type !== 'ImportDeclaration')
|
|
57
|
+
continue;
|
|
58
|
+
const decl = node;
|
|
59
|
+
const sourceLiteral = decl.source.value;
|
|
60
|
+
for (const specifier of decl.specifiers) {
|
|
61
|
+
if (specifier.type === 'ImportSpecifier') {
|
|
62
|
+
const s = specifier;
|
|
63
|
+
const importedName = s.imported.type === 'Identifier' ? s.imported.name : s.imported.value;
|
|
64
|
+
bindings.set(s.local.name, {
|
|
65
|
+
source: sourceLiteral,
|
|
66
|
+
localName: s.local.name,
|
|
67
|
+
importedName
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
else if (specifier.type === 'ImportDefaultSpecifier') {
|
|
71
|
+
const s = specifier;
|
|
72
|
+
bindings.set(s.local.name, {
|
|
73
|
+
source: sourceLiteral,
|
|
74
|
+
localName: s.local.name,
|
|
75
|
+
importedName: 'default'
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
else if (specifier.type === 'ImportNamespaceSpecifier') {
|
|
79
|
+
const s = specifier;
|
|
80
|
+
bindings.set(s.local.name, {
|
|
81
|
+
source: sourceLiteral,
|
|
82
|
+
localName: s.local.name,
|
|
83
|
+
importedName: '*'
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
path.stop();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
const resolved = [];
|
|
92
|
+
const skipped = [];
|
|
93
|
+
let counter = 0;
|
|
94
|
+
for (const candidate of candidates) {
|
|
95
|
+
// 1. ZodForm must come from @zod-to-form/react
|
|
96
|
+
const zodFormBinding = bindings.get('ZodForm');
|
|
97
|
+
if (zodFormBinding === undefined) {
|
|
98
|
+
skipped.push({
|
|
99
|
+
candidate,
|
|
100
|
+
reason: `<ZodForm> at ${candidate.loc.line}:${candidate.loc.column} has no in-scope import; generate mode requires a top-level 'import { ZodForm }' statement`
|
|
101
|
+
});
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (zodFormBinding.source !== ZOD_FORM_PACKAGE) {
|
|
105
|
+
skipped.push({
|
|
106
|
+
candidate,
|
|
107
|
+
reason: `ZodForm import origin is '${zodFormBinding.source}', not '${ZOD_FORM_PACKAGE}'`
|
|
108
|
+
});
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (zodFormBinding.importedName !== 'ZodForm') {
|
|
112
|
+
skipped.push({
|
|
113
|
+
candidate,
|
|
114
|
+
reason: `ZodForm import is aliased ('${zodFormBinding.importedName}' as '${zodFormBinding.localName}'); only the unaliased named import is matched`
|
|
115
|
+
});
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
// 2. The schema identifier must resolve to a top-level import.
|
|
119
|
+
// CandidateSite.schemaIdentifier is non-null by scan-jsx's contract.
|
|
120
|
+
const schemaIdName = candidate.schemaIdentifier;
|
|
121
|
+
const schemaBinding = bindings.get(schemaIdName);
|
|
122
|
+
if (schemaBinding === undefined) {
|
|
123
|
+
skipped.push({
|
|
124
|
+
candidate,
|
|
125
|
+
reason: `schema identifier '${schemaIdName}' is not a top-level import (generate mode only handles imported schemas)`
|
|
126
|
+
});
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (schemaBinding.importedName === '*' || schemaBinding.importedName === 'default') {
|
|
130
|
+
skipped.push({
|
|
131
|
+
candidate,
|
|
132
|
+
reason: `schema identifier '${schemaIdName}' is a ${schemaBinding.importedName === '*' ? 'namespace' : 'default'} import; only named imports are handled`
|
|
133
|
+
});
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
// 3. The schema source must resolve to an absolute path inside the
|
|
137
|
+
// Vite root. Wrap the resolver call in try/catch — Vite's
|
|
138
|
+
// `this.resolve` can throw (rather than return null) if a downstream
|
|
139
|
+
// resolveId hook errors during the lookup. Treat that as a skip with
|
|
140
|
+
// the underlying error attached, not an uncaught reject.
|
|
141
|
+
let absoluteSchemaPath;
|
|
142
|
+
try {
|
|
143
|
+
absoluteSchemaPath = await resolveImport(schemaBinding.source, sourceFile);
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
skipped.push({
|
|
147
|
+
candidate,
|
|
148
|
+
reason: `schema import '${schemaBinding.source}' threw during resolution: ${err instanceof Error ? err.message : String(err)}`
|
|
149
|
+
});
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (absoluteSchemaPath === null) {
|
|
153
|
+
skipped.push({
|
|
154
|
+
candidate,
|
|
155
|
+
reason: `schema import '${schemaBinding.source}' could not be resolved by Vite`
|
|
156
|
+
});
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (!isInsideRoot(absoluteSchemaPath, viteRoot)) {
|
|
160
|
+
skipped.push({
|
|
161
|
+
candidate,
|
|
162
|
+
reason: `schema identifier '${schemaIdName}' resolves to '${absoluteSchemaPath}', which is outside the Vite root`
|
|
163
|
+
});
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
counter += 1;
|
|
167
|
+
resolved.push({
|
|
168
|
+
candidate,
|
|
169
|
+
schemaFile: absoluteSchemaPath,
|
|
170
|
+
schemaExportName: schemaBinding.importedName,
|
|
171
|
+
generatedIdentifier: `_z2fGeneratedForm_${counter}`
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
return { resolved, skipped };
|
|
175
|
+
}
|
|
176
|
+
function isInsideRoot(child, root) {
|
|
177
|
+
const c = child.replace(/\\/g, '/');
|
|
178
|
+
const r = root.replace(/\\/g, '/');
|
|
179
|
+
const normalizedRoot = r.endsWith('/') ? r : r + '/';
|
|
180
|
+
return c === r || c.startsWith(normalizedRoot);
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=resolve-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-schema.js","sourceRoot":"","sources":["../../src/generate-mode/resolve-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One JSX attribute as it appears on a candidate `<ZodForm>` element.
|
|
3
|
+
*
|
|
4
|
+
* Discriminated on `kind`: a `'spread'` attribute (`{...rest}`) has no
|
|
5
|
+
* name; a `'named'` attribute has one. Encoding the distinction in the
|
|
6
|
+
* type prevents the "name is null when isSpread is true" coupling from
|
|
7
|
+
* silently drifting.
|
|
8
|
+
*/
|
|
9
|
+
export type CandidateAttribute = {
|
|
10
|
+
kind: 'named';
|
|
11
|
+
/** Attribute identifier (e.g. `'schema'`, `'onSubmit'`). */
|
|
12
|
+
name: string;
|
|
13
|
+
/** Byte range of the entire attribute, inclusive of name + value. */
|
|
14
|
+
range: {
|
|
15
|
+
start: number;
|
|
16
|
+
end: number;
|
|
17
|
+
};
|
|
18
|
+
/** Raw source slice for this attribute (used to preserve formatting). */
|
|
19
|
+
source: string;
|
|
20
|
+
} | {
|
|
21
|
+
kind: 'spread';
|
|
22
|
+
range: {
|
|
23
|
+
start: number;
|
|
24
|
+
end: number;
|
|
25
|
+
};
|
|
26
|
+
source: string;
|
|
27
|
+
};
|
|
28
|
+
export interface CandidateSite {
|
|
29
|
+
/**
|
|
30
|
+
* Byte range of the *opening tag* (e.g. `<ZodForm schema={X} ... >` or
|
|
31
|
+
* `<ZodForm ... />` for self-closing). The closing tag (if any) is
|
|
32
|
+
* tracked separately.
|
|
33
|
+
*/
|
|
34
|
+
openingRange: {
|
|
35
|
+
start: number;
|
|
36
|
+
end: number;
|
|
37
|
+
};
|
|
38
|
+
/** Byte range of the closing tag, or null for self-closing elements. */
|
|
39
|
+
closingRange: {
|
|
40
|
+
start: number;
|
|
41
|
+
end: number;
|
|
42
|
+
} | null;
|
|
43
|
+
/** Source location of the opening tag, for diagnostics (1-indexed line). */
|
|
44
|
+
loc: {
|
|
45
|
+
line: number;
|
|
46
|
+
column: number;
|
|
47
|
+
};
|
|
48
|
+
/** True iff the element is `<ZodForm ... />`. */
|
|
49
|
+
selfClosing: boolean;
|
|
50
|
+
/** All attributes in source order, including the `schema` attribute. */
|
|
51
|
+
attributes: CandidateAttribute[];
|
|
52
|
+
/** The identifier name from `schema={identifier}`. */
|
|
53
|
+
schemaIdentifier: string;
|
|
54
|
+
/** Children source slice (between opening and closing tags), or '' if self-closing. */
|
|
55
|
+
childrenSource: string;
|
|
56
|
+
}
|
|
57
|
+
export interface ScanResult {
|
|
58
|
+
/** Candidate sites that may be transformable. resolveSchema validates them. */
|
|
59
|
+
candidates: CandidateSite[];
|
|
60
|
+
/** Sites that matched `<ZodForm>` but failed an early structural check. */
|
|
61
|
+
skipped: SkippedSite[];
|
|
62
|
+
}
|
|
63
|
+
export interface SkippedSite {
|
|
64
|
+
loc: {
|
|
65
|
+
line: number;
|
|
66
|
+
column: number;
|
|
67
|
+
};
|
|
68
|
+
reason: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Scan a source string for `<ZodForm>` JSX elements. Returns candidates
|
|
72
|
+
* for further validation by `resolveSchema` plus an array of sites that
|
|
73
|
+
* structurally don't qualify (and thus need a DEBUG diagnostic).
|
|
74
|
+
*
|
|
75
|
+
* Returns `null` (a discriminator distinct from "scanned and found
|
|
76
|
+
* nothing") when the substring fast-path filtered the file out — the
|
|
77
|
+
* caller can short-circuit before allocating anything else.
|
|
78
|
+
*
|
|
79
|
+
* On a Babel parse failure, returns a `ScanResult` with zero candidates
|
|
80
|
+
* and a single skip diagnostic naming the parser error so it surfaces
|
|
81
|
+
* in the buildEnd summary. We deliberately don't propagate the parse
|
|
82
|
+
* error — Vite's main pipeline will report the user's syntax problem
|
|
83
|
+
* elsewhere with better context.
|
|
84
|
+
*/
|
|
85
|
+
export declare function scanJsx(source: string): ScanResult | null;
|
|
86
|
+
//# sourceMappingURL=scan-jsx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-jsx.d.ts","sourceRoot":"","sources":["../../src/generate-mode/scan-jsx.ts"],"names":[],"mappings":"AAyBA;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IACE,IAAI,EAAE,OAAO,CAAC;IACd,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEN,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,wEAAwE;IACxE,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACpD,4EAA4E;IAC5E,GAAG,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,iDAAiD;IACjD,WAAW,EAAE,OAAO,CAAC;IACrB,wEAAwE;IACxE,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,sDAAsD;IACtD,gBAAgB,EAAE,MAAM,CAAC;IACzB,uFAAuF;IACvF,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,+EAA+E;IAC/E,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,2EAA2E;IAC3E,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAgHzD"}
|