blob: 15f77e8b7df38a5dad3697b14de9f2cea49d4f03 [file] [log] [blame]
import { parseDestructuring, parseFrom, parseIdentifier, parseWith } from './partParsers.js';
import { addError, getPosition, stripComments } from './utils.js';
/**
* Adds error of parsing `export` statement with declaration.
*/
export const onDeclarationExportError = (importsExports, _source, { start, end }) => addError(importsExports, 'Cannot find end of export with declaration', start, end);
/**
* Parses `export` statement with declaration.
*/
export const onDeclarationExportParse = (importsExports, source, { start, end: unparsedStart, comments }, { start: unparsedEnd, end: exportEnd, match: endMatch }) => {
var end = exportEnd;
var isDeclare = false;
var isType = false;
var unparsed = stripComments(source, unparsedStart, unparsedEnd, comments).trim();
if (unparsed.startsWith('declare ')) {
isDeclare = true;
unparsed = unparsed.slice(8).trim();
}
if (unparsed.startsWith('type ')) {
isType = true;
unparsed = unparsed.slice(5).trim();
}
const modifiers = `${isDeclare ? 'declare ' : ''}${isType ? 'type ' : ''}`;
if (unparsed[0] === '*') {
if (isDeclare) {
return addError(importsExports, `Cannot declare star export (\`export ${modifiers}* ... from ...\`)`, start, end);
}
let namespace;
if (unparsed.startsWith('* as ')) {
unparsed = unparsed.slice(5).trim();
const spaceIndex = unparsed.indexOf(' ');
if (spaceIndex === -1) {
return addError(importsExports, `Cannot find namespace of \`export ${modifiers}* as ... from ...\` statement`, start, end);
}
namespace = unparsed.slice(0, spaceIndex);
unparsed = unparsed.slice(spaceIndex + 1);
}
if (unparsed[unparsed.length - 1] === ';') {
unparsed = unparsed.slice(0, -1).trim();
}
const { groups } = endMatch;
let quoteCharacter;
if (groups.with === undefined) {
quoteCharacter = unparsed[unparsed.length - 1];
unparsed = unparsed.slice(0, -1);
}
else {
quoteCharacter = groups.with[0];
}
const reexportKind = `${namespace === undefined ? 'star' : 'namespace'} reexport`;
if (quoteCharacter !== "'" && quoteCharacter !== '"') {
return addError(importsExports, `Cannot find end of \`from\` string literal of ${reexportKind}`, start, end);
}
const { from, index } = parseFrom(quoteCharacter, unparsed);
if (index === -1) {
return addError(importsExports, `Cannot find start of \`from\` string literal of ${reexportKind}`, start, end);
}
let withAttributes;
if (groups.with !== undefined) {
if (isType) {
return addError(importsExports, `Cannot use import attributes (\`with {...}\`) in \`export ${modifiers}\` statement for ${reexportKind} from \`${from}\``, start, end);
}
const attributes = parseWith(exportEnd, source);
if (attributes === undefined) {
return addError(importsExports, `Cannot find end of import attributes (\`with {...}\`) for ${reexportKind} from \`${from}\``, start, end);
}
end = attributes.endIndex;
withAttributes = attributes.with;
if (withAttributes === undefined) {
return addError(importsExports, `Cannot parse import attributes (\`with {...}\`) for ${reexportKind} from \`${from}\``, start, end);
}
}
const position = getPosition(importsExports, start, end);
const parsedReexport = withAttributes === undefined ? position : { ...position, with: withAttributes };
let key = 'starReexports';
if (namespace !== undefined) {
parsedReexport.namespace = namespace;
key = 'namespaceReexports';
}
if (isType) {
key = key === 'starReexports' ? 'typeStarReexports' : 'typeNamespaceReexports';
}
let reexports = importsExports[key];
reexports !== null && reexports !== void 0 ? reexports : (reexports = importsExports[key] = { __proto__: null });
let reexportsList = reexports[from];
if (reexportsList === undefined) {
reexports[from] = [parsedReexport];
}
else {
reexportsList.push(parsedReexport);
}
return end;
}
const identifierIndex = parseIdentifier(unparsed);
if (identifierIndex === 0) {
return addError(importsExports, `Cannot parse declaration identifier of \`export ${modifiers}...\` statement`, start, end);
}
const identifier = unparsed.slice(0, identifierIndex);
if (isType) {
let { typeExports } = importsExports;
if (typeExports === undefined) {
importsExports.typeExports = typeExports = { __proto__: null };
}
else if (identifier in typeExports) {
return addError(importsExports, `Duplicate exported type \`${identifier}\``, start, end);
}
typeExports[identifier] = getPosition(importsExports, start, end);
if (isDeclare) {
typeExports[identifier].isDeclare = true;
}
return;
}
if (identifier === 'default') {
if (isDeclare) {
return addError(importsExports, `Cannot export default with declare (\`export ${modifiers}default ...\`)`, start, end);
}
if (importsExports.defaultExport !== undefined) {
return addError(importsExports, 'Duplicate default export', start, end);
}
importsExports.defaultExport = getPosition(importsExports, start, end);
return;
}
unparsed = unparsed.slice(identifierIndex).trim();
if (identifier === 'interface') {
const nameIndex = parseIdentifier(unparsed);
if (nameIndex === 0) {
return addError(importsExports, `Cannot parse interface identifier of \`export ${modifiers}interface ...\` statement`, start, end);
}
const name = unparsed.slice(0, nameIndex);
let { interfaceExports } = importsExports;
interfaceExports !== null && interfaceExports !== void 0 ? interfaceExports : (interfaceExports = importsExports.interfaceExports = { __proto__: null });
const interfaceExport = getPosition(importsExports, start, end);
if (isDeclare) {
interfaceExport.isDeclare = true;
}
let exportsList = interfaceExports[name];
if (exportsList === undefined) {
interfaceExports[name] = [interfaceExport];
}
else {
exportsList.push(interfaceExport);
}
return;
}
if (identifier === 'namespace') {
const nameIndex = parseIdentifier(unparsed);
if (nameIndex === 0) {
return addError(importsExports, `Cannot parse namespace identifier of \`export ${modifiers}namespace ...\` statement`, start, end);
}
const name = unparsed.slice(0, nameIndex);
let { namespaceExports } = importsExports;
namespaceExports !== null && namespaceExports !== void 0 ? namespaceExports : (namespaceExports = importsExports.namespaceExports = { __proto__: null });
const namespaceExport = getPosition(importsExports, start, end);
if (isDeclare) {
namespaceExport.isDeclare = true;
}
let exportsList = namespaceExports[name];
if (exportsList === undefined) {
namespaceExports[name] = [namespaceExport];
}
else {
exportsList.push(namespaceExport);
}
return;
}
var isAsync = false;
var kind;
const names = [];
switch (identifier) {
case 'const':
case 'class':
case 'enum':
case 'let':
case 'var':
if ((identifier === 'const' || identifier === 'let' || identifier === 'var') &&
(unparsed[0] === '{' || unparsed[0] === '[')) {
const destructuring = parseDestructuring(unparsed + source.slice(end));
if (destructuring === undefined) {
return addError(importsExports, `Cannot parse destructuring names in \`export ${modifiers}${identifier} ...\` statement`, start, end);
}
const endDiff = destructuring.endIndex - unparsed.length;
if (endDiff > 0) {
end += endDiff;
}
names.push(...destructuring.names);
kind = `destructuring ${identifier}`;
if (isDeclare) {
kind = `declare ${kind}`;
}
break;
}
const nameIndex = parseIdentifier(unparsed);
if (nameIndex === 0) {
return addError(importsExports, `Cannot parse \`${identifier}\` identifier of \`export ${modifiers}${identifier} ...\` statement`, start, end);
}
kind = identifier;
if (isDeclare) {
kind = `declare ${kind}`;
}
names[0] = unparsed.slice(0, nameIndex);
if (identifier === 'const' && names[0] === 'enum') {
unparsed = unparsed.slice(4).trim();
const constEnumNameIndex = parseIdentifier(unparsed);
if (constEnumNameIndex === 0) {
return addError(importsExports, `Cannot parse identifier of \`export ${modifiers}const enum ...\` statement`, start, end);
}
kind = 'const enum';
if (isDeclare) {
kind = `declare ${kind}`;
}
names[0] = unparsed.slice(0, constEnumNameIndex);
}
break;
case 'abstract':
if (!unparsed.startsWith('class ')) {
return addError(importsExports, `Cannot parse declaration of abstract class of \`export ${modifiers}abstract ...\` statement`, start, end);
}
unparsed = unparsed.slice(5).trim();
const abstractClassNameIndex = parseIdentifier(unparsed);
if (abstractClassNameIndex === 0) {
return addError(importsExports, `Cannot parse \`${identifier}\` identifier of \`export ${modifiers}abstract class ${identifier} ...\` statement`, start, end);
}
kind = 'abstract class';
if (isDeclare) {
kind = `declare ${kind}`;
}
names[0] = unparsed.slice(0, abstractClassNameIndex);
break;
// @ts-expect-error
case 'async':
if (isDeclare) {
return addError(importsExports, `Cannot export async function with declare (\`export ${modifiers}async ...\`)`, start, end);
}
if (unparsed.startsWith('function') === false) {
return addError(importsExports, 'Cannot parse async function in `export async ...` statement', start, end);
}
isAsync = true;
unparsed = unparsed.slice(8).trim();
case 'function':
if (unparsed[0] === '*') {
if (isDeclare) {
return addError(importsExports, `Cannot export generator function with declare (\`export ${modifiers}function* ...\`)`, start, end);
}
unparsed = unparsed.slice(1).trim();
kind = 'function*';
}
else {
kind = 'function';
}
if (isAsync) {
kind = `async ${kind}`;
}
else if (isDeclare) {
kind = 'declare function';
}
const functionNameIndex = parseIdentifier(unparsed);
if (functionNameIndex === 0) {
return addError(importsExports, `Cannot parse \`${kind}\` identifier of \`export ${modifiers}${kind} ...\` statement`, start, end);
}
names[0] = unparsed.slice(0, functionNameIndex);
break;
default:
return addError(importsExports, `Cannot parse \`export ${modifiers}${identifier} ...\` statement`, start, end);
}
var { declarationExports } = importsExports;
declarationExports !== null && declarationExports !== void 0 ? declarationExports : (declarationExports = importsExports.declarationExports = {
__proto__: null,
});
for (const name of names) {
if (name in declarationExports) {
return addError(importsExports, `Duplicate exported declaration \`${kind} ${name}\``, start, end);
}
declarationExports[name] = {
...getPosition(importsExports, start, end),
kind: kind,
};
}
return end;
};