rollup#TransformResult TypeScript Examples

The following examples show how to use rollup#TransformResult. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: sass.ts    From stencil-tailwind with MIT License 6 votes vote down vote up
export default async function _transformSass(code: string): Promise<TransformResult> {
  const match = /(.* = ")(.*)(";[\s|\S]*)/.exec(code)
  const transformedStyles = await postcss([ tailwindcss() ])
    .process(match![2].replace(/\(\\"/g, '("').replace(/\\"\)/g, '")').replace(/\\n/g, ''))
    .then(result => match![1] + result.toString() + match![3])
  return {
    code: transformedStyles.replace(/[\n\r]*/g, '')
  }
}
Example #2
Source File: tsx.ts    From stencil-tailwind with MIT License 6 votes vote down vote up
export default function transformTsx(code: string, node: Node, cssRoot: Root): TransformResult {
  let match = /= (.*?Style);/.exec(code)
  if (match) {
    debug.red('transformTsx:code:\n',code)
    const s = new MagicString(code)
    const utilityClasses = _buildTailwindClassList(node, cssRoot)
    if (utilityClasses) {
      s.overwrite(match.index, match.index + match[1].length + 2,`= \`${utilityClasses} \${${match[1]}}\``)
    }
    return {
      code: s.toString().replace(/\\:/g, '\\\\:')
    }
  }
}
Example #3
Source File: pluginContainer.ts    From icepkg with MIT License 4 votes vote down vote up
export async function createPluginContainer(
  { plugins, logger, root, output, build: { rollupOptions } },
  moduleGraph?: any,
  watcher?: FSWatcher,
): Promise<PluginContainer> {
  let ids = 0; // counter for generating unique emitted asset IDs
  const files = new Map();

  const isDebug = process.env.DEBUG;

  const seenResolves: Record<string, true | undefined> = {};

  const debugResolve = createLogger('resolve');
  const debugPluginResolve = createDebugger('plugin-resolve');
  const debugPluginTransform = createDebugger('plugin-transform');

  const watchFiles = new Set<string>();

  // get rollup version
  const rollupPkgPath = resolve(require.resolve('rollup'), '../../package.json');
  const minimalContext: MinimalPluginContext = {
    meta: {
      rollupVersion: safeRequire(rollupPkgPath)
        .version,
      // rollupVersion: '2.3.4',
      watchMode: true,
    },
  };

  function warnIncompatibleMethod(method: string, plugin: string) {
    logger.warn(
      colors.cyan(`[plugin:${plugin}] `) +
        colors.yellow(
          `context method ${colors.bold(
            `${method}()`,
          )} is not supported in serve mode. This plugin is likely not vite-compatible.`,
        ),
    );
  }

  // throw when an unsupported ModuleInfo property is accessed,
  // so that incompatible plugins fail in a non-cryptic way.
  const ModuleInfoProxy: ProxyHandler<ModuleInfo> = {
    get(info: any, key: string) {
      if (key in info) {
        return info[key];
      }
      throw Error(
        `[vite] The "${key}" property of ModuleInfo is not supported.`,
      );
    },
  };

  // same default value of "moduleInfo.meta" as in Rollup
  const EMPTY_OBJECT = Object.freeze({});

  function getModuleInfo(id: string) {
    const module = moduleGraph?.getModuleById(id);
    if (!module) {
      return null;
    }
    if (!module.info) {
      module.info = new Proxy(
        // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
        { id, meta: module.meta || EMPTY_OBJECT } as ModuleInfo,
        ModuleInfoProxy,
      );
    }
    return module.info;
  }

  function updateModuleInfo(id: string, { meta }: { meta?: object | null }) {
    if (meta) {
      const moduleInfo = getModuleInfo(id);
      if (moduleInfo) {
        moduleInfo.meta = { ...moduleInfo.meta, ...meta };
      }
    }
  }

  // we should create a new context for each async hook pipeline so that the
  // active plugin in that pipeline can be tracked in a concurrency-safe manner.
  // using a class to make creating new contexts more efficient
  class Context implements PluginContext {
    meta = minimalContext.meta;
    ssr = false;
    _activePlugin: Plugin | null;
    _activeId: string | null = null;
    _activeCode: string | null = null;
    _resolveSkips?: Set<Plugin>;
    _addedImports: Set<string> | null = null;

    constructor(initialPlugin?: Plugin) {
      this._activePlugin = initialPlugin || null;
    }

    parse(code: string, opts: any = {}) {
      return parser.parse(code, {
        sourceType: 'module',
        ecmaVersion: 'latest',
        locations: true,
        ...opts,
      });
    }

    async resolve(
      id: string,
      importer?: string,
      options?: { skipSelf?: boolean },
    ) {
      let skip: Set<Plugin> | undefined;
      if (options?.skipSelf && this._activePlugin) {
        skip = new Set(this._resolveSkips);
        skip.add(this._activePlugin);
      }
      let out = await container.resolveId(id, importer, { skip, ssr: this.ssr });
      if (typeof out === 'string') out = { id: out };
      return out as ResolvedId | null;
    }

    getModuleInfo(id: string) {
      return getModuleInfo(id);
    }

    getModuleIds() {
      return moduleGraph
        ? moduleGraph.idToModuleMap.keys()
        : Array.prototype[Symbol.iterator]();
    }

    addWatchFile(id: string) {
      watchFiles.add(id);
      (this._addedImports || (this._addedImports = new Set())).add(id);
      if (watcher) ensureWatchedFile(watcher, id, root);
    }

    getWatchFiles() {
      return [...watchFiles];
    }

    emitFile(assetOrFile: EmittedFile) {
      function resolveFileName(fileName: string) {
        if (!fileName) return;
        if (isAbsolute(fileName)) return fileName;
        return resolve(root, output, fileName);
      }

      const { type, fileName } = assetOrFile;
      const name = type === 'chunk' ? assetOrFile.name || assetOrFile.id : assetOrFile.name;
      const source = type === 'asset' && assetOrFile.source;
      const filename = resolveFileName(fileName);

      const id = String(++ids);
      files.set(id, { id, name, filename });

      if (type === 'chunk') {
        consola.warn(`type ${type} of this.emitFile is not supported in transform mode. This plugin is likely not compatible`);
      } else if (source) {
        fs.writeFileSync(filename, source);
      }
      return id;
    }

    setAssetSource(assetId: string, source: string | Uint8Array) {
      const asset = files.get(String(assetId));
      if (asset.type === 'chunk') {
        return;
      }
      asset.source = source;
      fs.writeFile(asset.filename, source);
    }

    getFileName() {
      warnIncompatibleMethod('getFileName', this._activePlugin!.name);
      return '';
    }

    warn(
      e: string | RollupError,
      position?: number | { column: number; line: number },
    ) {
      const err = formatError(e, position, this);
      const msg = err.message;
      // const msg = buildErrorMessage(
      //   err,
      //   [colors.yellow(`warning: ${err.message}`)],
      //   false,
      // );
      logger.warn(msg, {
        clear: true,
        timestamp: true,
      });
    }

    error(
      e: string | RollupError,
      position?: number | { column: number; line: number },
    ): never {
      // error thrown here is caught by the transform middleware and passed on
      // the the error middleware.
      throw formatError(e, position, this);
    }
  }

  function formatError(
    e: string | RollupError,
    position: number | { column: number; line: number } | undefined,
    ctx: Context,
  ) {
    let err = (
      typeof e === 'string' ? new Error(e) : e
    ) as postcss.CssSyntaxError & RollupError;

    if (err.file && err.name === 'CssSyntaxError') {
      err.id = normalizePath(err.file);
    }
    if (ctx._activePlugin) err.plugin = ctx._activePlugin.name;
    if (ctx._activeId && !err.id) err.id = ctx._activeId;

    if (ctx._activeCode && !err.pluginCode) {
      err.pluginCode = ctx._activeCode;

      const pos =
        position != null
          ? position
          : err.pos != null
            ? err.pos
            : // some rollup plugins, e.g. json, sets position instead of pos
            (err as any).position;

      if (pos != null) {
        let errLocation;
        try {
          errLocation = numberToPos(ctx._activeCode, pos);
        } catch (err2) {
          logger.error(
            colors.red(
              `Error in error handler:\n${err2.stack || err2.message}\n`,
            ),
            // print extra newline to separate the two errors
            { error: err2 },
          );
          throw err;
        }
        err.loc = err.loc || {
          file: err.id,
          ...errLocation,
        };
        err.frame = err.frame || generateCodeFrame(ctx._activeCode, pos);
      } else if (err.loc) {
        // css preprocessors may report errors in an included file
        if (!err.frame) {
          let code = ctx._activeCode;
          if (err.loc.file) {
            err.id = normalizePath(err.loc.file);
            try {
              code = fs.readFileSync(err.loc.file, 'utf-8');
            } catch {
              // empty
            }
          }
          err.frame = generateCodeFrame(code, err.loc);
        }
      } else if ((err as any).line && (err as any).column) {
        err.loc = {
          file: err.id,
          line: (err as any).line,
          column: (err as any).column,
        };
        err.frame = err.frame || generateCodeFrame(err.id!, err.loc);
      }

      if (err.loc && ctx instanceof TransformContext) {
        const rawSourceMap = ctx._getCombinedSourcemap();
        if (rawSourceMap) {
          const consumer = new SourceMapConsumer(rawSourceMap as any);
          const { source, line, column } = consumer.originalPositionFor({
            line: Number(err.loc.line),
            column: Number(err.loc.column),
            bias: SourceMapConsumer.GREATEST_LOWER_BOUND,
          });
          if (source) {
            err.loc = { file: source, line, column };
          }
        }
      }
    }

    // Be consistent of rollup https://github.com/rollup/rollup/blob/master/src/utils/pluginUtils.ts#L7
    if (!(err instanceof Error)) {
      err = Object.assign(new Error(err.message), err);
    }

    return err;
  }

  class TransformContext extends Context {
    filename: string;
    originalCode: string;
    originalSourcemap: SourceMap | null = null;
    sourcemapChain: Array<NonNullable<SourceDescription['map']>> = [];
    combinedMap: SourceMap | null = null;

    constructor(filename: string, code: string, inMap?: SourceMap | string) {
      super();
      this.filename = filename;
      this.originalCode = code;
      if (inMap) {
        this.sourcemapChain.push(inMap);
      }
    }

    _getCombinedSourcemap(createIfNull = false) {
      let { combinedMap } = this;
      for (let m of this.sourcemapChain) {
        if (typeof m === 'string') m = JSON.parse(m);
        if (!('version' in (m as SourceMap))) {
          // empty, nullified source map
          this.combinedMap = null;
          combinedMap = this.combinedMap;
          this.sourcemapChain.length = 0;
          break;
        }
        if (!combinedMap) {
          combinedMap = m as SourceMap;
        } else {
          combinedMap = combineSourcemaps(this.filename, [
            {
              ...(m as RawSourceMap),
              sourcesContent: combinedMap.sourcesContent,
            },
            combinedMap as RawSourceMap,
          ]) as SourceMap;
        }
      }
      if (!combinedMap) {
        return createIfNull
          ? new MagicString(this.originalCode).generateMap({
            includeContent: true,
            hires: true,
            source: this.filename,
          })
          : null;
      }
      if (combinedMap !== this.combinedMap) {
        this.combinedMap = combinedMap;
        this.sourcemapChain.length = 0;
      }
      return this.combinedMap;
    }

    getCombinedSourcemap() {
      return this._getCombinedSourcemap(true) as SourceMap;
    }
  }

  let closed = false;

  const container: PluginContainer = {
    options: await (async () => {
      let options = rollupOptions;
      for (const plugin of plugins) {
        if (!plugin.options) continue;
        options =
          (await plugin.options.call(minimalContext, options)) || options;
      }
      if (options.acornInjectPlugins) {
        parser = acorn.Parser.extend(options.acornInjectPlugins as any);
      }
      return {
        acorn,
        acornInjectPlugins: [],
        ...options,
      };
    })(),

    getModuleInfo,

    async buildStart() {
      await Promise.all(
        plugins.map((plugin) => {
          if (plugin.buildStart) {
            return plugin.buildStart.call(
              new Context(plugin) as any,
              container.options as NormalizedInputOptions,
            );
          }
          return null;
        }),
      );
    },

    async resolveId(rawId, importer = join(root, 'index.html'), options) {
      const skip = options?.skip;
      const ssr = options?.ssr;
      const ctx = new Context();
      ctx.ssr = !!ssr;
      ctx._resolveSkips = skip;
      const resolveStart = isDebug ? performance.now() : 0;

      let id: string | null = null;
      const partial: Partial<PartialResolvedId> = {};
      for (const plugin of plugins) {
        if (!plugin.resolveId) continue;
        if (skip?.has(plugin)) continue;

        ctx._activePlugin = plugin;

        const pluginResolveStart = isDebug ? performance.now() : 0;
        const result = await plugin.resolveId.call(
          ctx as any,
          rawId,
          importer,
          { ssr },
        );
        if (!result) continue;

        if (typeof result === 'string') {
          id = result;
        } else {
          id = result.id;
          Object.assign(partial, result);
        }

        isDebug &&
          debugPluginResolve.info(
            timeFrom(pluginResolveStart),
            plugin.name,
            // prettifyUrl(id, root),
          );

        // resolveId() is hookFirst - first non-null result is returned.
        break;
      }

      if (isDebug && rawId !== id && !rawId.startsWith(FS_PREFIX)) {
        const key = rawId + id;
        // avoid spamming
        if (!seenResolves[key]) {
          seenResolves[key] = true;
          debugResolve.info(
            `${timeFrom(resolveStart)}`,
            `${colors.cyan(rawId)} -> ${colors.dim(
              id,
            )}`,
          );
        }
      }

      if (id) {
        partial.id = isExternalUrl(id) ? id : normalizePath(id);
        return partial as PartialResolvedId;
      } else {
        return null;
      }
    },

    async load(id, options) {
      const ssr = options?.ssr;
      const ctx = new Context();
      ctx.ssr = !!ssr;
      for (const plugin of plugins) {
        if (!plugin.load) continue;
        ctx._activePlugin = plugin;
        // eslint-disable-next-line no-await-in-loop
        const result = await plugin.load.call(ctx as any, id, { ssr });
        if (result != null) {
          if (isObject(result)) {
            updateModuleInfo(id, result);
          }
          return result;
        }
      }
      return null;
    },

    async transform(code, id, options) {
      const inMap = options?.inMap;
      const ssr = options?.ssr;
      const ctx = new TransformContext(id, code, inMap as SourceMap);
      ctx.ssr = !!ssr;
      let meta = null;
      for (const plugin of plugins) {
        if (!plugin.transform) continue;
        ctx._activePlugin = plugin;
        ctx._activeId = id;
        ctx._activeCode = code;
        const start = isDebug ? performance.now() : 0;
        let result: TransformResult | string | undefined;
        try {
          // eslint-disable-next-line no-await-in-loop
          result = await plugin.transform.call(ctx as any, code, id, { ssr });
        } catch (e) {
          ctx.error(e);
        }
        if (!result) continue;
        isDebug &&
          debugPluginTransform(
            timeFrom(start),
            plugin.name,
            // prettifyUrl(id, root),
          );
        if (isObject(result)) {
          if (result.code !== undefined) {
            code = result.code;
            if (result.map) {
              ctx.sourcemapChain.push(result.map);
            }

            // Add to support custom meta info
            if (result.meta) {
              meta = result.meta;
            }
          }
          updateModuleInfo(id, result);
        } else {
          code = result;
        }
      }
      return {
        code,
        map: ctx._getCombinedSourcemap(),
        meta,
      };
    },

    async close() {
      if (closed) return;
      const ctx = new Context();
      await Promise.all(
        plugins.map((p) => p.buildEnd && p.buildEnd.call(ctx as any)),
      );
      await Promise.all(
        plugins.map((p) => p.closeBundle && p.closeBundle.call(ctx as any)),
      );
      closed = true;
    },
  };

  return container;
}