Skip to content

Commit

Permalink
Support .mjs and .mts specifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
wojpawlik committed Oct 6, 2023
1 parent bd444ad commit 40d534f
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 20 deletions.
25 changes: 10 additions & 15 deletions src/_transformations/specifiers.test.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
import fc from "https://cdn.skypack.dev/fast-check@3.8.0?dts";
import { transpileSpecifier } from "./specifiers.ts";
import fc from "https://esm.sh/fast-check@3.10.0";
import { name, services, transpileSpecifier } from "./specifiers.ts";

const join = (array: string[]) => array.join("");
const path = fc.option(fc.webPath(), { nil: "" });
const relativePrefix = fc.constantFrom("./", "../");
const extension = fc.constantFrom("js", "ts", "jsx", "tsx");
const version = fc.webSegment().map((s) => s ? `@${s}` : "");
const query = fc.webQueryParameters().map((s) => s ? `?${s}` : "");
const name = fc.stringOf(fc.char().filter((c) => /[\w.-]/.test(c)));
const relativePath = fc.tuple(relativePrefix, fc.webPath()).map(join);

const scopedPackage = fc.tuple(
name.map((s) => s ? `@${s}/` : ""),
name.filter(Boolean),
).map(join);

const service = fc.constantFrom(
"npm:",
"https://esm.sh/",
"https://cdn.skypack.dev/",
const urlSegments = fc.tuple(
fc.constantFrom(...services),
fc.stringMatching(name),
version,
fc.option(fc.webPath(), { nil: "" }),
fc.webQueryParameters().map((s) => s ? `?${s}` : ""),
);

Deno.test(function localSpecifiers() {
Expand All @@ -27,14 +21,15 @@ Deno.test(function localSpecifiers() {
relativePath,
extension,
(path, ext) =>
transpileSpecifier(`${path}.deno.m${ext}`) === `${path}.node.mjs` &&
transpileSpecifier(`${path}.deno.${ext}`) === `${path}.node.js`,
),
);
});

Deno.test(function remoteSpecifiers() {
fc.assert(
fc.property(service, scopedPackage, version, path, query, (...segments) => {
fc.property(urlSegments, (segments) => {
const [, scopedPackage, , path] = segments;
return transpileSpecifier(join(segments)) === scopedPackage + path;
}),
Expand Down
19 changes: 14 additions & 5 deletions src/_transformations/specifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ const url = re.tag()`^${re.union(services)}(${name})${version}?(${path})?.*$`;
const transpileHttpsImport = (specifier: string) =>
specifier.replace(url, "$1$2");

export const transpileExtension = (specifier: string) =>
specifier.replace(/[jt]sx?$/i, "js");

const transpileRelativeImport = (specifier: string) =>
specifier
.replace(/\.[jt]sx?$/i, ".js")
.replace(/\.deno\.js$/i, ".node.js");
transpileExtension(specifier).replace(".deno.", ".node.");

const isRelative = (specifier: string) => /^\.\.?\//.test(specifier);

Expand All @@ -22,15 +23,23 @@ export const transpileSpecifier = (specifier: string) => {
return transpileHttpsImport(specifier);
};

export function transpileSpecifiers(sourceFile: SourceFile) {
/**
* Replaces all import/export specifiers in `sourceFile`
* according to the specified `transpileSpecifier` function.
* The default one makes specifiers Node-friendly.
*/
export function transpileSpecifiers(
sourceFile: SourceFile,
fn = transpileSpecifier,
) {
for (const statement of sourceFile.getStatements()) {
if (
Node.isImportDeclaration(statement) ||
Node.isExportDeclaration(statement)
) {
const modSpecifierValue = statement.getModuleSpecifierValue();
if (modSpecifierValue !== undefined) {
statement.setModuleSpecifier(transpileSpecifier(modSpecifierValue));
statement.setModuleSpecifier(fn(modSpecifierValue));
}
}
}
Expand Down

0 comments on commit 40d534f

Please sign in to comment.