Skip to content

Commit

Permalink
feat(esm): support new import attributes syntax (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 authored Mar 30, 2024
1 parent 6c03a07 commit 0c2da07
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 35 deletions.
78 changes: 48 additions & 30 deletions src/esm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,50 @@ import { CodegenOptions } from "./types";
import { genString } from "./string";

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
// https://tc39.es/ecma262/multipage/ecmascript-language-scripts-and-modules.html#sec-imports
export type ESMImport = string | { name: string; as?: string };

export interface ESMCodeGenOptions extends CodegenOptions {
// https://github.com/tc39/proposal-import-attributes
// https://nodejs.org/api/esm.html#import-attributes
attributes?: { type: string };
/** @deprecated use attributes */
assert?: { type: string };
}

export interface DynamicImportOptions extends ESMCodeGenOptions {
comment?: string;
wrapper?: boolean;
interopDefault?: boolean;
}

export function genImport(
specifier: string,
imports?: ESMImport | ESMImport[],
options: CodegenOptions = {},
options: ESMCodeGenOptions = {},
) {
return _genStatement("import", specifier, imports, options);
}

export function genTypeImport(
specifier: string,
imports: ESMImport[],
options: CodegenOptions = {},
options: ESMCodeGenOptions = {},
) {
return _genStatement("import type", specifier, imports, options);
}

export function genTypeExport(
specifier: string,
imports: ESMImport[],
options: CodegenOptions = {},
options: ESMCodeGenOptions = {},
) {
return _genStatement("export type", specifier, imports, options);
}

export const genInlineTypeImport = (
specifier: string,
name = "default",
options: CodegenOptions = {},
options: ESMCodeGenOptions = {},
) => {
return `typeof ${genDynamicImport(specifier, {
...options,
Expand All @@ -47,7 +60,7 @@ export type ESMExport = string | { name: string; as?: string };
export function genExport(
specifier: string,
exports?: ESMExport | ESMExport[],
options: CodegenOptions = {},
options: ESMCodeGenOptions = {},
) {
return _genStatement("export", specifier, exports, options);
}
Expand All @@ -58,7 +71,7 @@ function _genStatement(
type: ImportExportType,
specifier: string,
names?: ESMImportOrExport | ESMImportOrExport[],
options: CodegenOptions = {},
options: ESMCodeGenOptions = {},
) {
const specifierString = genString(specifier, options);
if (!names) {
Expand Down Expand Up @@ -86,36 +99,35 @@ function _genStatement(
return `${type} { ${namesString} } from ${genString(
specifier,
options,
)}${_genAssertClause(type, options.assert)};`;
)}${_genImportAttributes(type, options)};`;
}
return `${type} ${namesString} from ${genString(
specifier,
options,
)}${_genAssertClause(type, options.assert)};`;
)}${_genImportAttributes(type, options)};`;
}

function _genAssertClause(type: ImportExportType, assert?: { type: string }) {
function _genImportAttributes(
type: ImportExportType,
options: ESMCodeGenOptions,
) {
// import assertions isn't specified type-only import or export on Typescript
if (type === "import type" || type === "export type") {
return "";
}
// currently, `type` only
if (!assert || typeof assert !== "object") {
return "";

if (typeof options.attributes?.type === "string") {
return ` with { type: ${genString(options.attributes.type)} }`;
}
return ` assert { type: ${genString(assert.type)} }`;
}

export interface DynamicImportOptions extends CodegenOptions {
comment?: string;
wrapper?: boolean;
interopDefault?: boolean;
// https://github.com/tc39/proposal-import-assertions
// https://tc39.es/proposal-import-assertions/
assert?: {
type: string;
};
// TODO: Remove deprecated `assert` in the next major release
if (typeof options.assert?.type === "string") {
return ` assert { type: ${genString(options.assert.type)} }`;
}

return "";
}

export function genDynamicImport(
specifier: string,
options: DynamicImportOptions = {},
Expand All @@ -125,18 +137,24 @@ export function genDynamicImport(
const ineropString = options.interopDefault
? ".then(m => m.default || m)"
: "";
const optionsString = _genDynamicImportOptions(options);
const optionsString = _genDynamicImportAttributes(options);
return `${wrapperString}import(${genString(
specifier,
options,
)}${commentString}${optionsString})${ineropString}`;
}

function _genDynamicImportOptions(options: DynamicImportOptions = {}) {
// currently, `assert` option only
return options.assert && typeof options.assert === "object"
? `, { assert: { type: ${genString(options.assert.type)} } }`
: "";
function _genDynamicImportAttributes(options: DynamicImportOptions = {}) {
// TODO: Remove deprecated `assert` in the next major release
if (typeof options.assert?.type === "string") {
return `, { assert: { type: ${genString(options.assert.type)} } }`;
}

if (typeof options.attributes?.type === "string") {
return `, { with: { type: ${genString(options.attributes.type)} } }`;
}

return "";
}

export function genSafeVariableName(name: string) {
Expand Down
5 changes: 0 additions & 5 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
export interface CodegenOptions {
singleQuotes?: boolean;
// https://github.com/tc39/proposal-import-assertions
// https://tc39.es/proposal-import-assertions/
assert?: {
type: string;
};
}
9 changes: 9 additions & 0 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ const genImportTests = [
code: 'import { foo } from "pkg" assert { type: "json" };',
options: { assert: { type: "json" } },
},
{
names: ["foo"],
code: 'import { foo } from "pkg" with { type: "json" };',
options: { attributes: { type: "json" } },
},
];

describe("genImport", () => {
Expand Down Expand Up @@ -87,6 +92,10 @@ const genDynamicImportTests = [
opts: { assert: { type: "json" } },
code: '() => import("pkg", { assert: { type: "json" } })',
},
{
opts: { attributes: { type: "json" } },
code: '() => import("pkg", { with: { type: "json" } })',
},
];

describe("genDynamicImport", () => {
Expand Down

0 comments on commit 0c2da07

Please sign in to comment.