@knighted/jsx 1.10.0 → 1.11.0

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.
@@ -120,6 +120,125 @@ const collectImportMetadata = (body) => {
120
120
  });
121
121
  return imports;
122
122
  };
123
+ const toIdentifierName = (value) => {
124
+ if (!isObjectRecord(value)) {
125
+ return null;
126
+ }
127
+ if (value.type !== 'Identifier') {
128
+ return null;
129
+ }
130
+ return typeof value.name === 'string' ? value.name : null;
131
+ };
132
+ const toVariableInitializerKind = (value) => {
133
+ if (!isObjectRecord(value) || typeof value.type !== 'string') {
134
+ return null;
135
+ }
136
+ if (value.type === 'ArrowFunctionExpression') {
137
+ return 'arrow-function';
138
+ }
139
+ if (value.type === 'FunctionExpression') {
140
+ return 'function-expression';
141
+ }
142
+ if (value.type === 'ClassExpression') {
143
+ return 'class-expression';
144
+ }
145
+ return 'other';
146
+ };
147
+ const pushTopLevelDeclarationMetadata = ({ declaration, exportKind, statementRange, declarations, }) => {
148
+ if (declaration.type === 'FunctionDeclaration') {
149
+ const name = toIdentifierName(declaration.id);
150
+ if (!name) {
151
+ return;
152
+ }
153
+ declarations.push({
154
+ name,
155
+ kind: 'function',
156
+ exportKind,
157
+ range: toSourceRange(declaration),
158
+ statementRange,
159
+ initializerKind: null,
160
+ });
161
+ return;
162
+ }
163
+ if (declaration.type === 'ClassDeclaration') {
164
+ const name = toIdentifierName(declaration.id);
165
+ if (!name) {
166
+ return;
167
+ }
168
+ declarations.push({
169
+ name,
170
+ kind: 'class',
171
+ exportKind,
172
+ range: toSourceRange(declaration),
173
+ statementRange,
174
+ initializerKind: null,
175
+ });
176
+ return;
177
+ }
178
+ if (!Array.isArray(declaration.declarations)) {
179
+ return;
180
+ }
181
+ for (const declarator of declaration.declarations) {
182
+ if (!isObjectRecord(declarator)) {
183
+ continue;
184
+ }
185
+ const name = toIdentifierName(declarator.id);
186
+ if (!name) {
187
+ continue;
188
+ }
189
+ declarations.push({
190
+ name,
191
+ kind: 'variable',
192
+ exportKind,
193
+ range: toSourceRange(declarator),
194
+ statementRange,
195
+ initializerKind: toVariableInitializerKind(declarator.init),
196
+ });
197
+ }
198
+ };
199
+ const collectTopLevelDeclarationMetadata = (body) => {
200
+ if (!Array.isArray(body)) {
201
+ return [];
202
+ }
203
+ const declarations = [];
204
+ for (const statement of body) {
205
+ if (!isObjectRecord(statement) || typeof statement.type !== 'string') {
206
+ continue;
207
+ }
208
+ const statementRange = toSourceRange(statement);
209
+ if (statement.type === 'ExportNamedDeclaration') {
210
+ if (!isObjectRecord(statement.declaration)) {
211
+ continue;
212
+ }
213
+ pushTopLevelDeclarationMetadata({
214
+ declaration: statement.declaration,
215
+ exportKind: 'named',
216
+ statementRange,
217
+ declarations,
218
+ });
219
+ continue;
220
+ }
221
+ if (statement.type === 'ExportDefaultDeclaration') {
222
+ if (!isObjectRecord(statement.declaration)) {
223
+ continue;
224
+ }
225
+ pushTopLevelDeclarationMetadata({
226
+ declaration: statement.declaration,
227
+ exportKind: 'default',
228
+ statementRange,
229
+ declarations,
230
+ });
231
+ continue;
232
+ }
233
+ pushTopLevelDeclarationMetadata({
234
+ declaration: statement,
235
+ exportKind: 'none',
236
+ statementRange,
237
+ declarations,
238
+ });
239
+ }
240
+ return declarations;
241
+ };
123
242
  const ensureSupportedOptions = (options) => {
124
243
  if (options.sourceType !== undefined &&
125
244
  options.sourceType !== 'module' &&
@@ -136,6 +255,10 @@ const ensureSupportedOptions = (options) => {
136
255
  options.typescriptStripBackend !== 'transpile-manual') {
137
256
  throw new Error(`[jsx] Unsupported typescriptStripBackend "${String(options.typescriptStripBackend)}". Use "oxc-transform" or "transpile-manual".`);
138
257
  }
258
+ if (options.collectTopLevelDeclarations !== undefined &&
259
+ typeof options.collectTopLevelDeclarations !== 'boolean') {
260
+ throw new Error(`[jsx] Unsupported collectTopLevelDeclarations value "${String(options.collectTopLevelDeclarations)}". Use true or false.`);
261
+ }
139
262
  };
140
263
  function transformJsxSource(source, options = {}) {
141
264
  const internalOptions = options;
@@ -146,12 +269,16 @@ function transformJsxSource(source, options = {}) {
146
269
  const parsed = (0, oxc_parser_1.parseSync)('transform-jsx-source.tsx', source, createParserOptions(sourceType));
147
270
  const parserDiagnostics = parsed.errors.map(error => toDiagnostic('parser', error));
148
271
  const imports = collectImportMetadata(parsed.program.body);
272
+ const declarations = internalOptions.collectTopLevelDeclarations
273
+ ? collectTopLevelDeclarationMetadata(parsed.program.body)
274
+ : undefined;
149
275
  if (parserDiagnostics.length) {
150
276
  return {
151
277
  code: source,
152
278
  changed: false,
153
279
  imports,
154
280
  diagnostics: parserDiagnostics,
281
+ declarations,
155
282
  };
156
283
  }
157
284
  const transpileBaseOptions = {
@@ -167,6 +294,7 @@ function transformJsxSource(source, options = {}) {
167
294
  changed: result.changed,
168
295
  imports,
169
296
  diagnostics: parserDiagnostics,
297
+ declarations,
170
298
  };
171
299
  }
172
300
  if (typescriptStripBackend === 'transpile-manual') {
@@ -179,6 +307,7 @@ function transformJsxSource(source, options = {}) {
179
307
  changed: result.changed,
180
308
  imports,
181
309
  diagnostics: parserDiagnostics,
310
+ declarations,
182
311
  };
183
312
  }
184
313
  const transformed = (0, oxc_transform_1.transformSync)('transform-jsx-source.tsx', source, {
@@ -196,6 +325,7 @@ function transformJsxSource(source, options = {}) {
196
325
  changed: fallbackCode !== source,
197
326
  imports,
198
327
  diagnostics,
328
+ declarations,
199
329
  };
200
330
  }
201
331
  const jsxResult = (0, transpile_js_1.transpileJsxSource)(transformed.code, transpileBaseOptions);
@@ -204,5 +334,6 @@ function transformJsxSource(source, options = {}) {
204
334
  changed: jsxResult.code !== source,
205
335
  imports,
206
336
  diagnostics,
337
+ declarations,
207
338
  };
208
339
  }
@@ -23,12 +23,26 @@ export type TransformImport = {
23
23
  bindings: TransformImportBinding[];
24
24
  range: SourceRange | null;
25
25
  };
26
- export type TransformJsxSourceOptions = TranspileJsxSourceOptions;
26
+ export type TransformTopLevelDeclarationKind = 'function' | 'class' | 'variable';
27
+ export type TransformTopLevelDeclarationExportKind = 'none' | 'named' | 'default';
28
+ export type TransformVariableInitializerKind = 'arrow-function' | 'function-expression' | 'class-expression' | 'other' | null;
29
+ export type TransformTopLevelDeclaration = {
30
+ name: string;
31
+ kind: TransformTopLevelDeclarationKind;
32
+ exportKind: TransformTopLevelDeclarationExportKind;
33
+ range: SourceRange | null;
34
+ statementRange: SourceRange | null;
35
+ initializerKind: TransformVariableInitializerKind;
36
+ };
37
+ export type TransformJsxSourceOptions = TranspileJsxSourceOptions & {
38
+ collectTopLevelDeclarations?: boolean;
39
+ };
27
40
  export type TransformJsxSourceResult = {
28
41
  code: string;
29
42
  changed: boolean;
30
43
  imports: TransformImport[];
31
44
  diagnostics: TransformDiagnostic[];
45
+ declarations?: TransformTopLevelDeclaration[];
32
46
  };
33
47
  export declare function transformJsxSource(source: string, options?: TransformJsxSourceOptions): TransformJsxSourceResult;
34
48
  export {};
@@ -23,12 +23,26 @@ export type TransformImport = {
23
23
  bindings: TransformImportBinding[];
24
24
  range: SourceRange | null;
25
25
  };
26
- export type TransformJsxSourceOptions = TranspileJsxSourceOptions;
26
+ export type TransformTopLevelDeclarationKind = 'function' | 'class' | 'variable';
27
+ export type TransformTopLevelDeclarationExportKind = 'none' | 'named' | 'default';
28
+ export type TransformVariableInitializerKind = 'arrow-function' | 'function-expression' | 'class-expression' | 'other' | null;
29
+ export type TransformTopLevelDeclaration = {
30
+ name: string;
31
+ kind: TransformTopLevelDeclarationKind;
32
+ exportKind: TransformTopLevelDeclarationExportKind;
33
+ range: SourceRange | null;
34
+ statementRange: SourceRange | null;
35
+ initializerKind: TransformVariableInitializerKind;
36
+ };
37
+ export type TransformJsxSourceOptions = TranspileJsxSourceOptions & {
38
+ collectTopLevelDeclarations?: boolean;
39
+ };
27
40
  export type TransformJsxSourceResult = {
28
41
  code: string;
29
42
  changed: boolean;
30
43
  imports: TransformImport[];
31
44
  diagnostics: TransformDiagnostic[];
45
+ declarations?: TransformTopLevelDeclaration[];
32
46
  };
33
47
  export declare function transformJsxSource(source: string, options?: TransformJsxSourceOptions): TransformJsxSourceResult;
34
48
  export {};
package/dist/transform.js CHANGED
@@ -117,6 +117,125 @@ const collectImportMetadata = (body) => {
117
117
  });
118
118
  return imports;
119
119
  };
120
+ const toIdentifierName = (value) => {
121
+ if (!isObjectRecord(value)) {
122
+ return null;
123
+ }
124
+ if (value.type !== 'Identifier') {
125
+ return null;
126
+ }
127
+ return typeof value.name === 'string' ? value.name : null;
128
+ };
129
+ const toVariableInitializerKind = (value) => {
130
+ if (!isObjectRecord(value) || typeof value.type !== 'string') {
131
+ return null;
132
+ }
133
+ if (value.type === 'ArrowFunctionExpression') {
134
+ return 'arrow-function';
135
+ }
136
+ if (value.type === 'FunctionExpression') {
137
+ return 'function-expression';
138
+ }
139
+ if (value.type === 'ClassExpression') {
140
+ return 'class-expression';
141
+ }
142
+ return 'other';
143
+ };
144
+ const pushTopLevelDeclarationMetadata = ({ declaration, exportKind, statementRange, declarations, }) => {
145
+ if (declaration.type === 'FunctionDeclaration') {
146
+ const name = toIdentifierName(declaration.id);
147
+ if (!name) {
148
+ return;
149
+ }
150
+ declarations.push({
151
+ name,
152
+ kind: 'function',
153
+ exportKind,
154
+ range: toSourceRange(declaration),
155
+ statementRange,
156
+ initializerKind: null,
157
+ });
158
+ return;
159
+ }
160
+ if (declaration.type === 'ClassDeclaration') {
161
+ const name = toIdentifierName(declaration.id);
162
+ if (!name) {
163
+ return;
164
+ }
165
+ declarations.push({
166
+ name,
167
+ kind: 'class',
168
+ exportKind,
169
+ range: toSourceRange(declaration),
170
+ statementRange,
171
+ initializerKind: null,
172
+ });
173
+ return;
174
+ }
175
+ if (!Array.isArray(declaration.declarations)) {
176
+ return;
177
+ }
178
+ for (const declarator of declaration.declarations) {
179
+ if (!isObjectRecord(declarator)) {
180
+ continue;
181
+ }
182
+ const name = toIdentifierName(declarator.id);
183
+ if (!name) {
184
+ continue;
185
+ }
186
+ declarations.push({
187
+ name,
188
+ kind: 'variable',
189
+ exportKind,
190
+ range: toSourceRange(declarator),
191
+ statementRange,
192
+ initializerKind: toVariableInitializerKind(declarator.init),
193
+ });
194
+ }
195
+ };
196
+ const collectTopLevelDeclarationMetadata = (body) => {
197
+ if (!Array.isArray(body)) {
198
+ return [];
199
+ }
200
+ const declarations = [];
201
+ for (const statement of body) {
202
+ if (!isObjectRecord(statement) || typeof statement.type !== 'string') {
203
+ continue;
204
+ }
205
+ const statementRange = toSourceRange(statement);
206
+ if (statement.type === 'ExportNamedDeclaration') {
207
+ if (!isObjectRecord(statement.declaration)) {
208
+ continue;
209
+ }
210
+ pushTopLevelDeclarationMetadata({
211
+ declaration: statement.declaration,
212
+ exportKind: 'named',
213
+ statementRange,
214
+ declarations,
215
+ });
216
+ continue;
217
+ }
218
+ if (statement.type === 'ExportDefaultDeclaration') {
219
+ if (!isObjectRecord(statement.declaration)) {
220
+ continue;
221
+ }
222
+ pushTopLevelDeclarationMetadata({
223
+ declaration: statement.declaration,
224
+ exportKind: 'default',
225
+ statementRange,
226
+ declarations,
227
+ });
228
+ continue;
229
+ }
230
+ pushTopLevelDeclarationMetadata({
231
+ declaration: statement,
232
+ exportKind: 'none',
233
+ statementRange,
234
+ declarations,
235
+ });
236
+ }
237
+ return declarations;
238
+ };
120
239
  const ensureSupportedOptions = (options) => {
121
240
  if (options.sourceType !== undefined &&
122
241
  options.sourceType !== 'module' &&
@@ -133,6 +252,10 @@ const ensureSupportedOptions = (options) => {
133
252
  options.typescriptStripBackend !== 'transpile-manual') {
134
253
  throw new Error(`[jsx] Unsupported typescriptStripBackend "${String(options.typescriptStripBackend)}". Use "oxc-transform" or "transpile-manual".`);
135
254
  }
255
+ if (options.collectTopLevelDeclarations !== undefined &&
256
+ typeof options.collectTopLevelDeclarations !== 'boolean') {
257
+ throw new Error(`[jsx] Unsupported collectTopLevelDeclarations value "${String(options.collectTopLevelDeclarations)}". Use true or false.`);
258
+ }
136
259
  };
137
260
  export function transformJsxSource(source, options = {}) {
138
261
  const internalOptions = options;
@@ -143,12 +266,16 @@ export function transformJsxSource(source, options = {}) {
143
266
  const parsed = parseSync('transform-jsx-source.tsx', source, createParserOptions(sourceType));
144
267
  const parserDiagnostics = parsed.errors.map(error => toDiagnostic('parser', error));
145
268
  const imports = collectImportMetadata(parsed.program.body);
269
+ const declarations = internalOptions.collectTopLevelDeclarations
270
+ ? collectTopLevelDeclarationMetadata(parsed.program.body)
271
+ : undefined;
146
272
  if (parserDiagnostics.length) {
147
273
  return {
148
274
  code: source,
149
275
  changed: false,
150
276
  imports,
151
277
  diagnostics: parserDiagnostics,
278
+ declarations,
152
279
  };
153
280
  }
154
281
  const transpileBaseOptions = {
@@ -164,6 +291,7 @@ export function transformJsxSource(source, options = {}) {
164
291
  changed: result.changed,
165
292
  imports,
166
293
  diagnostics: parserDiagnostics,
294
+ declarations,
167
295
  };
168
296
  }
169
297
  if (typescriptStripBackend === 'transpile-manual') {
@@ -176,6 +304,7 @@ export function transformJsxSource(source, options = {}) {
176
304
  changed: result.changed,
177
305
  imports,
178
306
  diagnostics: parserDiagnostics,
307
+ declarations,
179
308
  };
180
309
  }
181
310
  const transformed = transformSync('transform-jsx-source.tsx', source, {
@@ -193,6 +322,7 @@ export function transformJsxSource(source, options = {}) {
193
322
  changed: fallbackCode !== source,
194
323
  imports,
195
324
  diagnostics,
325
+ declarations,
196
326
  };
197
327
  }
198
328
  const jsxResult = transpileJsxSource(transformed.code, transpileBaseOptions);
@@ -201,5 +331,6 @@ export function transformJsxSource(source, options = {}) {
201
331
  changed: jsxResult.code !== source,
202
332
  imports,
203
333
  diagnostics,
334
+ declarations,
204
335
  };
205
336
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knighted/jsx",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "description": "Runtime JSX tagged template that renders DOM or React trees anywhere with or without a build step.",
5
5
  "keywords": [
6
6
  "jsx runtime",