@wyw-in-js/transform 0.4.0 → 0.4.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.
@@ -5,12 +5,16 @@
5
5
  import type { BabelFile, PluginObj } from '@babel/core';
6
6
  import type { ValueCache } from '@wyw-in-js/processor-utils';
7
7
  import type { StrictOptions } from '@wyw-in-js/shared';
8
+ import { EventEmitter } from '../utils/EventEmitter';
8
9
  import type { Core } from '../babel';
9
10
  import type { IPluginState } from '../types';
10
11
  export declare const filename: string;
11
- export declare function collector(file: BabelFile, options: Pick<StrictOptions, 'classNameSlug' | 'displayName' | 'evaluate' | 'tagResolver'>, values: ValueCache): {
12
+ export declare function collector(file: BabelFile, options: Pick<StrictOptions, 'classNameSlug' | 'displayName' | 'evaluate' | 'tagResolver'> & {
13
+ eventEmitter?: EventEmitter;
14
+ }, values: ValueCache): {
12
15
  artifacts: import("@wyw-in-js/shared").Artifact[];
13
16
  }[];
14
17
  export default function collectorPlugin(babel: Core, options: StrictOptions & {
18
+ eventEmitter?: EventEmitter;
15
19
  values?: ValueCache;
16
20
  }): PluginObj<IPluginState>;
@@ -6,21 +6,16 @@
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.collector = exports.filename = void 0;
8
8
  const shared_1 = require("@wyw-in-js/shared");
9
- const processTemplateExpression_1 = require("../utils/processTemplateExpression");
9
+ const EventEmitter_1 = require("../utils/EventEmitter");
10
+ const getTagProcessor_1 = require("../utils/getTagProcessor");
10
11
  const scopeHelpers_1 = require("../utils/scopeHelpers");
11
12
  const traversalCache_1 = require("../utils/traversalCache");
12
13
  exports.filename = __filename;
13
14
  function collector(file, options, values) {
15
+ const eventEmitter = options.eventEmitter ?? EventEmitter_1.EventEmitter.dummy;
14
16
  const processors = [];
15
- const identifiers = [];
16
- file.path.traverse({
17
- Identifier: (p) => {
18
- identifiers.push(p);
19
- },
20
- });
21
- // TODO: process transformed literals
22
- identifiers.forEach((p) => {
23
- (0, processTemplateExpression_1.processTemplateExpression)(p, file.opts, options, (processor) => {
17
+ eventEmitter.perf('transform:collector:processTemplate', () => {
18
+ (0, getTagProcessor_1.applyProcessors)(file.path, file.opts, options, (processor) => {
24
19
  processor.build(values);
25
20
  processor.doRuntimeReplacement();
26
21
  processors.push(processor);
@@ -7,10 +7,10 @@ import type { StrictOptions } from '@wyw-in-js/shared';
7
7
  import type { Core } from '../babel';
8
8
  import type { IPluginState } from '../types';
9
9
  import { EventEmitter } from '../utils/EventEmitter';
10
- export type PreevalOptions = Pick<StrictOptions, 'classNameSlug' | 'displayName' | 'evaluate' | 'features'> & {
11
- eventEmitter: EventEmitter;
10
+ export type PreevalOptions = Pick<StrictOptions, 'classNameSlug' | 'displayName' | 'evaluate' | 'features' | 'tagResolver'> & {
11
+ eventEmitter?: EventEmitter;
12
12
  };
13
- export declare function preeval(babel: Core, { eventEmitter, ...options }: PreevalOptions): PluginObj<IPluginState & {
13
+ export declare function preeval(babel: Core, options: PreevalOptions): PluginObj<IPluginState & {
14
14
  onFinish: () => void;
15
15
  }>;
16
16
  export default preeval;
@@ -2,14 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.preeval = void 0;
4
4
  const shared_1 = require("@wyw-in-js/shared");
5
+ const getTagProcessor_1 = require("../utils/getTagProcessor");
5
6
  const EventEmitter_1 = require("../utils/EventEmitter");
6
7
  const addIdentifierToWywPreval_1 = require("../utils/addIdentifierToWywPreval");
7
8
  const getFileIdx_1 = require("../utils/getFileIdx");
8
- const processTemplateExpression_1 = require("../utils/processTemplateExpression");
9
9
  const removeDangerousCode_1 = require("../utils/removeDangerousCode");
10
10
  const traversalCache_1 = require("../utils/traversalCache");
11
- function preeval(babel, { eventEmitter = EventEmitter_1.EventEmitter.dummy, ...options }) {
11
+ function preeval(babel, options) {
12
12
  const { types: t } = babel;
13
+ const eventEmitter = options.eventEmitter ?? EventEmitter_1.EventEmitter.dummy;
13
14
  return {
14
15
  name: '@wyw-in-js/transform/preeval',
15
16
  pre(file) {
@@ -19,18 +20,14 @@ function preeval(babel, { eventEmitter = EventEmitter_1.EventEmitter.dummy, ...o
19
20
  const rootScope = file.scope;
20
21
  this.processors = [];
21
22
  eventEmitter.perf('transform:preeval:processTemplate', () => {
22
- file.path.traverse({
23
- Identifier: (p) => {
24
- (0, processTemplateExpression_1.processTemplateExpression)(p, file.opts, options, (processor) => {
25
- processor.dependencies.forEach((dependency) => {
26
- if (dependency.ex.type === 'Identifier') {
27
- (0, addIdentifierToWywPreval_1.addIdentifierToWywPreval)(rootScope, dependency.ex.name);
28
- }
29
- });
30
- processor.doEvaltimeReplacement();
31
- this.processors.push(processor);
32
- });
33
- },
23
+ (0, getTagProcessor_1.applyProcessors)(file.path, file.opts, options, (processor) => {
24
+ processor.dependencies.forEach((dependency) => {
25
+ if (dependency.ex.type === 'Identifier') {
26
+ (0, addIdentifierToWywPreval_1.addIdentifierToWywPreval)(rootScope, dependency.ex.name);
27
+ }
28
+ });
29
+ processor.doEvaltimeReplacement();
30
+ this.processors.push(processor);
34
31
  });
35
32
  });
36
33
  if ((0, shared_1.isFeatureEnabled)(options.features, 'dangerousCodeRemover', filename)) {
@@ -1,6 +1,13 @@
1
1
  import type { NodePath } from '@babel/traverse';
2
- import type { Identifier } from '@babel/types';
2
+ import type { Program } from '@babel/types';
3
3
  import { BaseProcessor } from '@wyw-in-js/processor-utils';
4
- import type { IFileContext } from '@wyw-in-js/processor-utils';
4
+ import type { IFileContext, TagSource } from '@wyw-in-js/processor-utils';
5
5
  import type { StrictOptions } from '@wyw-in-js/shared';
6
- export declare function getTagProcessor(path: NodePath<Identifier>, fileContext: IFileContext, options: Pick<StrictOptions, 'classNameSlug' | 'displayName' | 'evaluate' | 'tagResolver'>): BaseProcessor | null;
6
+ import type { IImport } from './collectExportsAndImports';
7
+ type DefinedProcessor = [ProcessorClass, TagSource];
8
+ type DefinedProcessors = Map<string, DefinedProcessor>;
9
+ export type ProcessorClass = new (...args: ConstructorParameters<typeof BaseProcessor>) => BaseProcessor;
10
+ export declare function getProcessorForImport({ imported, source }: IImport, filename: string | null | undefined, options: Pick<StrictOptions, 'tagResolver'>): [ProcessorClass | null, TagSource];
11
+ export declare function getDefinedProcessors(imports: IImport[], path: NodePath<Program>, filename: string | null | undefined, options: Pick<StrictOptions, 'tagResolver'>): DefinedProcessors;
12
+ export declare function applyProcessors(path: NodePath<Program>, fileContext: IFileContext, options: Pick<StrictOptions, 'classNameSlug' | 'displayName' | 'evaluate' | 'tagResolver'>, callback: (processor: BaseProcessor) => void): void;
13
+ export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getTagProcessor = void 0;
3
+ exports.applyProcessors = exports.getDefinedProcessors = exports.getProcessorForImport = void 0;
4
4
  const fs_1 = require("fs");
5
5
  const path_1 = require("path");
6
6
  const core_1 = require("@babel/core");
@@ -76,52 +76,21 @@ function getProcessorFromFile(processorPath) {
76
76
  }
77
77
  return Processor;
78
78
  }
79
- function getProcessorForIdentifier(path, imports, filename, options) {
80
- const pathBinding = path.scope.getBinding(path.node.name);
81
- if (!pathBinding) {
82
- // It's not a binding, so it's not a tag
83
- return [null, null, null];
84
- }
79
+ function getProcessorForImport({ imported, source }, filename, options) {
85
80
  const tagResolver = options.tagResolver ?? (() => null);
86
- // FIXME: can be simplified
87
- const relatedImports = imports
88
- .map((i) => {
89
- const { local } = i;
90
- if (local === path) {
91
- return [i, null];
92
- }
93
- if (!local.isIdentifier()) {
94
- if (path.isDescendant(local)) {
95
- return [i, local];
96
- }
97
- return null;
98
- }
99
- const binding = local.scope.getBinding(local.node.name);
100
- if (pathBinding === binding) {
101
- return [i, path];
102
- }
103
- return null;
104
- })
105
- .filter(isNotNull_1.isNotNull)
106
- .filter((i) => i[1] === null || i[1].isExpression());
107
- if (relatedImports.length === 0) {
108
- return [null, null, null];
109
- }
110
- const [Processor = null, tagSource = null, tagPath = null] = relatedImports
111
- .map(([{ imported, source }, p]) => {
112
- const customFile = tagResolver(source, imported);
113
- const processor = customFile
114
- ? getProcessorFromFile(customFile)
115
- : getProcessorFromPackage(source, imported, filename);
116
- return [processor, { imported, source }, p];
117
- })
118
- .find(([proc]) => proc) ?? [];
119
- return Processor === null || tagSource === null || tagPath === null
120
- ? [null, null, null]
121
- : [Processor, tagSource, tagPath];
81
+ const customFile = tagResolver(source, imported);
82
+ const processor = customFile
83
+ ? getProcessorFromFile(customFile)
84
+ : getProcessorFromPackage(source, imported, filename);
85
+ return [processor, { imported, source }];
122
86
  }
123
- function getBuilderForIdentifier(path, imports, filename, options) {
124
- const [Processor, tagSource, tagPath] = getProcessorForIdentifier(path, imports, filename, options);
87
+ exports.getProcessorForImport = getProcessorForImport;
88
+ function getBuilderForIdentifier(definedProcessor, path, imports, options) {
89
+ const [Processor, tagSource] = definedProcessor;
90
+ let tagPath = path;
91
+ if (tagPath.parentPath?.isMemberExpression({ property: tagPath.node })) {
92
+ tagPath = tagPath.parentPath;
93
+ }
125
94
  if (!Processor || !tagSource || !tagPath) {
126
95
  return null;
127
96
  }
@@ -193,11 +162,18 @@ function getBuilderForIdentifier(path, imports, filename, options) {
193
162
  }
194
163
  });
195
164
  };
196
- const astService = {
197
- ...core_1.types,
165
+ const importHelpers = {
198
166
  addDefaultImport: (importedSource, nameHint) => (0, helper_module_imports_1.addDefault)(path, importedSource, { nameHint }),
199
167
  addNamedImport: (name, importedSource, nameHint = name) => (0, helper_module_imports_1.addNamed)(path, name, importedSource, { nameHint }),
200
168
  };
169
+ const astService = new Proxy(core_1.types, {
170
+ get(target, prop, receiver) {
171
+ if (prop in importHelpers) {
172
+ return importHelpers[prop];
173
+ }
174
+ return Reflect.get(target, prop, receiver);
175
+ },
176
+ });
201
177
  return (...args) => new Processor(params, tagSource, astService, tagPath.node.loc ?? null, replacer, ...args);
202
178
  }
203
179
  function getDisplayName(path, idx, filename) {
@@ -279,13 +255,42 @@ const getNextIndex = (state) => {
279
255
  counters.set(state, counter + 1);
280
256
  return counter;
281
257
  };
282
- function getTagProcessor(path, fileContext, options) {
283
- const cache = (0, traversalCache_1.getTraversalCache)(path, 'getTagProcessor');
258
+ function getDefinedProcessors(imports, path, filename, options) {
259
+ const cache = (0, traversalCache_1.getTraversalCache)(path, 'getDefinedProcessors');
260
+ if (!cache.has(path)) {
261
+ const defined = new Map();
262
+ imports.forEach((i) => {
263
+ const [processor, tagSource] = getProcessorForImport(i, filename, options);
264
+ const { local } = i;
265
+ if (!processor) {
266
+ return;
267
+ }
268
+ let name = null;
269
+ if (local.isIdentifier()) {
270
+ name = local.node.name;
271
+ }
272
+ if (name === null && local.isMemberExpression()) {
273
+ const property = local.get('property');
274
+ const object = local.get('object');
275
+ if (property.isIdentifier() && object.isIdentifier()) {
276
+ name = `${object.node.name}.${property.node.name}`;
277
+ }
278
+ }
279
+ if (name === null) {
280
+ return;
281
+ }
282
+ defined.set(name, [processor, tagSource]);
283
+ });
284
+ cache.set(path, defined);
285
+ }
286
+ return cache.get(path);
287
+ }
288
+ exports.getDefinedProcessors = getDefinedProcessors;
289
+ function createProcessorInstance(definedProcessor, imports, path, fileContext, options) {
290
+ const cache = (0, traversalCache_1.getTraversalCache)(path, 'createProcessorInstance');
284
291
  if (!cache.has(path.node)) {
285
- const root = path.scope.getProgramParent().path;
286
- const { imports } = (0, collectExportsAndImports_1.collectExportsAndImports)(root);
287
292
  try {
288
- const builder = getBuilderForIdentifier(path, imports.filter(collectExportsAndImports_1.explicitImport), fileContext.filename, options);
293
+ const builder = getBuilderForIdentifier(definedProcessor, path, imports, options);
289
294
  if (builder) {
290
295
  // Increment the index of the style we're processing
291
296
  // This is used for slug generation to prevent collision
@@ -312,4 +317,54 @@ function getTagProcessor(path, fileContext, options) {
312
317
  }
313
318
  return cache.get(path.node) ?? null;
314
319
  }
315
- exports.getTagProcessor = getTagProcessor;
320
+ function applyProcessors(path, fileContext, options, callback) {
321
+ const imports = (0, collectExportsAndImports_1.collectExportsAndImports)(path).imports.filter(collectExportsAndImports_1.explicitImport);
322
+ const definedProcessors = getDefinedProcessors(imports, path, fileContext.filename, options);
323
+ const usages = [];
324
+ definedProcessors.forEach((processor, idName) => {
325
+ if (idName.includes('.')) {
326
+ // It's a member expression
327
+ const [object, property] = idName.split('.');
328
+ const objBinding = path.scope.getBinding(object);
329
+ if (!objBinding) {
330
+ return;
331
+ }
332
+ objBinding.referencePaths.forEach((p) => {
333
+ const parent = p.parentPath;
334
+ if (!parent?.isMemberExpression()) {
335
+ return;
336
+ }
337
+ const identifier = parent.get('property');
338
+ if (identifier.isIdentifier({ name: property })) {
339
+ usages.push({
340
+ identifier,
341
+ processor,
342
+ });
343
+ }
344
+ });
345
+ return;
346
+ }
347
+ path.scope.getBinding(idName)?.referencePaths.forEach((identifier) => {
348
+ if (identifier.isIdentifier()) {
349
+ usages.push({
350
+ identifier,
351
+ processor,
352
+ });
353
+ }
354
+ });
355
+ });
356
+ // The same order, the same slugs
357
+ usages.sort((a, b) => (a.identifier.node.start ?? 0) - (b.identifier.node.start ?? 0));
358
+ usages.forEach((usage) => {
359
+ const definedProcessor = usage.processor;
360
+ if (!definedProcessor) {
361
+ return;
362
+ }
363
+ const instance = createProcessorInstance(definedProcessor, imports, usage.identifier, fileContext, options);
364
+ if (instance === null) {
365
+ return;
366
+ }
367
+ callback(instance);
368
+ });
369
+ }
370
+ exports.applyProcessors = applyProcessors;
@@ -1,11 +0,0 @@
1
- import { getTagProcessor } from './getTagProcessor';
2
- const processed = new WeakSet();
3
- export const processTemplateExpression = (p, fileContext, options, emit) => {
4
- if (p.parentPath.isExportSpecifier()) return;
5
- if (processed.has(p.node)) return;
6
- const tagProcessor = getTagProcessor(p, fileContext, options);
7
- processed.add(p.node);
8
- if (tagProcessor === null) return;
9
- emit(tagProcessor);
10
- };
11
- //# sourceMappingURL=processTemplateExpression.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"processTemplateExpression.js","names":["getTagProcessor","processed","WeakSet","processTemplateExpression","p","fileContext","options","emit","parentPath","isExportSpecifier","has","node","tagProcessor","add"],"sources":["../../src/utils/processTemplateExpression.ts"],"sourcesContent":["import type { NodePath } from '@babel/traverse';\nimport type { Identifier } from '@babel/types';\n\nimport type { BaseProcessor, IFileContext } from '@wyw-in-js/processor-utils';\nimport type { StrictOptions } from '@wyw-in-js/shared';\n\nimport { getTagProcessor } from './getTagProcessor';\n\nconst processed = new WeakSet<Identifier>();\n\nexport const processTemplateExpression = (\n p: NodePath<Identifier>,\n fileContext: IFileContext,\n options: Pick<\n StrictOptions,\n 'classNameSlug' | 'displayName' | 'evaluate' | 'tagResolver'\n >,\n emit: (processor: BaseProcessor) => void\n) => {\n if (p.parentPath.isExportSpecifier()) return;\n if (processed.has(p.node)) return;\n\n const tagProcessor = getTagProcessor(p, fileContext, options);\n\n processed.add(p.node);\n\n if (tagProcessor === null) return;\n\n emit(tagProcessor);\n};\n"],"mappings":"AAMA,SAASA,eAAe,QAAQ,mBAAmB;AAEnD,MAAMC,SAAS,GAAG,IAAIC,OAAO,CAAa,CAAC;AAE3C,OAAO,MAAMC,yBAAyB,GAAGA,CACvCC,CAAuB,EACvBC,WAAyB,EACzBC,OAGC,EACDC,IAAwC,KACrC;EACH,IAAIH,CAAC,CAACI,UAAU,CAACC,iBAAiB,CAAC,CAAC,EAAE;EACtC,IAAIR,SAAS,CAACS,GAAG,CAACN,CAAC,CAACO,IAAI,CAAC,EAAE;EAE3B,MAAMC,YAAY,GAAGZ,eAAe,CAACI,CAAC,EAAEC,WAAW,EAAEC,OAAO,CAAC;EAE7DL,SAAS,CAACY,GAAG,CAACT,CAAC,CAACO,IAAI,CAAC;EAErB,IAAIC,YAAY,KAAK,IAAI,EAAE;EAE3BL,IAAI,CAACK,YAAY,CAAC;AACpB,CAAC"}
@@ -1,18 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.processTemplateExpression = void 0;
7
- var _getTagProcessor = require("./getTagProcessor");
8
- const processed = new WeakSet();
9
- const processTemplateExpression = (p, fileContext, options, emit) => {
10
- if (p.parentPath.isExportSpecifier()) return;
11
- if (processed.has(p.node)) return;
12
- const tagProcessor = (0, _getTagProcessor.getTagProcessor)(p, fileContext, options);
13
- processed.add(p.node);
14
- if (tagProcessor === null) return;
15
- emit(tagProcessor);
16
- };
17
- exports.processTemplateExpression = processTemplateExpression;
18
- //# sourceMappingURL=processTemplateExpression.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"processTemplateExpression.js","names":["_getTagProcessor","require","processed","WeakSet","processTemplateExpression","p","fileContext","options","emit","parentPath","isExportSpecifier","has","node","tagProcessor","getTagProcessor","add","exports"],"sources":["../../src/utils/processTemplateExpression.ts"],"sourcesContent":["import type { NodePath } from '@babel/traverse';\nimport type { Identifier } from '@babel/types';\n\nimport type { BaseProcessor, IFileContext } from '@wyw-in-js/processor-utils';\nimport type { StrictOptions } from '@wyw-in-js/shared';\n\nimport { getTagProcessor } from './getTagProcessor';\n\nconst processed = new WeakSet<Identifier>();\n\nexport const processTemplateExpression = (\n p: NodePath<Identifier>,\n fileContext: IFileContext,\n options: Pick<\n StrictOptions,\n 'classNameSlug' | 'displayName' | 'evaluate' | 'tagResolver'\n >,\n emit: (processor: BaseProcessor) => void\n) => {\n if (p.parentPath.isExportSpecifier()) return;\n if (processed.has(p.node)) return;\n\n const tagProcessor = getTagProcessor(p, fileContext, options);\n\n processed.add(p.node);\n\n if (tagProcessor === null) return;\n\n emit(tagProcessor);\n};\n"],"mappings":";;;;;;AAMA,IAAAA,gBAAA,GAAAC,OAAA;AAEA,MAAMC,SAAS,GAAG,IAAIC,OAAO,CAAa,CAAC;AAEpC,MAAMC,yBAAyB,GAAGA,CACvCC,CAAuB,EACvBC,WAAyB,EACzBC,OAGC,EACDC,IAAwC,KACrC;EACH,IAAIH,CAAC,CAACI,UAAU,CAACC,iBAAiB,CAAC,CAAC,EAAE;EACtC,IAAIR,SAAS,CAACS,GAAG,CAACN,CAAC,CAACO,IAAI,CAAC,EAAE;EAE3B,MAAMC,YAAY,GAAG,IAAAC,gCAAe,EAACT,CAAC,EAAEC,WAAW,EAAEC,OAAO,CAAC;EAE7DL,SAAS,CAACa,GAAG,CAACV,CAAC,CAACO,IAAI,CAAC;EAErB,IAAIC,YAAY,KAAK,IAAI,EAAE;EAE3BL,IAAI,CAACK,YAAY,CAAC;AACpB,CAAC;AAACG,OAAA,CAAAZ,yBAAA,GAAAA,yBAAA"}
@@ -1,5 +0,0 @@
1
- import type { NodePath } from '@babel/traverse';
2
- import type { Identifier } from '@babel/types';
3
- import type { BaseProcessor, IFileContext } from '@wyw-in-js/processor-utils';
4
- import type { StrictOptions } from '@wyw-in-js/shared';
5
- export declare const processTemplateExpression: (p: NodePath<Identifier>, fileContext: IFileContext, options: Pick<StrictOptions, 'classNameSlug' | 'displayName' | 'evaluate' | 'tagResolver'>, emit: (processor: BaseProcessor) => void) => void;
@@ -1,17 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.processTemplateExpression = void 0;
4
- const getTagProcessor_1 = require("./getTagProcessor");
5
- const processed = new WeakSet();
6
- const processTemplateExpression = (p, fileContext, options, emit) => {
7
- if (p.parentPath.isExportSpecifier())
8
- return;
9
- if (processed.has(p.node))
10
- return;
11
- const tagProcessor = (0, getTagProcessor_1.getTagProcessor)(p, fileContext, options);
12
- processed.add(p.node);
13
- if (tagProcessor === null)
14
- return;
15
- emit(tagProcessor);
16
- };
17
- exports.processTemplateExpression = processTemplateExpression;