Как я могу переписать / перепаковать код, написанный для AMD, в CommonJs, не связывая его? - PullRequest
1 голос
/ 09 марта 2019

У меня есть проект, написанный для браузера с использованием модулей AMD, теперь мне нужно запустить тот же код в nodejs, поэтому мне нужно переписать каждый файл с использованием модулей CommonJs.Я попробовал webpack, но он дает мне пакет, который мне не нужен.Все, что я хочу - это сохранить мои файлы такими, как они есть, но переписать define(.. импорт в require(..)

1 Ответ

1 голос
/ 09 марта 2019

благодаря совету Феликса Клинга я написал следующий преобразователь в машинописном тексте

import { FileInfo, API, Options } from 'jscodeshift';
import { resolve, normalize, relative } from 'path';

export default function transformer(file: FileInfo, api: API, options: Options) {
    const { j } = api;
    return j(file.source)
        .find(j.ExpressionStatement, { expression: { callee: { name: 'define' } } })
        .replaceWith(({ node }) => {
            const { expression: defineCallExpression } = node;

            if (defineCallExpression.type !== 'CallExpression') return crash('No call to define function of AMD.');
            const [moduleLocationsArray, callback] = defineCallExpression.arguments;
            if (callback.type !== 'FunctionExpression') return;
            if (moduleLocationsArray.type !== 'ArrayExpression') return;

            const imports = moduleLocationsArray.elements.map((element, index) => {
                if (element === null) return crash('Module name skipped.');
                if (element.type !== 'Literal') return crash('Module name is not a literal');
                const param = callback.params[index];
                if (param.type !== 'Identifier') return crash('Module parameter is not an identifier.');
                return {
                    location: element.value as string,
                    name: param.name,
                };
            }).filter(pair => shouldKeepModule(pair.location));

            const filePath = normalize(resolve(__dirname, file.path));
            const baseDir = normalize(resolve(__dirname, options.where));
            const importStatements = imports.map(({name, location}) => {
                const modulePath = normalize(resolve(baseDir, location));
                const relativeModuleName = slashings(relative(filePath, modulePath));
                const text = `const ${name} = require('${relativeModuleName}');`;
                const statement = api.j(text, options);
                return statement;
            });
            const statementsBefore = callback.body.body;
            const statementsAfter = [...importStatements, ...statementsBefore];
            return statementsAfter;
        })
        .toSource();
}

function shouldKeepModule(location: string): boolean {
    return location !== 'module' && location !== 'exports' && location !== 'require';
}
function crash(message: string): never { throw new Error(message); }
function slashings(text: string): string { return text.replace(/\\/g, '/'); }

со следующим tsconfig.json

{
    "compileOnSave": true,
    "compilerOptions": {
        "strict": true,
        "target": "es6",
        "module": "commonjs",
        "lib": ["es6"],
        "types": ["node", "jscodeshift"],
        "outDir": "../../node_modules/amd-to-commonjs"
    }
}

со следующим package.json

{
    "private": true,
    "devDependencies": {
        "@types/node": "7.0.4",
        "@types/jscodeshift": "0.6.0",
        "jscodeshift": "0.6.3",
        "typescript": "3.4.0-dev.20190227"
    }
}

построен с помощью следующей команды

npm install
node ../../node_modules/typescript/bin/tsc --project ./

и запущен с помощью следующей команды

node ../../node_modules/jscodeshift/bin/jscodeshift.js --transform=../../node_modules/amd-to-commonjs/transformer.js --where=../../scripts/built ../../scripts/built
...