Typescript: لا يحافظ الانبعاث على الخطوط الفارغة

تم إنشاؤها على ٧ أكتوبر ٢٠١٤  ·  36تعليقات  ·  مصدر: microsoft/TypeScript

مرحبا،

إصدار TS : 1.1.2

معطى

function foo() {

    var x = 10;

    var y = 11;
}

اعتدنا على الحصول على

function foo() {
    var x = 10;

    var y = 11;
}

فاصل الأسطر مفقود في المترجم الجديد

function foo() {
    var x = 10;
    var y = 11;
}

(قام كلا المترجمين بإزالة السطر الأول الفارغ ، لكن المترجم الجديد قطع خطوة إلى الأمام.)

يمكن أن يؤثر ذلك على التجربة عند تصحيح أخطاء JavaScript في المستعرض.

Bug help wanted

التعليق الأكثر فائدة

الجماهير تريد preserveWhitespace: true/false
ORESoftware ++

ال 36 كومينتر

إضافة بعض معلومات الخلفية ... السبب في قيام المترجم الجديد بإزالة جميع الأسطر الفارغة هو أن هذا هو الشيء الوحيد الذي يمكننا القيام به _ باستمرار _. سيكون الحفاظ على الأسطر الفارغة دائمًا أمرًا ناجحًا أو مفقودًا عندما يتعلق الأمر بالتركيبات التي تخضع لإعادة الكتابة ، مثل إعلانات الفصل والوحدة. نواجه نفس المشكلات بالضبط مع الاحتفاظ بالتعليقات. لذا ، بينما أنا متعاطف مع حل هذا ، فإنه ليس بالأمر السهل القيام به.

NoelAbrahams لدي فضول ما هي المشكلات التي تراها عند تصحيح الأخطاء؟

ahejlsbergNoelAbrahams أنا خلق نموذج المنبعثة في المشروع الأصلي الذي كود بلاكس فعلا قام بعمل رائع مع تعليق والحفاظ على السطر. حتى في التركيبات التي تمت إعادة كتابتها بشكل كبير (مثل دوال الأسهم لتعبيرات الوظائف) ، فإنها ستفعل دائمًا ما كنت تتوقعه بشكل حدسي.

غالبًا ما يكون الحفاظ على الأسطر هو مجرد إعادة استخدام فواصل الأسطر عند الحفاظ على الشفرة القديمة ، واستخدام التباعد النسبي عند إجراء عمليات التحويل. على سبيل المثال ، إذا كان لديك:

module M {
}
module N {
}

ثم عندما تقوم بإصدار IIFE لـ "N" ، فأنت تقول "يجب أن نحافظ على التوافه بين الوحدة التي نعيد كتابتها والعنصر النحوي السابق".

إليك ما قبل / بعد كيفية عمل النموذج الأولي للباعث الذي احتفظ بالتعليقات / الأسطر الجديدة بمستويات عالية من الدقة:

https://typescript.codeplex.com/SourceControl/latest#tests/Fidelity/emitter2/ecmascript5/Parser.ts
https://typescript.codeplex.com/SourceControl/latest#tests/Fidelity/emitter2/ecmascript5/Parser.ts. المتوقعة

يمكنك مشاهدة الكثير من الأمثلة هنا أيضًا:
https://typescript.codeplex.com/SourceControl/latest#tests/Fidelity/emitter/ecmascript5/

الميزة الوحيدة التي لم أقم بتطبيقها هي "المحاذاة". على سبيل المثال ، إذا كان لديك رمز تمت محاذاته بطريقة ما في الأصل (شائع جدًا مع إعلانات المعلمات) ، فنحن نريد أن تحافظ الشفرة المنبعثة على ذلك أيضًا.

لكن كان من السهل جدًا القيام بذلك.

ومع ذلك ، فإن تحويل العقد من TS إلى JS حاول الحفاظ على المسافة البادئة. يمكنك أن ترى ذلك هنا:
https://typescript.codeplex.com/SourceControl/latest#tests/Fidelity/emitter/ecmascript5/ClassDeclaration/ClassDeclaration2.ts
https://typescript.codeplex.com/SourceControl/latest#tests/Fidelity/emitter/ecmascript5/ClassDeclaration/ClassDeclaration2.ts.ma

لاحظ كيف يتم وضع مسافة بادئة للعبارات بشكل صحيح (حتى عندما تنتشر على عدة أسطر) حتى بعد تحويل الوحدات النمطية المتداخلة والفئة إلى IIFEs

ahejlsberg ، لا توجد مشكلات مهمة عند تصحيح الأخطاء في المتصفح. إنه يجعل من الأسهل التنقل في شفرة JavaScript وتحديد موقع الخطوط لتعيين نقاط التوقف عندما يكون هناك تطابق دقيق مع شفرة مصدر TypeScript الفعلية.

يمكنني أن أعيش شخصيًا بدون الأسطر الفارغة ، ولكن نظرًا لأن TS قد بذلت مثل هذه الأطوال للحفاظ على JavaScript وإصدارها (: smile :) ، يبدو من الطبيعي أن يتم تنفيذ ذلك.

ahejlsbergNoelAbrahams هناك قضية واحدة موجودة مع التصحيح في المستعرض الذي يرتبط بشكل طفيف إلى هذه المحادثة. عند استخدام سلاسل setter / getter (مثل jquery) أو تسلسل الوعود ، تُفقد خلاصات السطر الجديد أثناء الترجمة. ومع ذلك ، فهي نقطة ألم كبيرة عند العمل مع وظائف Arrow.

كمثال:

(<any> x).a('#test')
    .b('test')
    .c(() => 'foo')
    .d(() => 'bar')
    .e(() => 5)
    .f(() => 6);

يصبح:

x.a('#test').b('test').c(function () { return 'foo'; }).d(function () { return 'bar'; }).e(function () { return 5; }).f(function () { return 6; });

باستخدام Chrome و sourceMap ، لا يزال يتم تخطي نقاط التوقف.

http://www.typescriptlang.org/Playground#src = (٪ 3Cany٪ 3E٪ 20x) .a ('٪ 23test')٪ 0A٪ 20٪ 20٪ 20٪ 20.b ('test')٪ 0A٪ 09.c (()٪ 20٪ 3D٪ 3E٪ 20'foo ')٪ 0A٪ 09.d (()٪ 20٪ 3D٪ 3E٪ 20'bar')٪ 0A٪ 09.e ()٪ 20 ٪ 3D٪ 3E٪ 205)٪ 0A٪ 09.f (()٪ 20٪ 3D٪ 3E٪ 206)٪ 3B

mtraynham ، في الواقع أعتقد أن المشكلة التي تبرزها مختلفة قليلاً.

في الإصدارات السابقة ، كان دائمًا ما ينبعث جسم الوظيفة المضمنة في أسطر جديدة:

// TS
var x = () => 'foo';

// JS - old
var x = function () { 
             return 'foo'; 
       };

// JS - new
var x = function () { return 'foo'; };

لقد وجدت أيضًا أن هذه مشكلة - اضطررت أحيانًا للعودة وإنشاء function حتى أتمكن من تعيين نقطة توقف عند تصحيح الأخطاء في المتصفح.

NoelAbrahams آه ، نعم ، لقد كنت أستخدم نفس حل درجة الحرارة بالضبط ... لم أكن متأكدًا مما إذا كان هذا خطأ مناسبًا للمساهمة في هذه المشكلة (محو خطوط التغذية) ، أم يجب أن أفتح أخرى؟

لقد أنشأت # 2259 للإصدار المنفصل.

بصفتك مديرًا هندسيًا يستكشف نقل مجتمع تطوير جافا سكريبت لدينا إلى الطباعة المطبوعة ، فإن قدرة الخط الجديد ستساعد حقًا. كان أحد أهم عوامل الجذب للطباعة المطبوعة هو الحفاظ على قابلية القراءة وبنية الشفرة التي تم إنشاؤها في جافا سكريبت التي تم إنشاؤها.

من الرائع أن ترى التعليقات محفوظة في التحديث الأخير وإضافة توجيه سطر الأوامر "--removeComments".

أود أيضًا أن أحصل على هذا لسبب مشابه لـ timjmartel - عندما يرى المطورون أن JS المنبعث يبدو لطيفًا ، فهم أقل مقاومة للتبني. يؤدي الاحتفاظ بالمسافة البيضاء (الرأسية على الأقل) إلى جعل الكود يبدو وكأنه تم إنشاؤه بواسطة جهاز ويشبه إلى حد كبير رمز JS المكتوب بواسطة إنسان.

إذا قرر فريقنا في أي وقت التخلي عن TS واستمر في استخدام JS المنقول بدلاً من ذلك ، فسيكون من الأسهل بكثير اعتماد مصادر JS المنبعثة إذا كان لديهم مسافة بيضاء صديقة للإنسان.

فيما يتعلق بالخطوط الفارغة ، هل من الممكن - في الوقت الحالي - إطلاقها ، حتى لو تعرضت للضرب أو الخطأ؟ يمكن طلب مثل هذه الميزة التجريبية باستخدام خيار "- keepEmptyLines". لن يكون ذلك كثيرًا لامتلاك JS لطيف ، ولكن لوجود JS أكثر قابلية للقراءة.

فيما يتعلق باستدعاءات الوظائف المتسلسلة ، هل من الممكن وجود مكالمة واحدة للخط ، للسماح للمستخدمين بتعيين نقاط التوقف؟ مرة أخرى ، يمكن أن تُطلب هذه الميزة مع خيار "--oneCallForLine" ، إذا كان هناك شيء آخر "ضربة أو خطأ".

شكرا على انتباهك.

في الواقع ، يمكن تقسيم استدعاءات الوظائف المتسلسلة بواسطة مُجمل التعليمات البرمجية المصدر ، لذلك ليس من المنطقي تضمين هذه الميزة في TypeScript.

لا ينبغي أن يكون هذا بهذه الصعوبة ، فلا ينبغي أن يكون هناك خيار في tsconfig.json فقط

preserveWhitespace: true/false

؟

لكني لا أرى هذا كخيار مترجم: https://www.typescriptlang.org/docs/handbook/compiler-options.html

لقد أدركت للتو. أحد الأسباب الجيدة لعدم الاحتفاظ بالمسافات البيضاء هو أنها ستساعد حقًا في منعك من تحرير ملفات .js عن طريق الخطأ بدلاً من .ts. أعتقد أن شيئًا واحدًا يجب فعله هو كتابة ملفات .js على أنها للقراءة فقط / تنفيذ فقط. لذلك ربما هذه ليست قضية.

ومع ذلك ، لا أعتقد أن tsc يكتب ملفات .js للقراءة فقط / للتنفيذ فقط ، فهل هناك طريقة لتهيئة tsc للقيام بذلك؟

لا ليس في الوقت الحاضر. لا تتردد في فتح قضية منفصلة لذلك بالرغم من ذلك.

DanielRosenwasser أنت تقول إذا أردنا الحفاظ على المسافة البيضاء يجب علينا فتح قضية منفصلة؟ ألا يكفي هذا الموضوع؟ بعد أكثر من شهر ، أدركت أنك كنت تقول لفتح إصدار منفصل لأذونات القراءة / الكتابة / التنفيذ على الملفات المنقولة :)

سيكون من الجيد الحصول على هذا.

+1

+1

+1

الجماهير تريد preserveWhitespace: true/false
ORESoftware ++

السبب في أهمية ذلك هو أن TypeScript من المفترض أن "تتحلل بأمان" إلى JS. في الوقت الحالي ، لا يمكن الحفاظ على الأسطر الجديدة مما يجعل JS كثيفة بعض الشيء للقراءة ، خاصة إذا كنت تكتب TypeScript ، ولكن من المفترض أن ترسل JS إلى مكان آخر.

+1 preserveWhitespace: true/false

اختراق مؤقت

استخدم esformatter لإضافة

بملف التكوين التالي:

{
  "lineBreak": {
    "before": {
      "FunctionDeclaration": ">=2",
      "FunctionDeclarationOpeningBrace": 0,
      "FunctionDeclarationClosingBrace": 1,
      "MethodDefinition": ">=2",
      "ClassDeclaration": ">=2"
    },
    "after": {
      "FunctionDeclaration": ">=2",
      "FunctionDeclarationOpeningBrace": 1,
      "MethodDefinitionClosingBrace": ">=2",
      "ClassClosingBrace": ">=2"
    }
  }
}

mtraynham مثالك :

(<any> x).a('#test')
    .b('test')
    .c(() => 'foo')
    .d(() => 'bar')
    .e(() => 5)
    .f(() => 6);

مع أحدث مترجم ينتج JS:

x.a('#test')
    .b('test')
    .c(function () { return 'foo'; })
    .d(function () { return 'bar'; })
    .e(function () { return 5; })
    .f(function () { return 6; });

(راجع TS PlayGround https://goo.gl/JViurr)

لقد تغير الكثير منذ إصدار TS 1.1 (إصدار TypeScript الذي تم إنشاء هذه المشكلة من أجله). ربما يمكن إغلاق هذه القضية؟ تضمين التغريدة

@ valera-rozuvan فتحت # 2259 بدلاً من ذلك. كانت مشكلتي متعلقة بخلاصات الأسطر ، ولكن لم تكن المشكلة نفسها التي وصفها هذا الخطأ. # 2259 تم إغلاقه منذ فترة (مايو 2015).

هذا هو تكوين esformatter bril -andrew ولكن مع خطأ ثابت ، (عندما احتوى إعلان الفئة على كلمة استيراد ، لم يكن هناك فاصل سطر):

{
    "lineBreak": {
        "before": {
            "FunctionDeclaration": ">=2",
            "FunctionDeclarationOpeningBrace": 0,
            "FunctionDeclarationClosingBrace": 1,
            "MethodDefinition": ">=2",
            "ClassDeclaration": ">=2",
            "ExportNamedDeclaration": 2
        },
        "after": {
            "FunctionDeclaration": ">=2",
            "FunctionDeclarationOpeningBrace": 1,
            "MethodDefinitionClosingBrace": ">=2",
            "ClassClosingBrace": ">=2"
        }
    }
}

لا أعتقد أن استخدام esformatter يحل المشكلة برمتها. بالتأكيد ، يمكنه إدراج أسطر فارغة تلقائيًا حول الوظائف وما إلى ذلك. ولكن بالنسبة لي ، تعد الأسطر الفارغة داخل الوظائف أكثر أهمية. نستخدم أسطرًا فارغة مثل الفقرات في النثر: لتجميع الأفكار الفردية.

تساعد هذه الأسطر الفارغة داخل الوظائف على توصيل بنية الوظيفة. بدونهم ، أجد صعوبة في القراءة.

ahejlsberg أرى أرقام

أم أنه تم دمجه بالفعل ولم يتم إصداره بعد؟ -> V4 الإصدار الكبير التالي # 3143

JimTheMan إذا كنت تستخدم خرائط المصدر ، فربما تساعدك الحزمة source-map-support الحصول على تتبعات المكدس الصحيحة في المخرجات.

أنا أيضا واجهت هذه القضية. توصلت إلى حل بديل عن طريق إنشاء رقعة فرق وعودة تغييرات المسافات البيضاء في التصحيح. يسمح لك jsdiff بإنشاء كائن تصحيح منظم ومعالجته كما يحلو لك.

import * as diff from 'diff';

const patch =
      diff.parsePatch(diff.createPatch('file', oldText, newText, '', ''));
const hunks = patch[0].hunks;
for (let i = 0; i < hunks.length; ++i) {
  let lineOffset = 0;
  const hunk = hunks[i];
  hunk.lines = hunk.lines.map(line => {
    if (line === '-') {
      lineOffset++;
      return ' ';
    }
    return line;
  });
  hunk.newLines += lineOffset;
  for (let j = i + 1; j < hunks.length; ++j) {
    hunks[j].newStart += lineOffset;
  }
}
return diff.applyPatch(oldText, patch);

باستخدام هذا الحل البديل ، يمكنك الاحتفاظ بكافة فواصل الأسطر من الملف الأصلي.

zeroliu هل يقدم تأخيرًا زمنيًا ملحوظًا في خطوة الترجمة؟

ahejlsberg هل تعتقد أن الأمر يستحق إصلاح هذه المشكلة؟

@ valera-rozuvan حسب حجم مشروعك. بالنسبة لحالات الاستخدام الخاصة بي حيث أقوم بنقل ملفات 10-ish من 100-1000 LOC ، فإنه لا يحدث أي تأخير ملحوظ.

أي حلول هنا حتى الآن؟ أنا أركض في هذه المشكلة أيضًا ...

كنت جزءًا من محاولة إصلاح هذا في المترجم نفسه عندما ذكّرني زميلي في الفريق tsc يمكنه الاحتفاظ بالتعليقات. إليك القليل من خط الأنابيب الذي يبدو أنه يقوم بعمل لائق إلى حد ما في الحفاظ على الخطوط الجديدة:

const gulp = require('gulp');
const ts = require('gulp-typescript');
const through = require('through2');

function preserveNewlines() {
  return through.obj(function(file, encoding, callback) {
    const data = file.contents.toString('utf8');
    const fixedUp = data.replace(/\n\n/g, '\n/** THIS_IS_A_NEWLINE **/');
    file.contents = Buffer.from(fixedUp, 'utf8');
    callback(null, file);
  });
}

function restoreNewlines() {
  return through.obj(function(file, encoding, callback) {
    const data = file.contents.toString('utf8');
    const fixedUp = data.replace(/\/\*\* THIS_IS_A_NEWLINE \*\*\//g, '\n');
    file.contents = Buffer.from(fixedUp, 'utf8');
    callback(null, file);
  });
}

gulp.task('default', function () {
  return gulp.src('src/**/*.ts')
    .pipe(preserveNewlines())
    .pipe(ts({
      removeComments: false
    }))
    .pipe(restoreNewlines())
    .pipe(gulp.dest('lib'));
});

أعتقد أن التعليق الأكثر ذكاءً سيمنع بعض الإيجابيات الخاطئة ، ولكن يبدو أنه يعمل جيدًا بالنسبة لنا اليوم. لقد اختبرت هذا فقط على ملف صغير نسبيًا ، لكن حمل الأداء كان ضئيلًا.

ح

تضمين التغريدة

انتهى بي الأمر باستخدام فكرتك كقاعدة ، ثم توسعتها في النهاية حتى أصبحت وحدة npm:
https://www.npmjs.com/package/gulp-preserve-typescript-whitespace

لقد أضفت الفضل إلى رسالتك في الملف التمهيدي ، آمل ألا تمانع :)

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات